stl的容器库常用模式就是将容器、迭代器和算法的进行分离,容器专于存储,迭代器负责枚举,这样互相独立好处多多。

    因此TBOX也借鉴了这种模式,不同的是没用模板,仅仅用了c语言来实现。容器库里面的大部分容器都是继承自迭代器的,所以迭代起来相当的方便。

    下面先看个迭代器使用的例子:

    1. // 初始化一个双向链表,元素类型为tb_long_t, 满256个元素自动增长
    2. tb_list_ref_t list = tb_list_init(256, tb_element_long());
    3. if (list)
    4. {
    5. // 插入一些元素
    6. tb_list_insert_tail(list, (tb_cpointer_t)1);
    7. tb_list_insert_tail(list, (tb_cpointer_t)2);
    8. tb_list_insert_tail(list, (tb_cpointer_t)3);
    9. tb_list_insert_tail(list, (tb_cpointer_t)4);
    10. tb_list_insert_tail(list, (tb_cpointer_t)5);
    11.  
    12. // 迭代遍历所有元素
    13. tb_for_all (tb_long_t, item, list)
    14. {
    15. tb_trace_i("item: %ld", item);
    16. }
    17.  
    18. // 迭代遍历所有 > 3 的元素
    19. tb_for_all_if (tb_long_t, item2, list, item2 > 3)
    20. {
    21. tb_trace_i("item: %ld", item2);
    22. }
    23.  
    24. // 反向迭代遍历所有元素,注:只有支持反向迭代的容器,才行,例如单链tb_single_list_t就不行
    25. tb_rfor_all (tb_long_t, item3, list)
    26. {
    27. tb_trace_i("item: %ld", item3);
    28. }
    29.  
    30. // 反向迭代遍历所有 > 3 的元素
    31. tb_rfor_all_if (tb_long_t, item4, list, item4 > 3)
    32. {
    33. tb_trace_i("item: %ld", item4);
    34. }
    35.  
    36. // 迭代遍历部分元素,这里认为传入迭代的头部和尾部,进行遍历所有
    37. tb_for (tb_long_t, item5, tb_iterator_head(list), tb_iterator_tail(list), list)
    38. {
    39. tb_trace_i("item: %ld", item5);
    40. }
    41.  
    42. // 退出链表
    43. tb_list_exit(list);
    44. }

    怎么样简单吧,其实这里的 tb_for_all 是一个宏,如果把它展开的话,其实也可以这样遍历只不过看上去繁琐些,但是更加灵活:

    1. // 获取list的头部索引
    2. tb_size_t itor = tb_iterator_head(list);
    3.  
    4. // 获取list的尾部索引
    5. tb_size_t tail = tb_iterator_tail(list);
    6.  
    7. // 进行遍历,这里没去删除元素,所以不需要实时更新tail的值
    8. for (; itor != tail; itor = tb_iterator_next(list, itor))
    9. {
    10. // 获取索引itor对应的元素
    11. tb_long_t item = (tb_long_t)tb_iterator_item(list, itor);
    12. }
    13.  
    14. // 进行遍历,并且删除元素,需要更新tail, 所以这个tb_for 就办不到了
    15. // tb_for为了效率,不会去更新tail的值
    16. while (itor != tb_iterator_tail(list, itor))
    17. {
    18. // 获取索引itor对应的元素
    19. tb_long_t item = (tb_long_t)tb_iterator_item(list, itor);
    20. if (item > 3)
    21. {
    22. // 先保存下一个索引,避免删除当前元素后itor变为无效索引
    23. tb_size_t next = tb_iterator_next(list, itor);
    24.  
    25. // 使用迭代器删除
    26. tb_iterator_remove(list, itor);
    27.  
    28. // 或者使用容器删除
    29. // tb_list_remove(list, itor);
    30.  
    31. // 继续下一个
    32. itor = next;
    33. continue ;
    34. }
    35.  
    36. // 继续下一个
    37. itor = tb_iterator_next(list, itor);
    38. }

    这种方式其实也已经相当方便了,如果觉得上面的删除比较繁琐的话,可以使用算法库提供的remove函数来进行遍历删除,并且更加高效。

    1. // 自定义谓词函数,具体说明参看:algorithm/predicate.h
    2. tb_bool_t tb_list_predicate_xxxx(tb_iterator_ref_t iterator, tb_cpointer_t item, tb_cpointer_t value);
    3. {
    4. // 如果 > 3 就删除它
    5. if ((tb_long_t)item > 3)
    6. {
    7. /* 标记这个元素为删除
    8. *
    9. * 注:
    10. * 这个时候容器内部还没有真正的删除它,里面做了些优化
    11. * 来一次性删除一块连续的元素,这样效率会高好多
    12. *
    13. * 这种删除模式,是最快速的,尤其是对tb_vector_t这种有连续内存的容器,更为高效
    14. * 避免了每删除一个元素,都要进行一遍tb_memmov内存的搬运
    15. *
    16. * 名字类似,vector的遍历删除使用:tb_vector_walk
    17. */
    18. return tb_true;
    19. }
    20.  
    21. // 继续下一个
    22. return tb_false;
    23. }
    24.  
    25. // 遍历所有元素,并对每个元素调用回调函数
    26. tb_remove_if(list, tb_list_predicate_xxxx, tb_null);

    还有一种遍历方式,就是使用算法库的tb_walk函数,这个和 tb_list_walk类似,但不提供删除功能。 主要应用在通用化,模块化复杂遍历代码的地方:

    1. tb_bool_t tb_walk_item_func(tb_iterator_ref_t iterator, tb_pointer_t item, tb_pointer_t priv)
    2. {
    3. // ...
    4. }
    5.  
    6. // 遍历所有
    7. tb_walk_all(list, tb_walk_item_func, tb_null);
    8.  
    9. // 反向遍历所有
    10. tb_rwalk_all(list, tb_walk_item_func, tb_null);
    11.  
    12. // 通过迭代器索引,局部遍历
    13. tb_walk(list, tb_iterator_head(list), tb_iterator_tail(list), tb_walk_item_func, tb_null);
    14.  
    15. // 反向通过迭代器索引,局部遍历
    16. tb_rwalk(list, tb_iterator_head(list), tb_iterator_tail(list), tb_walk_item_func, tb_null);

    总结下:

    1. tb_for系列:用于小代码块的简单逻辑遍历
    2. 直接使用迭代器:用于小代码块复杂逻辑遍历
    3. 容器的tb_xxx_walk:用于复杂代码块、高效删除元素时的遍历
    4. tb_walk系列:用于复杂代码块,不需要删除时的遍历

    迭代器主要由如下几种访问模式,不同容器支持的力度不一样:

    1. /// the iterator mode type
    2. typedef enum __tb_iterator_mode_t
    3. {
    4. TB_ITERATOR_MODE_FORWARD = 1 //!< 前向遍历迭代器,大部分容器都支持
    5. , TB_ITERATOR_MODE_REVERSE = 2 //!< 反向向遍历迭代器, 单链不支持
    6. , TB_ITERATOR_MODE_RACCESS = 4 //!< 随机访问迭代器,链表、队列、堆栈等不支持,最常用就是vector
    7. , TB_ITERATOR_MODE_MUTABLE = 8 //!< 易变的迭代器,同一个迭代器索引的值有可能因为删除某个元素而改变,例如:vector
    8. , TB_ITERATOR_MODE_READONLY = 16 //!< 只读访问迭代器,不提供删除、替换等操作
    9.  
    10. }tb_iterator_mode_t;

    常用的一些迭代器接口:

    1. // 获取迭代器访问模式
    2. tb_size_t tb_iterator_mode(tb_iterator_ref_t iterator);
    3.  
    4. // 获取迭代器对应容器的元素总数
    5. tb_size_t tb_iterator_size(tb_iterator_ref_t iterator);
    6.  
    7. // 获取迭代器的头部索引
    8. tb_size_t tb_iterator_head(tb_iterator_ref_t iterator);
    9.  
    10. // 获取迭代器的最后一个元素的索引
    11. tb_size_t tb_iterator_last(tb_iterator_ref_t iterator);
    12.  
    13. // 获取迭代器的尾部索引,不指向实际元素,一般用于判断结束
    14. tb_size_t tb_iterator_tail(tb_iterator_ref_t iterator);
    15.  
    16. // 获取迭代器的先前一个元素的索引
    17. tb_size_t tb_iterator_prev(tb_iterator_ref_t iterator, tb_size_t itor);
    18.  
    19. // 获取迭代器的下一个元素的索引
    20. tb_size_t tb_iterator_next(tb_iterator_ref_t iterator, tb_size_t itor);
    21.  
    22. // 获取迭代器索引指向的元素
    23. tb_pointer_t tb_iterator_item(tb_iterator_ref_t iterator, tb_size_t itor);
    24.  
    25. // 删除迭代器索引指向的元素
    26. tb_void_t tb_iterator_remove(tb_iterator_ref_t iterator, tb_size_t itor);
    27.  
    28. // 复制迭代器索引指向的元素
    29. tb_void_t tb_iterator_copy(tb_iterator_ref_t iterator, tb_size_t itor, tb_cpointer_t item);
    30.  
    31. // 比较迭代器索引指向的两个元素
    32. tb_long_t tb_iterator_comp(tb_iterator_ref_t iterator, tb_cpointer_t ltem, tb_cpointer_t rtem);

    你也可以将常用的原始数组,迭代器化,来支持迭代,并用于所有算法:

    1. // 根据一个tb_long_t[]数组,生成迭代器, count 为数组元素个数
    2. tb_iterator_ref_t tb_iterator_make_for_long(tb_array_iterator_ref_t iterator, tb_long_t* items, tb_size_t count);
    3.  
    4. // 根据一个tb_size_t[]数组,生成迭代器, count 为数组元素个数
    5. tb_iterator_ref_t tb_iterator_make_for_size(tb_array_iterator_ref_t iterator, tb_size_t* items, tb_size_t count);
    6.  
    7. // 根据一个tb_char_t*[]字符串数组,生成迭代器, count 为数组元素个数
    8. tb_iterator_ref_t tb_iterator_make_for_str(tb_array_iterator_ref_t iterator, tb_char_t** items, tb_size_t count);
    9.  
    10. // 根据一个tb_pointer_t[]指针数组,生成迭代器, count 为数组元素个数
    11. tb_iterator_ref_t tb_iterator_make_for_ptr(tb_array_iterator_ref_t iterator, tb_pointer_t* items, tb_size_t count);
    12.  
    13. // 根据一个tb_struct_xxxx_t[]结构体数组,生成迭代器, count 为数组元素个数, size == sizeof(tb_struct_xxxx_t)
    14. tb_iterator_ref_t tb_iterator_make_for_mem(tb_array_iterator_ref_t iterator, tb_pointer_t items, tb_size_t count, tb_size_t size);