Linux内嵌链表

Linux内嵌链表

简介

linux 内嵌链表sys/queue.h移植自FreeBSD

queue 分为 SLIST、LIST、STAILQ、TAILQ、CIRCLEQ ,不同的链表有着不同的功能支持。queue 的所有源码都是宏定义,因此完全包含于queue.h当中,无需编译为库文件。

每种结构都支持基本的操作:

  1. 在链表头插入节点
  2. 在任意的节点后插入节点
  3. 移除链表头后的节点
  4. 前向迭代遍历链表
功能支持SLISTLISTSTAILQTAILQCIRCLEQ
EMPTY+++++
FIRST+++++
NEXT+++++
PREV++
LAST++
FOREACH+++++
FOREACH_REVERSE++
INSERT_HEAD+++++
INSERT_BEFORE+++
INSERT_AFTER+++++
INSERT_TAIL+++
CONCAT++
REMOVE_HEAD++
REMOVE+++++
LOOP_NEXT+
LOOP_PREV+

SLIST

SLIST 是Singly-linked List 的缩写,意为单向无尾链表。

SLIST 是最简单的结构,它适合数据量非常大而几乎不需要删除数据的场合,又或者当做堆栈使用。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
/* * Singly-linked List definitions. */
#define SLIST_HEAD(name, type)                                              \
struct name {                                                               \
    struct type *slh_first; /* first element */                             \
}

#define SLIST_HEAD_INITIALIZER(head)                                        \
    { NULL }

#define SLIST_ENTRY(type)                                                   \
struct {                                                                    \
    struct type *sle_next;  /* next element */                              \
}

/* * Singly-linked List functions. */
#define SLIST_INIT(head) do {                                               \
    (head)->slh_first = NULL;                                               \
} while (/*CONSTCOND*/0)

#define SLIST_INSERT_AFTER(slistelm, elm, field) do {                       \
    (elm)->field.sle_next = (slistelm)->field.sle_next;                     \
    (slistelm)->field.sle_next = (elm);                                     \
} while (/*CONSTCOND*/0)

#define SLIST_INSERT_HEAD(head, elm, field) do {                            \
    (elm)->field.sle_next = (head)->slh_first;                              \
    (head)->slh_first = (elm);                                              \
} while (/*CONSTCOND*/0)

#define SLIST_REMOVE_HEAD(head, field) do {                                 \
    (head)->slh_first = (head)->slh_first->field.sle_next;                  \
} while (/*CONSTCOND*/0)

#define SLIST_REMOVE(head, elm, type, field) do {                           \
    if ((head)->slh_first == (elm)) {                                       \
        SLIST_REMOVE_HEAD((head), field);                                   \
    }                                                                       \
    else {                                                                  \
        struct type *curelm = (head)->slh_first;                            \
        while(curelm->field.sle_next != (elm))                              \
            curelm = curelm->field.sle_next;                                \
        curelm->field.sle_next =                                            \
            curelm->field.sle_next->field.sle_next;                         \
    }                                                                       \
} while (/*CONSTCOND*/0)

#define SLIST_FOREACH(var, head, field)                                     \
    for ((var) = SLIST_FIRST((head));                                       \
        (var);                                                              \
        (var) = SLIST_NEXT((var), field) )

#define SLIST_FOREACH_PREVPTR(var, varp, head, field)                       \
    for ((varp) = &SLIST_FIRST((head));                                     \
        ((var) = *(varp)) != NULL;                                          \
        (varp) = &SLIST_NEXT((var), field) )

/* * Singly-linked List access methods. */
#define SLIST_EMPTY(head)       ((head)->slh_first == NULL)
#define SLIST_FIRST(head)       ((head)->slh_first)
#define SLIST_NEXT(elm, field)  ((elm)->field.sle_next)

STAILQ

STAILQ 是 Singly-linked Tail queue 的缩写,意为单向有尾链表。有尾链表可作队列使用。

