1 // Copyright © Tavian Barnes <tavianator@tavianator.com>
2 // SPDX-License-Identifier: 0BSD
5 * Intrusive linked lists.
7 * Singly-linked lists are declared like this:
18 * The SLIST_*() macros manipulate singly-linked lists.
24 * SLIST_ITEM_INIT(&item);
25 * SLIST_APPEND(&list, &item);
27 * Doubly linked lists are similar:
43 * LIST_ITEM_INIT(&item);
44 * LIST_APPEND(&list, &item);
46 * Items can be on multiple lists at once:
72 * SLIST_INIT(&items.queue);
73 * LIST_INIT(&items.cache);
76 * SLIST_ITEM_INIT(&item, chain);
77 * SLIST_APPEND(&items.queue, &item, chain);
78 * LIST_ITEM_INIT(&item, lru);
79 * LIST_APPEND(&items.cache, &item, lru);
90 * Initialize a singly-linked list.
93 * The list to initialize.
97 * Like many macros in this file, this macro delegates the bulk of its work to
98 * some helper macros. We explicitly parenthesize (list) here so the helpers
101 #define SLIST_INIT(list) \
105 * Helper for SLIST_INIT().
107 #define SLIST_INIT_(list) LIST_VOID_( \
109 list->tail = &list->head)
112 * Cast a list of expressions to void.
114 #define LIST_VOID_(...) ((void)(__VA_ARGS__))
117 * Initialize a singly-linked list item.
120 * The item to initialize.
121 * @param node (optional)
122 * If specified, use item->node.next rather than item->next.
126 * We play some tricks with variadic macros to handle the optional parameter:
128 * SLIST_ITEM_INIT(item) => item->next = NULL
129 * SLIST_ITEM_INIT(item, node) => item->node.next = NULL
131 * The first trick is that
133 * #define SLIST_ITEM_INIT(item, ...)
135 * won't work because both commas are required (until C23; see N3033). As a
136 * workaround, we dispatch to another macro and add a trailing comma.
138 * SLIST_ITEM_INIT(item) => SLIST_ITEM_INIT_(item, )
139 * SLIST_ITEM_INIT(item, node) => SLIST_ITEM_INIT_(item, node, )
141 #define SLIST_ITEM_INIT(...) \
142 SLIST_ITEM_INIT_(__VA_ARGS__, )
145 * Now we need a way to generate either ->next or ->node.next depending on
146 * whether the node parameter was passed. The approach is based on
148 * #define FOO(...) BAR(__VA_ARGS__, 1, 2, )
149 * #define BAR(x, y, z, ...) z
154 * The LIST_NEXT_() macro uses this technique:
156 * LIST_NEXT_() => LIST_NODE_(next, )
157 * LIST_NEXT_(node, ) => LIST_NODE_(next, node, )
159 #define LIST_NEXT_(...) \
160 LIST_NODE_(next, __VA_ARGS__)
163 * LIST_NODE_() dispatches to yet another macro:
165 * LIST_NODE_(next, ) => LIST_NODE__(next, , . , , )
166 * LIST_NODE_(next, node, ) => LIST_NODE__(next, node, , . , , )
168 #define LIST_NODE_(dir, ...) \
169 LIST_NODE__(dir, __VA_ARGS__, . , , )
172 * And finally, LIST_NODE__() adds the node and the dot if necessary.
174 * dir node ignored dot
176 * LIST_NODE__(next, , . , , ) => next
177 * LIST_NODE__(next, node, , . , , ) => node . next
179 * dir node ignored dot
181 #define LIST_NODE__(dir, node, ignored, dot, ...) \
185 * SLIST_ITEM_INIT_() uses LIST_NEXT_() to generate the right name for the list
186 * node, and finally delegates to the actual implementation.
188 #define SLIST_ITEM_INIT_(item, ...) \
189 SLIST_ITEM_INIT__((item), LIST_NEXT_(__VA_ARGS__))
191 #define SLIST_ITEM_INIT__(item, next) \
192 LIST_VOID_(item->next = NULL)
195 * Type-checking macro for singly-linked lists.
197 #define SLIST_CHECK_(list) \
198 (void)sizeof(list->tail - &list->head)
201 * Check if a singly-linked list is empty.
203 #define SLIST_EMPTY(list) \
206 #define SLIST_EMPTY_(list) \
207 (SLIST_CHECK_(list), !list->head)
210 * Check if an item is attached to a singly-linked list.
216 * @param node (optional)
217 * If specified, use item->node.next rather than item->next.
219 * Whether the item is attached to the list.
221 #define SLIST_ATTACHED(list, ...) \
222 SLIST_ATTACHED_(list, __VA_ARGS__, )
224 #define SLIST_ATTACHED_(list, item, ...) \
225 SLIST_ATTACHED__((list), (item), LIST_NEXT_(__VA_ARGS__))
227 #define SLIST_ATTACHED__(list, item, next) \
228 (item->next || list->tail == &item->next)
231 * Insert an item into a singly-linked list.
234 * The list to modify.
236 * A pointer to the item to insert after, e.g. &list->head or list->tail.
238 * The item to insert.
239 * @param node (optional)
240 * If specified, use item->node.next rather than item->next.
242 #define SLIST_INSERT(list, cursor, ...) \
243 SLIST_INSERT_(list, cursor, __VA_ARGS__, )
245 #define SLIST_INSERT_(list, cursor, item, ...) \
246 SLIST_INSERT__((list), (cursor), (item), LIST_NEXT_(__VA_ARGS__))
248 #define SLIST_INSERT__(list, cursor, item, next) LIST_VOID_( \
249 bfs_assert(!SLIST_ATTACHED__(list, item, next)), \
250 item->next = *cursor, \
252 list->tail = item->next ? list->tail : &item->next)
255 * Add an item to the tail of a singly-linked list.
258 * The list to modify.
260 * The item to append.
261 * @param node (optional)
262 * If specified, use item->node.next rather than item->next.
264 #define SLIST_APPEND(list, ...) \
265 SLIST_APPEND_(list, __VA_ARGS__, )
267 #define SLIST_APPEND_(list, item, ...) \
268 SLIST_INSERT_(list, (list)->tail, item, __VA_ARGS__)
271 * Add an item to the head of a singly-linked list.
274 * The list to modify.
276 * The item to prepend.
277 * @param node (optional)
278 * If specified, use item->node.next rather than item->next.
280 #define SLIST_PREPEND(list, ...) \
281 SLIST_PREPEND_(list, __VA_ARGS__, )
283 #define SLIST_PREPEND_(list, item, ...) \
284 SLIST_INSERT_(list, &(list)->head, item, __VA_ARGS__)
287 * Add an entire singly-linked list to the tail of another.
290 * The destination list.
294 #define SLIST_EXTEND(dest, src) \
295 SLIST_EXTEND_((dest), (src))
297 #define SLIST_EXTEND_(dest, src) \
298 (src->head ? (*dest->tail = src->head, dest->tail = src->tail, SLIST_INIT(src)) : (void)0)
301 * Remove an item from a singly-linked list.
304 * The list to modify.
306 * A pointer to the item to remove, either &list->head or &prev->next.
307 * @param node (optional)
308 * If specified, use item->node.next rather than item->next.
312 #define SLIST_REMOVE(list, ...) \
313 SLIST_REMOVE_(list, __VA_ARGS__, )
315 #define SLIST_REMOVE_(list, cursor, ...) \
316 SLIST_REMOVE__((list), (cursor), LIST_NEXT_(__VA_ARGS__))
318 #define SLIST_REMOVE__(list, cursor, next) \
319 (list->tail = (*cursor)->next ? list->tail : cursor, \
320 slist_remove_impl(*cursor, cursor, &(*cursor)->next, list->tail, sizeof(*cursor)))
322 // Helper for SLIST_REMOVE()
323 static inline void *slist_remove_impl(void *ret, void *cursor, void *next, void *tail, size_t size) {
325 // *cursor = ret->next;
326 memcpy(cursor, next, size);
327 // ret->next = *list->tail; (NULL)
328 memcpy(next, tail, size);
333 * Pop the head off a singly-linked list.
336 * The list to modify.
337 * @param node (optional)
338 * If specified, use head->node.next rather than head->next.
340 * The popped item, or NULL if the list was empty.
342 #define SLIST_POP(...) \
343 SLIST_POP_(__VA_ARGS__, )
345 #define SLIST_POP_(list, ...) \
346 SLIST_POP__((list), __VA_ARGS__)
348 #define SLIST_POP__(list, ...) \
349 (list->head ? SLIST_REMOVE_(list, &list->head, __VA_ARGS__) : NULL)
352 * Loop over the items in a singly-linked list.
355 * The list item type.
357 * The induction variable name.
359 * The list to iterate.
360 * @param node (optional)
361 * If specified, use head->node.next rather than head->next.
363 #define for_slist(type, item, ...) \
364 for_slist_(type, item, __VA_ARGS__, )
366 #define for_slist_(type, item, list, ...) \
367 for_slist__(type, item, (list), LIST_NEXT_(__VA_ARGS__))
369 #define for_slist__(type, item, list, next) \
370 for (type *item = list->head, *_next; \
371 item && (SLIST_CHECK_(list), _next = item->next, true); \
375 * Initialize a doubly-linked list.
378 * The list to initialize.
380 #define LIST_INIT(list) \
383 #define LIST_INIT_(list) \
384 LIST_VOID_(list->head = list->tail = NULL)
387 * LIST_PREV_() => prev
388 * LIST_PREV_(node, ) => node.prev
390 #define LIST_PREV_(...) \
391 LIST_NODE_(prev, __VA_ARGS__)
394 * Initialize a doubly-linked list item.
397 * The item to initialize.
398 * @param node (optional)
399 * If specified, use item->node.next rather than item->next.
401 #define LIST_ITEM_INIT(...) \
402 LIST_ITEM_INIT_(__VA_ARGS__, )
404 #define LIST_ITEM_INIT_(item, ...) \
405 LIST_ITEM_INIT__((item), LIST_PREV_(__VA_ARGS__), LIST_NEXT_(__VA_ARGS__))
407 #define LIST_ITEM_INIT__(item, prev, next) \
408 LIST_VOID_(item->prev = item->next = NULL)
411 * Type-checking macro for doubly-linked lists.
413 #define LIST_CHECK_(list) \
414 (void)sizeof(list->tail - list->head)
417 * Check if a doubly-linked list is empty.
419 #define LIST_EMPTY(list) \
422 #define LIST_EMPTY_(list) \
423 (LIST_CHECK_(list), !list->head)
426 * Add an item to the tail of a doubly-linked list.
429 * The list to modify.
431 * The item to append.
432 * @param node (optional)
433 * If specified, use item->node.{prev,next} rather than item->{prev,next}.
435 #define LIST_APPEND(list, ...) \
436 LIST_INSERT(list, (list)->tail, __VA_ARGS__)
439 * Add an item to the head of a doubly-linked list.
442 * The list to modify.
444 * The item to prepend.
445 * @param node (optional)
446 * If specified, use item->node.{prev,next} rather than item->{prev,next}.
448 #define LIST_PREPEND(list, ...) \
449 LIST_INSERT(list, NULL, __VA_ARGS__)
452 * Check if an item is attached to a doubly-linked list.
458 * @param node (optional)
459 * If specified, use item->node.{prev,next} rather than item->{prev,next}.
461 * Whether the item is attached to the list.
463 #define LIST_ATTACHED(list, ...) \
464 LIST_ATTACHED_(list, __VA_ARGS__, )
466 #define LIST_ATTACHED_(list, item, ...) \
467 LIST_ATTACHED__((list), (item), LIST_PREV_(__VA_ARGS__), LIST_NEXT_(__VA_ARGS__))
469 #define LIST_ATTACHED__(list, item, prev, next) \
470 (item->prev || item->next || list->head == item || list->tail == item)
473 * Insert into a doubly-linked list after the given cursor.
476 * The list to modify.
478 * Insert after this element.
480 * The item to insert.
481 * @param node (optional)
482 * If specified, use item->node.{prev,next} rather than item->{prev,next}.
484 #define LIST_INSERT(list, cursor, ...) \
485 LIST_INSERT_(list, cursor, __VA_ARGS__, )
487 #define LIST_INSERT_(list, cursor, item, ...) \
488 LIST_INSERT__((list), (cursor), (item), LIST_PREV_(__VA_ARGS__), LIST_NEXT_(__VA_ARGS__))
490 #define LIST_INSERT__(list, cursor, item, prev, next) LIST_VOID_( \
491 bfs_assert(!LIST_ATTACHED__(list, item, prev, next)), \
492 item->prev = cursor, \
493 item->next = cursor ? cursor->next : list->head, \
494 *(item->prev ? &item->prev->next : &list->head) = item, \
495 *(item->next ? &item->next->prev : &list->tail) = item)
498 * Remove an item from a doubly-linked list.
501 * The list to modify.
503 * The item to remove.
504 * @param node (optional)
505 * If specified, use item->node.{prev,next} rather than item->{prev,next}.
507 #define LIST_REMOVE(list, ...) \
508 LIST_REMOVE_(list, __VA_ARGS__, )
510 #define LIST_REMOVE_(list, item, ...) \
511 LIST_REMOVE__((list), (item), LIST_PREV_(__VA_ARGS__), LIST_NEXT_(__VA_ARGS__))
513 #define LIST_REMOVE__(list, item, prev, next) LIST_VOID_( \
514 *(item->prev ? &item->prev->next : &list->head) = item->next, \
515 *(item->next ? &item->next->prev : &list->tail) = item->prev, \
516 item->prev = item->next = NULL)
519 * Loop over the items in a doubly-linked list.
522 * The list item type.
524 * The induction variable name.
526 * The list to iterate.
527 * @param node (optional)
528 * If specified, use head->node.next rather than head->next.
530 #define for_list(type, item, ...) \
531 for_list_(type, item, __VA_ARGS__, )
533 #define for_list_(type, item, list, ...) \
534 for_list__(type, item, (list), LIST_NEXT_(__VA_ARGS__))
536 #define for_list__(type, item, list, next) \
537 for (type *item = list->head, *_next; \
538 item && (LIST_CHECK_(list), _next = item->next, true); \