PatchworkOS  c9fea19
A non-POSIX operating system.
Loading...
Searching...
No Matches
list.h
Go to the documentation of this file.
1#ifndef _SYS_LIST_H
2#define _SYS_LIST_H 1
3
5#include "_internal/NULL.h"
6
7#include <assert.h>
8#include <stdbool.h>
9#include <stdint.h>
10
11/**
12 * @brief Doubly linked list header.
13 * @ingroup libstd
14 * @defgroup libstd_sys_list Doubly linked list
15 *
16 * The `sys/list.h` header implements a intrusive doubly linked list where the linked list entry structure is stored
17 * within each entry instead of each entry having a pointer to each stucture.
18 *
19 * Given a entry within a structure, the `CONTAINER_OF()` macro can be used to get a pointer to the structure from the
20 * list entry pointer.
21 *
22 * @{
23 */
24
25typedef struct list list_t;
26
27/**
28 * @brief A entry in a doubly linked list.
29 * @ingroup libstd_sys_list
30 * @struct list_entry_t
31 *
32 * This structure should be placed within another structure so that the `CONTAINER_OF()` macro can then be used to
33 * access the other structure.
34 */
35typedef struct list_entry
36{
37 struct list_entry* prev; ///< The previous entry in the list
38 struct list_entry* next; ///< The next entry in the list
39 list_t* list; ///< The list this entry belongs to.
41
42/**
43 * @brief A doubly linked list.
44 * @ingroup libstd_sys_list
45 *
46 * This structure simplifies reasoning around linked lists.
47 */
48typedef struct list
49{
50 list_entry_t head; ///< The head of the list, where head::prev is the last entry of the list and head::next is the
51 ///< first entry of the list.
52 uint64_t length; ///< The number of elements in the list (excluding the head).
53} list_t;
54
55/**
56 * @brief Iterates over a list.
57 * @ingroup libstd_sys_list
58 *
59 * @param elem The loop variable, a pointer to the structure containing the list entry.
60 * @param list A pointer to the `list_t` structure to iterate over.
61 * @param member The name of the `list_entry_t` member within the structure `elem`.
62 */
63#define LIST_FOR_EACH(elem, list, member) \
64 for ((elem) = CONTAINER_OF((list)->head.next, typeof(*elem), member); &(elem)->member != &((list)->head); \
65 (elem) = CONTAINER_OF((elem)->member.next, typeof(*elem), member))
66
67/**
68 * @brief Safely iterates over a list, allowing for element removal during iteration.
69 * @ingroup libstd_sys_list
70 *
71 * The `LIST_FOR_EACH_SAFE()` macro is similar to `LIST_FOR_EACH()` but uses a temporary variable to store the next
72 * element, making it safe to remove the current element during iteration.
73 *
74 * @param elem The loop variable, a pointer to the structure containing the list entry.
75 * @param temp A temporary loop variable, a pointer to the structure containing the next list entry.
76 * @param list A pointer to the `list_t` structure to iterate over.
77 * @param member The name of the `list_entry_t` member within the structure `elem`.
78 */
79#define LIST_FOR_EACH_SAFE(elem, temp, list, member) \
80 for ((elem) = CONTAINER_OF((list)->head.next, typeof(*elem), member), \
81 (temp) = CONTAINER_OF((elem)->member.next, typeof(*elem), member); \
82 &(elem)->member != &((list)->head); \
83 (elem) = (temp), (temp) = CONTAINER_OF((elem)->member.next, typeof(*elem), member))
84
85/**
86 * @brief Iterates over a list in reverse.
87 * @ingroup libstd_sys_list
88 *
89 * @param elem The loop variable, a pointer to the structure containing the list entry.
90 * @param list A pointer to the `list_t` structure to iterate over.
91 * @param member The name of the `list_entry_t` member within the structure `elem`.
92 */
93#define LIST_FOR_EACH_REVERSE(elem, list, member) \
94 for ((elem) = CONTAINER_OF((list)->head.prev, typeof(*elem), member); &(elem)->member != &((list)->head); \
95 (elem) = CONTAINER_OF((elem)->member.prev, typeof(*elem), member))
96
97/**
98 * @brief Iterates over a list starting from a specific element.
99 * @ingroup libstd_sys_list
100 *
101 * The `LIST_FOR_EACH_FROM()` macro iterates from a specific element, inclusive, until the end of the list.
102 *
103 * @param elem The loop variable, a pointer to the structure containing the list entry.
104 * @param start A pointer to the `list_entry_t` from which to start iteration.
105 * @param list A pointer to the `list_t` structure to iterate over.
106 * @param member The name of the `list_entry_t` member within the structure `elem`.
107 */
108#define LIST_FOR_EACH_FROM(elem, start, list, member) \
109 for ((elem) = CONTAINER_OF(start, typeof(*elem), member); &(elem)->member != &((list)->head); \
110 (elem) = CONTAINER_OF((elem)->member.next, typeof(*elem), member))
111
112/**
113 * @brief Iterates over a list in reverse order starting from a specific element.
114 * @ingroup libstd_sys_list
115 *
116 * @param elem The loop variable, a pointer to the structure containing the list entry.
117 * @param start A pointer to the `list_entry_t` from which to start reverse iteration.
118 * @param list A pointer to the `list_t` structure to iterate over.
119 * @param member The name of the `list_entry_t` member within the structure `elem`.
120 */
121#define LIST_FOR_EACH_FROM_REVERSE(elem, start, list, member) \
122 for ((elem) = CONTAINER_OF(start, typeof(*elem), member); &(elem)->member != &((list)->head); \
123 (elem) = CONTAINER_OF((elem)->member.prev, typeof(*elem), member))
124
125/**
126 * @brief Iterates over a list up to a specific element.
127 * @ingroup libstd_sys_list
128 *
129 * The `LIST_FOR_EACH_TO()` macro iterates from the start of the list, inclusive, until a specified element, not
130 * inclusive.
131 *
132 * @param elem The loop variable, a pointer to the structure containing the list entry.
133 * @param end A pointer to the `list_entry_t` at which to stop iteration (exclusive).
134 * @param list A pointer to the `list_t` structure to iterate over.
135 * @param member The name of the `list_entry_t` member within the structure `elem`.
136 */
137#define LIST_FOR_EACH_TO(elem, end, list, member) \
138 for ((elem) = CONTAINER_OF((list)->head.next, typeof(*elem), member); \
139 &(elem)->member != &((list)->head) && &(elem)->member != (end); \
140 (elem) = CONTAINER_OF((elem)->member.next, typeof(*elem), member))
141
142/**
143 * @brief Iterates over a list in reverse order up to a specific element.
144 * @ingroup libstd_sys_list
145 *
146 * @param elem The loop variable, a pointer to the structure containing the list entry.
147 * @param end A pointer to the `list_entry_t` at which to stop reverse iteration (exclusive).
148 * @param list A pointer to the `list_t` structure to iterate over.
149 * @param member The name of the `list_entry_t` member within the structure `elem`.
150 */
151#define LIST_FOR_EACH_TO_REVERSE(elem, end, list, member) \
152 for ((elem) = CONTAINER_OF((list)->head.prev, typeof(*elem), member); \
153 &(elem)->member != &((list)->head) && &(elem)->member != (end); \
154 (elem) = CONTAINER_OF((elem)->member.prev, typeof(*elem), member))
155
156/**
157 * @brief Creates a list entry initializer.
158 *
159 * @param name The name of the entry variable to initialize.
160 * @return A `list_entry_t` initializer for the specified entry variable.
161 */
162#define LIST_ENTRY_CREATE(name) \
163 (list_entry_t) \
164 { \
165 .prev = &(name), .next = &(name), .list = NULL \
166 }
167
168/**
169 * @brief Creates a list initializer.
170 *
171 * @param name The name of the list variable to initialize.
172 * @return A `list_t` initializer for the specified list variable.
173 */
174#define LIST_CREATE(name) (list_t){.head = {.prev = &(name).head, .next = &(name).head, .list = &(name)}, .length = 0}
175
176/**
177 * @brief Initializes a list entry.
178 * @ingroup libstd_sys_list
179 *
180 * @param entry A pointer to the `list_entry_t` to initialize.
181 */
182static inline void list_entry_init(list_entry_t* entry)
183{
184 assert(entry != NULL);
185 entry->next = entry;
186 entry->prev = entry;
187 entry->list = NULL;
188}
189
190/**
191 * @brief Initializes a list.
192 * @ingroup libstd_sys_list
193 *
194 * @param list A pointer to the `list_t` to initialize.
195 */
196static inline void list_init(list_t* list)
197{
198 assert(list != NULL);
199 list_entry_init(&list->head);
200 list->head.next->list = list; // Also sets prev
201 list->length = 0;
202}
203
204/**
205 * @brief Check if an entry belongs to a specific list.
206 * @ingroup libstd_sys_list
207 *
208 * @param list A pointer to the `list_t` to search in.
209 * @param entry A pointer to the `list_entry_t` to search for.
210 * @return `true` if the entry is in the list, `false` otherwise.
211 */
212static inline bool list_contains_entry(list_t* list, list_entry_t* entry)
213{
214 assert(list != NULL);
215 assert(entry != NULL);
216
217 return entry->list == list;
218}
219
220/**
221 * @brief Checks if a list is empty.
222 * @ingroup libstd_sys_list
223 *
224 * @param list A pointer to the `list_t` to check.
225 * @return `true` if the list is empty, `false` otherwise.
226 */
227static inline bool list_is_empty(list_t* list)
228{
229 assert(list != NULL);
230
231 bool emptyByHead = (list->head.next == &list->head);
232 bool emptyByLength = (list->length == 0);
233
234 assert(emptyByHead == emptyByLength);
235
236 return emptyByHead;
237}
238
239/**
240 * @brief Gets the length of the list.
241 * @ingroup libstd_sys_list
242 *
243 * @param list A pointer to the `list_t`.
244 * @return The number of elements in the list.
245 */
246static inline uint64_t list_length(list_t* list)
247{
248 assert(list != NULL);
249 return list->length;
250}
251
252/**
253 * @brief Adds a new element between two existing list entries.
254 * @ingroup libstd_sys_list
255 *
256 * @param list A pointer to the `list_t` that will contain the new element.
257 * @param prev A pointer to the list entry that will precede the new element.
258 * @param next A pointer to the list entry that will follow the new element.
259 * @param elem A pointer to the `list_entry_t` to add.
260 */
261static inline void list_add(list_t* list, list_entry_t* prev, list_entry_t* next, list_entry_t* entry)
262{
263 assert(list != NULL);
264 assert(prev != NULL);
265 assert(next != NULL);
266 assert(entry != NULL);
267 assert(entry->next == entry && entry->prev == entry);
268 assert(prev->next == next && next->prev == prev);
269 assert(entry->list == NULL);
270 assert(prev->list == list);
271 assert(next->list == list);
272
273 next->prev = entry;
274 entry->next = next;
275 entry->prev = prev;
276 prev->next = entry;
277
278 entry->list = list;
279 list->length++;
280}
281
282/**
283 * @brief Appends an entry to the list.
284 * @ingroup libstd_sys_list
285 *
286 * @param list A pointer to the `list_t` to append to.
287 * @param prev A pointer to the list entry after which the new entry will be appended.
288 * @param entry A pointer to the `list_entry_t` to append.
289 */
290static inline void list_append(list_t* list, list_entry_t* prev, list_entry_t* entry)
291{
292 list_add(list, prev, prev->next, entry);
293}
294
295/**
296 * @brief Prepends an entry to the list.
297 * @ingroup libstd_sys_list
298 *
299 * @param list A pointer to the `list_t` to prepend to.
300 * @param head A pointer to the list entry before which the new entry will be prepended.
301 * @param entry A pointer to the `list_entry_t` to prepend.
302 */
303static inline void list_prepend(list_t* list, list_entry_t* head, list_entry_t* entry)
304{
305 list_add(list, head->prev, head, entry);
306}
307
308/**
309 * @brief Removes a list entry from its current list.
310 * @ingroup libstd_sys_list
311 *
312 * @param list A pointer to the `list_t` that contains the entry.
313 * @param entry A pointer to the `list_entry_t` to remove.
314 */
315static inline void list_remove(list_t* list, list_entry_t* entry)
316{
317 if (entry->list == NULL)
318 {
319 return;
320 }
321
322 assert(list != NULL);
323 assert(entry != NULL);
324 assert(list->length > 0);
325 assert(entry != &list->head);
326 assert(entry->list == list);
327
328 entry->prev->next = entry->next;
329 entry->next->prev = entry->prev;
330 list_entry_init(entry);
331
332 entry->list = NULL;
333 list->length--;
334}
335
336/**
337 * @brief Pushes an entry to the end of the list.
338 * @ingroup libstd_sys_list
339 *
340 * @param list A pointer to the `list_t` to push the entry to.
341 * @param entry A pointer to the `list_entry_t` to push.
342 */
343static inline void list_push_back(list_t* list, list_entry_t* entry)
344{
345 assert(list != NULL);
346 assert(entry != NULL);
347 assert(entry->next == entry && entry->prev == entry);
348
349 list_add(list, list->head.prev, &list->head, entry);
350}
351
352/**
353 * @brief Pushes an entry to the front of the list.
354 * @ingroup libstd_sys_list
355 *
356 * @param list A pointer to the `list_t` to push the entry to.
357 * @param entry A pointer to the `list_entry_t` to push.
358 */
359static inline void list_push_front(list_t* list, list_entry_t* entry)
360{
361 assert(list != NULL);
362 assert(entry != NULL);
363 assert(entry->next == entry && entry->prev == entry);
364
365 list_add(list, &list->head, list->head.next, entry);
366}
367
368/**
369 * @brief Pops the first entry from the list.
370 * @ingroup libstd_sys_list
371 *
372 * @param list A pointer to the `list_t` to pop the entry from.
373 * @return A pointer to the removed `list_entry_t`, or `NULL` if the list is empty.
374 */
375static inline list_entry_t* list_pop_first(list_t* list)
376{
377 assert(list != NULL);
378
379 if (list_is_empty(list))
380 {
381 return NULL;
382 }
383
384 list_entry_t* entry = list->head.next;
385 list_remove(list, entry);
386 return entry;
387}
388
389/**
390 * @brief Pops the last entry from the list.
391 * @ingroup libstd_sys_list
392 *
393 * @param list A pointer to the `list_t` to pop the entry from.
394 * @return A pointer to the removed `list_entry_t`, or `NULL` if the list is empty.
395 */
396static inline list_entry_t* list_pop_last(list_t* list)
397{
398 assert(list != NULL);
399
400 if (list_is_empty(list))
401 {
402 return NULL;
403 }
404
405 list_entry_t* entry = list->head.prev;
406 list_remove(list, entry);
407 return entry;
408}
409
410/**
411 * @brief Gets the first entry in the list without removing it.
412 * @ingroup libstd_sys_list
413 *
414 * @param list A pointer to the `list_t`.
415 * @return A pointer to the first `list_entry_t` in the list, or `NULL` if the list is empty.
416 */
417static inline list_entry_t* list_first(list_t* list)
418{
419 assert(list != NULL);
420
421 if (list_is_empty(list))
422 {
423 return NULL;
424 }
425 return list->head.next;
426}
427
428/**
429 * @brief Gets the last entry in the list without removing it.
430 * @ingroup libstd_sys_list
431 *
432 * @param list A pointer to the `list_t`.
433 * @return A pointer to the last `list_entry_t` in the list, or `NULL` if the list is empty.
434 */
435static inline list_entry_t* list_last(list_t* list)
436{
437 assert(list != NULL);
438
439 if (list_is_empty(list))
440 {
441 return NULL;
442 }
443 return list->head.prev;
444}
445
446#endif
447
448/** @} */
#define assert(expression)
Definition assert.h:29
static list_entry_t * list_first(list_t *list)
Gets the first entry in the list without removing it.
Definition list.h:417
static list_entry_t * list_pop_first(list_t *list)
Pops the first entry from the list.
Definition list.h:375
static uint64_t list_length(list_t *list)
Gets the length of the list.
Definition list.h:246
static list_entry_t * list_last(list_t *list)
Gets the last entry in the list without removing it.
Definition list.h:435
static void list_push_back(list_t *list, list_entry_t *entry)
Pushes an entry to the end of the list.
Definition list.h:343
static void list_prepend(list_t *list, list_entry_t *head, list_entry_t *entry)
Prepends an entry to the list.
Definition list.h:303
static list_entry_t * list_pop_last(list_t *list)
Pops the last entry from the list.
Definition list.h:396
static void list_remove(list_t *list, list_entry_t *entry)
Removes a list entry from its current list.
Definition list.h:315
static void list_append(list_t *list, list_entry_t *prev, list_entry_t *entry)
Appends an entry to the list.
Definition list.h:290
static bool list_is_empty(list_t *list)
Checks if a list is empty.
Definition list.h:227
static void list_entry_init(list_entry_t *entry)
Initializes a list entry.
Definition list.h:182
static void list_add(list_t *list, list_entry_t *prev, list_entry_t *next, list_entry_t *entry)
Adds a new element between two existing list entries.
Definition list.h:261
static void list_push_front(list_t *list, list_entry_t *entry)
Pushes an entry to the front of the list.
Definition list.h:359
static bool list_contains_entry(list_t *list, list_entry_t *entry)
Check if an entry belongs to a specific list.
Definition list.h:212
static void list_init(list_t *list)
Initializes a list.
Definition list.h:196
#define NULL
Pointer error value.
Definition NULL.h:23
static atomic_long next
Definition main.c:11
__UINT64_TYPE__ uint64_t
Definition stdint.h:17
A entry in a doubly linked list.
Definition list.h:36
list_t * list
The list this entry belongs to.
Definition list.h:39
struct list_entry * next
The next entry in the list.
Definition list.h:38
struct list_entry * prev
The previous entry in the list.
Definition list.h:37
A doubly linked list.
Definition list.h:49
uint64_t length
The number of elements in the list (excluding the head).
Definition list.h:52
list_entry_t head
Definition list.h:50