GCD源码浅析:LIST_HEAD、LIST_ENTRY、LIST_INIT…

在阅读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的定义,返回节点elmle_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节点不为NULLhead1第一个节点的le_prev,指向head1lh_first
  • 如果head2节点不为NULLhead2第一个节点的le_prev,指向head2lh_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 ---

你可能感兴趣的:(GCD源码浅析:LIST_HEAD、LIST_ENTRY、LIST_INIT…)