有尾链表虽然为一些尾部操作提供了便捷的操作,但是可执行文件比无尾链表增加了约15%的大小,且牺牲了约20%的执行速度。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
/* * Singly-linked Tail queue declarations. */
#define STAILQ_HEAD(name, type)                                             \
struct name {                                                               \
    struct type *stqh_first;    /* first element */                         \
    struct type **stqh_last;    /* addr of last next element */             \
}

#define STAILQ_HEAD_INITIALIZER(head)                                       \
    { NULL, &(head).stqh_first }

#define STAILQ_ENTRY(type)                                                  \
struct {                                                                    \
    struct type *stqe_next; /* next element */                              \
}

/* * Singly-linked Tail queue functions. */
#define STAILQ_INIT(head) do {                                              \
    (head)->stqh_first = NULL;                                              \
    (head)->stqh_last = &(head)->stqh_first;                                \
} while (/*CONSTCOND*/0)

#define STAILQ_INSERT_HEAD(head, elm, field) do {                           \
    if (((elm)->field.stqe_next = (head)->stqh_first) == NULL)              \
        (head)->stqh_last = &(elm)->field.stqe_next;                        \
    (head)->stqh_first = (elm);                                             \
} while (/*CONSTCOND*/0)

#define STAILQ_INSERT_TAIL(head, elm, field) do {                           \
    (elm)->field.stqe_next = NULL;                                          \
    *(head)->stqh_last = (elm);                                             \
    (head)->stqh_last = &(elm)->field.stqe_next;                            \
} while (/*CONSTCOND*/0)

#define STAILQ_INSERT_AFTER(head, listelm, elm, field) do {                 \
    if (((elm)->field.stqe_next = (listelm)->field.stqe_next) == NULL)      \
        (head)->stqh_last = &(elm)->field.stqe_next;                        \
    (listelm)->field.stqe_next = (elm);                                     \
} while (/*CONSTCOND*/0)

#define STAILQ_REMOVE_HEAD(head, field) do {                                \
    if (((head)->stqh_first = (head)->stqh_first->field.stqe_next) == NULL) \
        (head)->stqh_last = &(head)->stqh_first;                            \
} while (/*CONSTCOND*/0)

#define STAILQ_REMOVE(head, elm, type, field) do {                          \
    if ((head)->stqh_first == (elm)) {                                      \
        STAILQ_REMOVE_HEAD((head), field);                                  \
    } else {                                                                \
        struct type *curelm = (head)->stqh_first;                           \
        while (curelm->field.stqe_next != (elm))                            \
            curelm = curelm->field.stqe_next;                               \
        if ((curelm->field.stqe_next =                                      \
            curelm->field.stqe_next->field.stqe_next) == NULL)              \
                (head)->stqh_last = &(curelm)->field.stqe_next;             \
    }                                                                       \
} while (/*CONSTCOND*/0)

#define STAILQ_FOREACH(var, head, field)                                    \
    for ((var) = ((head)->stqh_first);                                      \
        (var);                                                              \
        (var) = ((var)->field.stqe_next))

#define STAILQ_CONCAT(head1, head2) do {                                    \
    if (!STAILQ_EMPTY((head2))) {                                           \
        *(head1)->stqh_last = (head2)->stqh_first;                          \
        (head1)->stqh_last = (head2)->stqh_last;                            \
        STAILQ_INIT((head2));                                               \
    }                                                                       \
} while (/*CONSTCOND*/0)

/* * Singly-linked Tail queue access methods. */
#define STAILQ_EMPTY(head)          ((head)->stqh_first == NULL)
#define STAILQ_FIRST(head)          ((head)->stqh_first)
#define STAILQ_NEXT(elm, field)     ((elm)->field.stqe_next)

LIST

LIST是双向无尾链表。

双向链表有前向的指针,因此可以执行一些前向操作,而且无需遍历链表便可以删除一些节点。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
/* * List definitions. */
#define LIST_HEAD(name, type)                                               \
struct name {                                                               \
    struct type *lh_first;  /* first element */                             \
}

#define LIST_HEAD_INITIALIZER(head)                                         \
    { NULL }

