blob: d009704cc2c1eee8eefd4ab2710b3614894733cc [file] [log] [blame]
Eric Salama8a9c6c22017-11-10 11:02:23 +01001#ifndef _COMMON_MINI_CLIST_H
2#define _COMMON_MINI_CLIST_H
3
4/* these are circular or bidirectionnal lists only. Each list pointer points to
5 * another list pointer in a structure, and not the structure itself. The
6 * pointer to the next element MUST be the first one so that the list is easily
7 * cast as a single linked list or pointer.
8 */
9struct list {
10 struct list *n; /* next */
11 struct list *p; /* prev */
12};
13
Eric Salama8a9c6c22017-11-10 11:02:23 +010014/* First undefine some macros which happen to also be defined on OpenBSD,
15 * in sys/queue.h, used by sys/event.h
16 */
17#undef LIST_HEAD
18#undef LIST_INIT
19#undef LIST_NEXT
20
21/* ILH = Initialized List Head : used to prevent gcc from moving an empty
22 * list to BSS. Some older version tend to trim all the array and cause
23 * corruption.
24 */
25#define ILH { .n = (struct list *)1, .p = (struct list *)2 }
26
27#define LIST_HEAD(a) ((void *)(&(a)))
28
29#define LIST_INIT(l) ((l)->n = (l)->p = (l))
30
31#define LIST_HEAD_INIT(l) { &l, &l }
32
33/* adds an element at the beginning of a list ; returns the element */
34#define LIST_ADD(lh, el) ({ (el)->n = (lh)->n; (el)->n->p = (lh)->n = (el); (el)->p = (lh); (el); })
35
36/* adds an element at the end of a list ; returns the element */
37#define LIST_ADDQ(lh, el) ({ (el)->p = (lh)->p; (el)->p->n = (lh)->p = (el); (el)->n = (lh); (el); })
38
39/* removes an element from a list and returns it */
40#define LIST_DEL(el) ({ typeof(el) __ret = (el); (el)->n->p = (el)->p; (el)->p->n = (el)->n; (__ret); })
41
42/* returns a pointer of type <pt> to a structure containing a list head called
43 * <el> at address <lh>. Note that <lh> can be the result of a function or macro
44 * since it's used only once.
45 * Example: LIST_ELEM(cur_node->args.next, struct node *, args)
46 */
Willy Tarreau8cdcc932020-03-11 11:54:04 +010047#define LIST_ELEM(lh, pt, el) ((pt)(((const char *)(lh)) - ((size_t)&((pt)NULL)->el)))
Eric Salama8a9c6c22017-11-10 11:02:23 +010048
49/* checks if the list head <lh> is empty or not */
50#define LIST_ISEMPTY(lh) ((lh)->n == (lh))
51
52/* returns a pointer of type <pt> to a structure following the element
53 * which contains list head <lh>, which is known as element <el> in
54 * struct pt.
55 * Example: LIST_NEXT(args, struct node *, list)
56 */
57#define LIST_NEXT(lh, pt, el) (LIST_ELEM((lh)->n, pt, el))
58
59
Joseph Herlantebe14bb2018-11-09 18:36:35 -080060/* returns a pointer of type <pt> to a structure preceding the element
Eric Salama8a9c6c22017-11-10 11:02:23 +010061 * which contains list head <lh>, which is known as element <el> in
62 * struct pt.
63 */
64#undef LIST_PREV
65#define LIST_PREV(lh, pt, el) (LIST_ELEM((lh)->p, pt, el))
66
67/*
68 * Simpler FOREACH_ITEM macro inspired from Linux sources.
69 * Iterates <item> through a list of items of type "typeof(*item)" which are
70 * linked via a "struct list" member named <member>. A pointer to the head of
71 * the list is passed in <list_head>. No temporary variable is needed. Note
72 * that <item> must not be modified during the loop.
73 * Example: list_for_each_entry(cur_acl, known_acl, list) { ... };
74 */
75#define list_for_each_entry(item, list_head, member) \
76 for (item = LIST_ELEM((list_head)->n, typeof(item), member); \
77 &item->member != (list_head); \
78 item = LIST_ELEM(item->member.n, typeof(item), member))
79
80/*
81 * Simpler FOREACH_ITEM_SAFE macro inspired from Linux sources.
82 * Iterates <item> through a list of items of type "typeof(*item)" which are
83 * linked via a "struct list" member named <member>. A pointer to the head of
84 * the list is passed in <list_head>. A temporary variable <back> of same type
85 * as <item> is needed so that <item> may safely be deleted if needed.
86 * Example: list_for_each_entry_safe(cur_acl, tmp, known_acl, list) { ... };
87 */
88#define list_for_each_entry_safe(item, back, list_head, member) \
89 for (item = LIST_ELEM((list_head)->n, typeof(item), member), \
90 back = LIST_ELEM(item->member.n, typeof(item), member); \
91 &item->member != (list_head); \
92 item = back, back = LIST_ELEM(back->member.n, typeof(back), member))
93
94
95#endif /* _COMMON_MINI_CLIST_H */