在阅读libdispatch源码时,会出现LIST_HEAD,LIST_ENTRY等链表定义,在libdispatch项目里无法直接跳转到它们的定义处,因此对它们的实现会比较模糊,经查找发现它们定在
LIST_HEAD,LIST_ENTRY通常用来定义双向链表。
一些宏定义
#if defined(__clang__) && defined(__cplusplus)
#define __MISMATCH_TAGS_PUSH \
_Pragma("clang diagnostic push") \
_Pragma("clang diagnostic ignored \"-Wmismatched-tags\"")
#define __MISMATCH_TAGS_POP \
_Pragma("clang diagnostic pop")
#else
#define __MISMATCH_TAGS_PUSH
#define __MISMATCH_TAGS_POP
#endif
#if defined(__clang__)
#define __NULLABILITY_COMPLETENESS_PUSH \
_Pragma("clang diagnostic push") \
_Pragma("clang diagnostic ignored \"-Wnullability-completeness\"")
#define __NULLABILITY_COMPLETENESS_POP \
_Pragma("clang diagnostic pop")
#else
#define __NULLABILITY_COMPLETENESS_PUSH
#define __NULLABILITY_COMPLETENESS_POP
#endif
__MISMATCH_TAGS_PUSH:编译器忽略未匹配的标识符警告
__NULLABILITY_COMPLETENESS_PUSH: 编译器忽略未指定变量可空或不可空警告
LIST_HEAD
LIST_HEAD(name, type)用来定义链表头
结构体
- name:结构体的名称(可省略)
- type:链表节点类型
#define LIST_HEAD(name, type) \
__MISMATCH_TAGS_PUSH \
__NULLABILITY_COMPLETENESS_PUSH \
struct name { \
struct type *lh_first; /* first element */ \
} \
__NULLABILITY_COMPLETENESS_POP \
__MISMATCH_TAGS_POP
LIST_HEAD_INITIALIZER
LIST_HEAD_INITIALIZER(head) 链表表头初始化,简单的初始化为NULL
#define LIST_HEAD_INITIALIZER(head) \
{ NULL }
LIST_ENTRY
用来定义链表节点,le_next指向下一个节点,le_prev指向前一个节点的le_next地址。这样的好处就是我们不必通过上一个节点拿到le_next了,就可以直接操作le_next。
#define LIST_ENTRY(type) \
__MISMATCH_TAGS_PUSH \
__NULLABILITY_COMPLETENESS_PUSH \
struct { \
struct type *le_next; /* next element */ \
struct type **le_prev; /* address of previous next element */ \
} \
__NULLABILITY_COMPLETENESS_POP \
__MISMATCH_TAGS_POP
LIST_NEXT
先看一下LIST_NEXT的定义,返回节点elm的le_next指针。
#define LIST_NEXT(elm, field) ((elm)->field.le_next)
LIST_CHECK_HEAD、LIST_CHECK_NEXT、LIST_CHECK_PREV
LIST_CHECK_HEAD、LIST_CHECK_NEXT、LIST_CHECK_PREV:字面是意思检查头指针、下一个指针,前一个指针是否有效,头文件里面没有明确定义,可以在使用时候自行定义。
#define LIST_CHECK_HEAD(head, field)
#define LIST_CHECK_NEXT(elm, field)
#define LIST_CHECK_PREV(elm, field)
LIST_EMPTY、LIST_FIRST
LIST_EMPTY:链表头的lh_first指针置空。
LIST_FIRST:链表第一个元素的指针。
#define LIST_EMPTY(head) ((head)->lh_first == NULL)
#define LIST_FIRST(head) ((head)->lh_first)
LIST_FOREACH
遍历链表的for循环语句头的简写,需要加上花括号。(var为链表第一个节点指针,var不为空, 本次循环结束后var为下一个节点指针)
var:for语句里面的自动变量。
head:链表头。
field:var里面表示链表前后索引的成员名。
#define LIST_FOREACH(var, head, field) \
for ((var) = LIST_FIRST((head)); \
(var); \
(var) = LIST_NEXT((var), field))
下面是libdispatch里面的源码示例:
LIST_FOREACH(dmn, dmb, dmn_list) {
if (dmn->dmn_ident == ident && dmn->dmn_filter == filter) {
break;
}
}
LIST_FOREACH_SAFE
LIST_FOREACH_SAFE相比LIST_FOREACH,先把下个节点指针取出来,等这次循环后直接把下个节点指针赋值给var,这样就可以避免在循环体里面修改了当前var下个节点指针的指向,造成循环结束或者错乱。
#define LIST_FOREACH_SAFE(var, head, field, tvar) \
for ((var) = LIST_FIRST((head)); \
(var) && ((tvar) = LIST_NEXT((var), field), 1); \
(var) = (tvar))
LIST_INIT
初始化链表,将链表头下一个指针指向空。
#define LIST_INIT(head) do { \
LIST_FIRST((head)) = NULL; \
} while (0)
LIST_INSERT_AFTER
LIST_INSERT_AFTER:在链表节点listelm的后面插入节点elm。
- 首先
(elm)->field.le_next
赋值为(listelm)->field.le_next
,如果listelm的原下一个节点不为空,原下一个节点(listelm)->field.le_next->field.le_prev
等于((elm)->field.le_next)
地址值。 -
(listelm)->field.le_next
新指向elm
。 -
(elm)->field.le_prev
赋值为(listelm)->field.le_next
的地址。
#define LIST_INSERT_AFTER(listelm, elm, field) do { \
LIST_CHECK_NEXT(listelm, field); \
if ((LIST_NEXT((elm), field) = LIST_NEXT((listelm), field)) != NULL)\ //
LIST_NEXT((listelm), field)->field.le_prev = \
&LIST_NEXT((elm), field); \ //
LIST_NEXT((listelm), field) = (elm); \
(elm)->field.le_prev = &LIST_NEXT((listelm), field); \
} while (0)
LIST_INSERT_BEFORE
LIST_INSERT_BEFORE:在链表节点listelm的前面插入节点elm。
- 首先
(elm)->field.le_prev
赋值为(listelm)->field.le_prev
。 - 然后
(elm)->field.le_next
新指向listelm
。 -
*(listelm)->field.le_prev***
指向elm
。le_prev是原上一个节点le_next的指针,那么```*(listelm)->field.le_prev ***就是上一个节点的le_next指向。 -
(listelm)->field.le_prev
赋值为elm
的le_next地址。
#define LIST_INSERT_BEFORE(listelm, elm, field) do { \
LIST_CHECK_PREV(listelm, field); \
(elm)->field.le_prev = (listelm)->field.le_prev; \
LIST_NEXT((elm), field) = (listelm); \
*(listelm)->field.le_prev = (elm); \
(listelm)->field.le_prev = &LIST_NEXT((elm), field); \
} while (0)
LIST_INSERT_HEAD
LIST_INSERT_HEAD:在链表头部插入节点elm。
- 首先
(elm)->field.le_next
赋值为(head)->lh_first
,如果链表不为空,head的原下一个节点(head)->lh_first->field.le_prev
等于((elm)->field.le_next)
地址值。 -
(head)->lh_first
指向elm
。 -
(elm)->field.le_prev
赋值为(head)->lh_first
的地址。
#define LIST_INSERT_HEAD(head, elm, field) do { \
LIST_CHECK_HEAD((head), field); \
if ((LIST_NEXT((elm), field) = LIST_FIRST((head))) != NULL) \
LIST_FIRST((head))->field.le_prev = &LIST_NEXT((elm), field);\
LIST_FIRST((head)) = (elm); \
(elm)->field.le_prev = &LIST_FIRST((head)); \
} while (0)
LIST_REMOVE
LIST_REMOVE:在链表中移除elm。
- 如果
(elm)->field.le_next
不为NULL,那么(elm)->field.le_next->field.le_prev = (elm)->field.le_prev;
下个节点的le_prev等于当前节点的le_prev。 - 当前节点上一个节点的next指向当前节点的下个节点。
-
(head)->lh_first
指向elm
。 -
(elm)->field.le_prev
赋值为(head)->lh_first
的地址。 - 把当前节点的le_next、le_prev值置为-1,
#define TRASHIT(x) do {(x) = (void *)-1;} while (0)
#define LIST_REMOVE(elm, field) do { \
LIST_CHECK_NEXT(elm, field); \
LIST_CHECK_PREV(elm, field); \
if (LIST_NEXT((elm), field) != NULL) \
LIST_NEXT((elm), field)->field.le_prev = \
(elm)->field.le_prev; \
*(elm)->field.le_prev = LIST_NEXT((elm), field); \
TRASHIT((elm)->field.le_next); \
TRASHIT((elm)->field.le_prev); \
} while (0)
LIST_SWAP
LIST_SWAP:更换两个链表的全部节点。
-
swap_tmp
指向(head1)->lh_first
-
(head1)->lh_first
赋值为(head2)->lh_first
-
(head2)->lh_first
赋值为swap_tmp
- 如果
head1
节点不为NULL
,head1
第一个节点的le_prev
,指向head1
的lh_first
- 如果
head2
节点不为NULL
,head2
第一个节点的le_prev
,指向head2
的lh_first
#define LIST_SWAP(head1, head2, type, field) \
__MISMATCH_TAGS_PUSH \
__NULLABILITY_COMPLETENESS_PUSH \
do { \
struct type *swap_tmp = LIST_FIRST((head1)); \
LIST_FIRST((head1)) = LIST_FIRST((head2)); \
LIST_FIRST((head2)) = swap_tmp; \
if ((swap_tmp = LIST_FIRST((head1))) != NULL) \
swap_tmp->field.le_prev = &LIST_FIRST((head1)); \
if ((swap_tmp = LIST_FIRST((head2))) != NULL) \
swap_tmp->field.le_prev = &LIST_FIRST((head2)); \
} while (0) \
__NULLABILITY_COMPLETENESS_POP \
__MISMATCH_TAGS_POP
--- END ---