#define LIST_ENTRY(type)                                                    \
struct {                                                                    \
    struct type *le_next;   /* next element */                              \
    struct type **le_prev;  /* address of previous next element */          \
}

/* * List functions. */
#define LIST_INIT(head) do {                                                \
    (head)->lh_first = NULL;                                                \
} while (/*CONSTCOND*/0)

#define LIST_INSERT_AFTER(listelm, elm, field) do {                         \
    if (((elm)->field.le_next = (listelm)->field.le_next) != NULL)          \
        (listelm)->field.le_next->field.le_prev =                           \
            &(elm)->field.le_next;                                          \
    (listelm)->field.le_next = (elm);                                       \
    (elm)->field.le_prev = &(listelm)->field.le_next;                       \
} while (/*CONSTCOND*/0)

#define LIST_INSERT_BEFORE(listelm, elm, field) do {                        \
    (elm)->field.le_prev = (listelm)->field.le_prev;                        \
    (elm)->field.le_next = (listelm);                                       \
    *(listelm)->field.le_prev = (elm);                                      \
    (listelm)->field.le_prev = &(elm)->field.le_next;                       \
} while (/*CONSTCOND*/0)

#define LIST_INSERT_HEAD(head, elm, field) do {                             \
    if (((elm)->field.le_next = (head)->lh_first) != NULL)                  \
        (head)->lh_first->field.le_prev = &(elm)->field.le_next;            \
    (head)->lh_first = (elm);                                               \
    (elm)->field.le_prev = &(head)->lh_first;                               \
} while (/*CONSTCOND*/0)

#define LIST_REMOVE(elm, field) do {                                        \
    if ((elm)->field.le_next != NULL)                                       \
        (elm)->field.le_next->field.le_prev =                               \
            (elm)->field.le_prev;                                           \
    *(elm)->field.le_prev = (elm)->field.le_next;                           \
} while (/*CONSTCOND*/0)

#define LIST_FOREACH(var, head, field)                                      \
    for ((var) = ((head)->lh_first);                                        \
        (var);                                                              \
        (var) = ((var)->field.le_next))

/* * List access methods. */
#define LIST_EMPTY(head)        ((head)->lh_first == NULL)
#define LIST_FIRST(head)        ((head)->lh_first)
#define LIST_NEXT(elm, field)   ((elm)->field.le_next)

TAILQ

TAILQ 是 Tail queue 的缩写,意为双向有尾链表。有尾链表可作队列使用。

双向有尾链表兼具了双向链表和有尾链表的特点。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
/* * Tail queue definitions. */
#define TAILQ_HEAD(name, type)                                              \
struct name {                                                               \
    struct type *tqh_first;     /* first element */                         \
    struct type **tqh_last;     /* addr of last next element */             \
}

#define TAILQ_HEAD_INITIALIZER(head)                                        \
    { NULL, &(head).tqh_first }

#define TAILQ_ENTRY(type)                                                   \
struct {                                                                    \
    struct type *tqe_next;      /* next element */                          \
    struct type **tqe_prev;     /* address of previous next element */      \
}

/* * Tail queue functions. */
#define TAILQ_INIT(head) do {                                               \
    (head)->tqh_first = NULL;                                               \
    (head)->tqh_last = &(head)->tqh_first;                                  \
} while (/*CONSTCOND*/0)

#define TAILQ_INSERT_HEAD(head, elm, field) do {                            \
    if (((elm)->field.tqe_next = (head)->tqh_first) != NULL)                \
        (head)->tqh_first->field.tqe_prev = &(elm)->field.tqe_next;         \
    else                                                                    \
        (head)->tqh_last = &(elm)->field.tqe_next;                          \
    (head)->tqh_first = (elm);                                              \
    (elm)->field.tqe_prev = &(head)->tqh_first;                             \
} while (/*CONSTCOND*/0)

#define TAILQ_INSERT_TAIL(head, elm, field) do {                            \
    (elm)->field.tqe_next = NULL;                                           \
    (elm)->field.tqe_prev = (head)->tqh_last;                               \
    *(head)->tqh_last = (elm);                                              \
    (head)->tqh_last = &(elm)->field.tqe_next;                              \
} while (/*CONSTCOND*/0)

