1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2 #pragma once
3 
4 #include "macro.h"
5 
6 /* The head of the linked list. Use this in the structure that shall
7  * contain the head of the linked list */
8 #define LIST_HEAD(t,name)                                               \
9         t *name
10 
11 /* The pointers in the linked list's items. Use this in the item structure */
12 #define LIST_FIELDS(t,name)                                             \
13         t *name##_next, *name##_prev
14 
15 /* Initialize the list's head */
16 #define LIST_HEAD_INIT(head)                                            \
17         do {                                                            \
18                 (head) = NULL;                                          \
19         } while (false)
20 
21 /* Initialize a list item */
22 #define LIST_INIT(name,item)                                            \
23         do {                                                            \
24                 typeof(*(item)) *_item = (item);                        \
25                 assert(_item);                                          \
26                 _item->name##_prev = _item->name##_next = NULL;         \
27         } while (false)
28 
29 /* Prepend an item to the list */
30 #define LIST_PREPEND(name,head,item)                                    \
31         do {                                                            \
32                 typeof(*(head)) **_head = &(head), *_item = (item);     \
33                 assert(_item);                                          \
34                 if ((_item->name##_next = *_head))                      \
35                         _item->name##_next->name##_prev = _item;        \
36                 _item->name##_prev = NULL;                              \
37                 *_head = _item;                                         \
38         } while (false)
39 
40 /* Append an item to the list */
41 #define LIST_APPEND(name,head,item)                                     \
42         do {                                                            \
43                 typeof(*(head)) **_hhead = &(head), *_tail;             \
44                 LIST_FIND_TAIL(name, *_hhead, _tail);                   \
45                 LIST_INSERT_AFTER(name, *_hhead, _tail, item);          \
46         } while (false)
47 
48 /* Remove an item from the list */
49 #define LIST_REMOVE(name,head,item)                                     \
50         do {                                                            \
51                 typeof(*(head)) **_head = &(head), *_item = (item);     \
52                 assert(_item);                                          \
53                 if (_item->name##_next)                                 \
54                         _item->name##_next->name##_prev = _item->name##_prev; \
55                 if (_item->name##_prev)                                 \
56                         _item->name##_prev->name##_next = _item->name##_next; \
57                 else {                                                  \
58                         assert(*_head == _item);                        \
59                         *_head = _item->name##_next;                    \
60                 }                                                       \
61                 _item->name##_next = _item->name##_prev = NULL;         \
62         } while (false)
63 
64 /* Find the head of the list */
65 #define LIST_FIND_HEAD(name,item,head)                                  \
66         do {                                                            \
67                 typeof(*(item)) *_item = (item);                        \
68                 if (!_item)                                             \
69                         (head) = NULL;                                  \
70                 else {                                                  \
71                         while (_item->name##_prev)                      \
72                                 _item = _item->name##_prev;             \
73                         (head) = _item;                                 \
74                 }                                                       \
75         } while (false)
76 
77 /* Find the tail of the list */
78 #define LIST_FIND_TAIL(name,item,tail)                                  \
79         do {                                                            \
80                 typeof(*(item)) *_item = (item);                        \
81                 if (!_item)                                             \
82                         (tail) = NULL;                                  \
83                 else {                                                  \
84                         while (_item->name##_next)                      \
85                                 _item = _item->name##_next;             \
86                         (tail) = _item;                                 \
87                 }                                                       \
88         } while (false)
89 
90 /* Insert an item after another one (a = where, b = what) */
91 #define LIST_INSERT_AFTER(name,head,a,b)                                \
92         do {                                                            \
93                 typeof(*(head)) **_head = &(head), *_a = (a), *_b = (b); \
94                 assert(_b);                                             \
95                 if (!_a) {                                              \
96                         if ((_b->name##_next = *_head))                 \
97                                 _b->name##_next->name##_prev = _b;      \
98                         _b->name##_prev = NULL;                         \
99                         *_head = _b;                                    \
100                 } else {                                                \
101                         if ((_b->name##_next = _a->name##_next))        \
102                                 _b->name##_next->name##_prev = _b;      \
103                         _b->name##_prev = _a;                           \
104                         _a->name##_next = _b;                           \
105                 }                                                       \
106         } while (false)
107 
108 /* Insert an item before another one (a = where, b = what) */
109 #define LIST_INSERT_BEFORE(name,head,a,b)                               \
110         do {                                                            \
111                 typeof(*(head)) **_head = &(head), *_a = (a), *_b = (b); \
112                 assert(_b);                                             \
113                 if (!_a) {                                              \
114                         if (!*_head) {                                  \
115                                 _b->name##_next = NULL;                 \
116                                 _b->name##_prev = NULL;                 \
117                                 *_head = _b;                            \
118                         } else {                                        \
119                                 typeof(*(head)) *_tail = (head);        \
120                                 while (_tail->name##_next)              \
121                                         _tail = _tail->name##_next;     \
122                                 _b->name##_next = NULL;                 \
123                                 _b->name##_prev = _tail;                \
124                                 _tail->name##_next = _b;                \
125                         }                                               \
126                 } else {                                                \
127                         if ((_b->name##_prev = _a->name##_prev))        \
128                                 _b->name##_prev->name##_next = _b;      \
129                         else                                            \
130                                 *_head = _b;                            \
131                         _b->name##_next = _a;                           \
132                         _a->name##_prev = _b;                           \
133                 }                                                       \
134         } while (false)
135 
136 #define LIST_JUST_US(name,item)                                         \
137         (!(item)->name##_prev && !(item)->name##_next)
138 
139 /* The type of the iterator 'i' is automatically determined by the type of 'head', and declared in the
140  * loop. Hence, do not declare the same variable in the outer scope. Sometimes, we set 'head' through
141  * hashmap_get(). In that case, you need to explicitly cast the result. */
142 #define LIST_FOREACH_WITH_NEXT(name,i,n,head)                           \
143         for (typeof(*(head)) *n, *i = (head); i && (n = i->name##_next, true); i = n)
144 
145 #define LIST_FOREACH(name,i,head)                                       \
146         LIST_FOREACH_WITH_NEXT(name, i, UNIQ_T(n, UNIQ), head)
147 
148 #define _LIST_FOREACH_WITH_PREV(name,i,p,start)                         \
149         for (typeof(*(start)) *p, *i = (start); i && (p = i->name##_prev, true); i = p)
150 
151 #define LIST_FOREACH_BACKWARDS(name,i,start)                            \
152         _LIST_FOREACH_WITH_PREV(name, i, UNIQ_T(p, UNIQ), start)
153 
154 /* Iterate through all the members of the list p is included in, but skip over p */
155 #define LIST_FOREACH_OTHERS(name,i,p)                                   \
156         for (typeof(*(p)) *_p = (p), *i = ({                            \
157                                 typeof(*_p) *_j = _p;                   \
158                                 while (_j && _j->name##_prev)           \
159                                         _j = _j->name##_prev;           \
160                                 if (_j == _p)                           \
161                                         _j = _p->name##_next;           \
162                                 _j;                                     \
163                         });                                             \
164              i;                                                         \
165              i = i->name##_next == _p ? _p->name##_next : i->name##_next)
166 
167 /* Loop starting from p->next until p->prev. p can be adjusted meanwhile. */
168 #define LIST_LOOP_BUT_ONE(name,i,head,p)                                \
169         for (typeof(*(p)) *i = (p)->name##_next ? (p)->name##_next : (head); \
170              i != (p);                                                  \
171              i = i->name##_next ? i->name##_next : (head))
172 
173 #define LIST_IS_EMPTY(head)                                             \
174         (!(head))
175 
176 /* Join two lists tail to head: a->b, c->d to a->b->c->d and de-initialise second list */
177 #define LIST_JOIN(name,a,b)                                             \
178         do {                                                            \
179                 assert(b);                                              \
180                 if (!(a))                                               \
181                         (a) = (b);                                      \
182                 else {                                                  \
183                         typeof(*(a)) *_head = (b), *_tail;              \
184                         LIST_FIND_TAIL(name, (a), _tail);               \
185                         _tail->name##_next = _head;                     \
186                         _head->name##_prev = _tail;                     \
187                 }                                                       \
188                 (b) = NULL;                                             \
189         } while (false)
190 
191 #define LIST_POP(name, a)                                               \
192         ({                                                              \
193                 typeof(a)* _a = &(a);                                   \
194                 typeof(a) _p = *_a;                                     \
195                 if (_p)                                                 \
196                         LIST_REMOVE(name, *_a, _p);                     \
197                 _p;                                                     \
198         })
199