在接触tbox这个开源库的时候,见识到了一个非常神奇的宏用来实现C语言的for-each循环,不禁让我很佩服作者的设计思路,想拿出来分享一下。
// 输入一共五个参数,type为元素类型,item为遍历取出的元素,head为容器的索引头,tail为容器的索引尾,iterator为自定义的迭代器
#define tb_for(type, item, head, tail, iterator) \
/* iterator */ \
// 先是用断言检查迭代器异常
tb_iterator_ref_t item##_iterator = (tb_iterator_ref_t)iterator; \
tb_assert(!item##_iterator || (tb_iterator_mode(item##_iterator) & (TB_ITERATOR_MODE_FORWARD | TB_ITERATOR_MODE_RACCESS))); \
/* init */ \
// 这里进行初始化操作
type item; \
tb_size_t item##_itor = head; \
tb_size_t item##_head = head; \
tb_size_t item##_tail = tail; \
/* walk */ \
// 开始遍历前先确认容器是否可以遍历,可以的话进入for循环
if (item##_iterator && item##_head != item##_tail) \
for ( ; \
// 如果没到最后一个元素则返回真继续遍历并且赋值给item贡开发者使用
// 为了防止这个元素值为0后面又加了个1保证&&后面的条件一定为真
item##_itor != item##_tail && ((item = (type)tb_iterator_item(item##_iterator, item##_itor)), 1); \
// 迭代器指向下一个元素
item##_itor = tb_iterator_next(item##_iterator, item##_itor))
上面的宏需要指定头部索引与尾部索引,那么可以简化一下写成如下形式只需提供迭代器即可遍历:
#define tb_for_all(type, item, iterator) \
tb_iterator_ref_t item##_iterator_all = (tb_iterator_ref_t)iterator; \
tb_for(type, item, tb_iterator_head(item##_iterator_all), tb_iterator_tail(item##_iterator_all), item##_iterator_all)
具体使用的时候,以tbox的hashmap为例:
tb_for_all(tb_hash_map_item_ref_t, item, iterator)
{
if (item) tb_trace_d("item: %p => %p", item->name, item->data);
}
大括号中拿到的item就是hashmap中的键值对,使用起来就像内置的关键字一样方便。
进一步扩展还可以增加一个条件判断:
#define tb_for_if(type, item, head, tail, iterator, cond) \
/* iterator */ \
tb_iterator_ref_t item##_iterator = (tb_iterator_ref_t)iterator; \
tb_assert(!item##_iterator || (tb_iterator_mode(item##_iterator) & (TB_ITERATOR_MODE_FORWARD | TB_ITERATOR_MODE_RACCESS))); \
/* init */ \
type item; \
tb_size_t item##_itor = head; \
tb_size_t item##_head = head; \
tb_size_t item##_tail = tail; \
/* walk */ \
if (item##_iterator && item##_head != item##_tail) \
for ( ; \
item##_itor != item##_tail && ((item = (type)tb_iterator_item(item##_iterator, item##_itor)), 1); \
item##_itor = tb_iterator_next(item##_iterator, item##_itor)) if ((cond))
tbox的github链接如下:
https://github.com/tboox/tbox