#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do {                  \
    if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)        \
        (elm)->field.tqe_next->field.tqe_prev = &(elm)->field.tqe_next;     \
    else                                                                    \
        (head)->tqh_last = &(elm)->field.tqe_next;                          \
    (listelm)->field.tqe_next = (elm);                                      \
    (elm)->field.tqe_prev = &(listelm)->field.tqe_next;                     \
} while (/*CONSTCOND*/0)

#define TAILQ_INSERT_BEFORE(listelm, elm, field) do {                       \
    (elm)->field.tqe_prev = (listelm)->field.tqe_prev;                      \
    (elm)->field.tqe_next = (listelm);                                      \
    *(listelm)->field.tqe_prev = (elm);                                     \
    (listelm)->field.tqe_prev = &(elm)->field.tqe_next;                     \
} while (/*CONSTCOND*/0)

#define TAILQ_REMOVE(head, elm, field) do {                                 \
    if (((elm)->field.tqe_next) != NULL)                                    \
        (elm)->field.tqe_next->field.tqe_prev = (elm)->field.tqe_prev;      \
    else                                                                    \
        (head)->tqh_last = (elm)->field.tqe_prev;                           \
    *(elm)->field.tqe_prev = (elm)->field.tqe_next;                         \
} while (/*CONSTCOND*/0)

#define TAILQ_FOREACH(var, head, field)                                     \
    for ((var) = ((head)->tqh_first);                                       \
        (var);                                                              \
        (var) = ((var)->field.tqe_next))

#define TAILQ_FOREACH_REVERSE(var, head, headname, field)                   \
    for ((var) = (*(((struct headname *)((head)->tqh_last))->tqh_last));    \
        (var);                                                              \
        (var) = (*(((struct headname *)((var)->field.tqe_prev))->tqh_last)))

#define TAILQ_CONCAT(head1, head2, field) do {                              \
    if (!TAILQ_EMPTY(head2)) {                                              \
        *(head1)->tqh_last = (head2)->tqh_first;                            \
        (head2)->tqh_first->field.tqe_prev = (head1)->tqh_last;             \
        (head1)->tqh_last = (head2)->tqh_last;                              \
        TAILQ_INIT((head2));                                                \
    }                                                                       \
} while (/*CONSTCOND*/0)

/* * Tail queue access methods. */
#define TAILQ_EMPTY(head)       ((head)->tqh_first == NULL)
#define TAILQ_FIRST(head)       ((head)->tqh_first)
#define TAILQ_NEXT(elm, field)  ((elm)->field.tqe_next)

#define TAILQ_LAST(head, headname)                                          \
    (*(((struct headname *)((head)->tqh_last))->tqh_last))

#define TAILQ_PREV(elm, headname, field)                                    \
    (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last))

CIRCLEQ

CIRCLEQ 是 Circular queue 的缩写,意为循环链表。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
/* * Circular queue definitions. */
#define CIRCLEQ_HEAD(name, type)                                            \
struct name {                                                               \
    struct type *cqh_first;     /* first element */                         \
    struct type *cqh_last;      /* last element */                          \
}

#define CIRCLEQ_HEAD_INITIALIZER(head)                                      \
    { (void *)&head, (void *)&head }

#define CIRCLEQ_ENTRY(type)                                                 \
struct {                                                                    \
    struct type *cqe_next;      /* next element */                          \
    struct type *cqe_prev;      /* previous element */                      \
}

/* * Circular queue functions. */
#define CIRCLEQ_INIT(head) do {                                             \
    (head)->cqh_first = (void *)(head);                                     \
    (head)->cqh_last = (void *)(head);                                      \
} while (/*CONSTCOND*/0)

#define CIRCLEQ_INSERT_AFTER(head, listelm, elm, field) do {                \
    (elm)->field.cqe_next = (listelm)->field.cqe_next;                      \
    (elm)->field.cqe_prev = (listelm);                                      \
    if ((listelm)->field.cqe_next == (void *)(head))                        \
        (head)->cqh_last = (elm);                                           \
    else                                                                    \
        (listelm)->field.cqe_next->field.cqe_prev = (elm);                  \
    (listelm)->field.cqe_next = (elm);                                      \
} while (/*CONSTCOND*/0)

#define CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) do {               \
    (elm)->field.cqe_next = (listelm);                                      \
    (elm)->field.cqe_prev = (listelm)->field.cqe_prev;                      \
    if ((listelm)->field.cqe_prev == (void *)(head))                        \
        (head)->cqh_first = (elm);                                          \
    else                                                                    \
        (listelm)->field.cqe_prev->field.cqe_next = (elm);                  \
    (listelm)->field.cqe_prev = (elm);                                      \
} while (/*CONSTCOND*/0)

#define CIRCLEQ_INSERT_HEAD(head, elm, field) do {                          \
    (elm)->field.cqe_next = (head)->cqh_first;                              \
    (elm)->field.cqe_prev = (void *)(head);                                 \
    if ((head)->cqh_last == (void *)(head))                                 \
        (head)->cqh_last = (elm);                                           \
    else                                                                    \
        (head)->cqh_first->field.cqe_prev = (elm);                          \
    (head)->cqh_first = (elm);                                              \
} while (/*CONSTCOND*/0)

#define CIRCLEQ_INSERT_TAIL(head, elm, field) do {                          \
    (elm)->field.cqe_next = (void *)(head);                                 \
    (elm)->field.cqe_prev = (head)->cqh_last;                               \
    if ((head)->cqh_first == (void *)(head))                                \
        (head)->cqh_first = (elm);                                          \
    else                                                                    \
        (head)->cqh_last->field.cqe_next = (elm);                           \
    (head)->cqh_last = (elm);                                               \
} while (/*CONSTCOND*/0)

#define CIRCLEQ_REMOVE(head, elm, field) do {                               \
    if ((elm)->field.cqe_next == (void *)(head))                            \
        (head)->cqh_last = (elm)->field.cqe_prev;                           \
    else                                                                    \
        (elm)->field.cqe_next->field.cqe_prev = (elm)->field.cqe_prev;      \
    if ((elm)->field.cqe_prev == (void *)(head))                            \
        (head)->cqh_first = (elm)->field.cqe_next;                          \
    else                                                                    \
        (elm)->field.cqe_prev->field.cqe_next = (elm)->field.cqe_next;      \
} while (/*CONSTCOND*/0)

#define CIRCLEQ_FOREACH(var, head, field)                                   \
    for ((var) = ((head)->cqh_first);                                       \
        (var) != (const void *)(head);                                      \
        (var) = ((var)->field.cqe_next))

#define CIRCLEQ_FOREACH_REVERSE(var, head, field)                           \
    for ((var) = ((head)->cqh_last);                                        \
        (var) != (const void *)(head);                                      \
        (var) = ((var)->field.cqe_prev))

/* * Circular queue access methods. */
#define CIRCLEQ_EMPTY(head)         ((head)->cqh_first == (void *)(head))
#define CIRCLEQ_FIRST(head)         ((head)->cqh_first)
#define CIRCLEQ_LAST(head)          ((head)->cqh_last)
#define CIRCLEQ_NEXT(elm, field)    ((elm)->field.cqe_next)
#define CIRCLEQ_PREV(elm, field)    ((elm)->field.cqe_prev)

#define CIRCLEQ_LOOP_NEXT(head, elm, field)                                 \
    (((elm)->field.cqe_next == (void *)(head))                              \
        ? ((head)->cqh_first)                                               \
        : (elm->field.cqe_next))

#define CIRCLEQ_LOOP_PREV(head, elm, field)                                 \
    (((elm)->field.cqe_prev == (void *)(head))                              \
        ? ((head)->cqh_last)                                                \
        : (elm->field.cqe_prev))

参考

  1. Linux内嵌链表(sys/queue.h)详解_tissar的博客-CSDN博客

updatedupdated2024-05-152024-05-15