1 /*
2 * Copyright (c) 2013-2015 Wind River Systems, Inc.
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 /**
8 * @file
9 * @defgroup doubly-linked-list_apis Doubly-linked list
10 * @ingroup datastructure_apis
11 *
12 * @brief Doubly-linked list implementation
13 *
14 * Doubly-linked list implementation using inline macros/functions.
15 * This API is not thread safe, and thus if a list is used across threads,
16 * calls to functions must be protected with synchronization primitives.
17 *
18 * The lists are expected to be initialized such that both the head and tail
19 * pointers point to the list itself. Initializing the lists in such a fashion
20 * simplifies the adding and removing of nodes to/from the list.
21 *
22 * @{
23 */
24
25 #ifndef ZEPHYR_INCLUDE_SYS_DLIST_H_
26 #define ZEPHYR_INCLUDE_SYS_DLIST_H_
27
28 #include <stddef.h>
29 #include <stdbool.h>
30
31 #ifdef __cplusplus
32 extern "C" {
33 #endif
34
35
36 struct _dnode {
37 union {
38 struct _dnode *head; /* ptr to head of list (sys_dlist_t) */
39 struct _dnode *next; /* ptr to next node (sys_dnode_t) */
40 };
41 union {
42 struct _dnode *tail; /* ptr to tail of list (sys_dlist_t) */
43 struct _dnode *prev; /* ptr to previous node (sys_dnode_t) */
44 };
45 };
46
47 /**
48 * @brief Doubly-linked list structure.
49 */
50 typedef struct _dnode sys_dlist_t;
51 /**
52 * @brief Doubly-linked list node structure.
53 */
54 typedef struct _dnode sys_dnode_t;
55
56
57 /**
58 * @brief Provide the primitive to iterate on a list
59 * Note: the loop is unsafe and thus __dn should not be removed
60 *
61 * User _MUST_ add the loop statement curly braces enclosing its own code:
62 *
63 * SYS_DLIST_FOR_EACH_NODE(l, n) {
64 * <user code>
65 * }
66 *
67 * This and other SYS_DLIST_*() macros are not thread safe.
68 *
69 * @param __dl A pointer on a sys_dlist_t to iterate on
70 * @param __dn A sys_dnode_t pointer to peek each node of the list
71 */
72 #define SYS_DLIST_FOR_EACH_NODE(__dl, __dn) \
73 for (__dn = sys_dlist_peek_head(__dl); __dn != NULL; \
74 __dn = sys_dlist_peek_next(__dl, __dn))
75
76 /**
77 * @brief Provide the primitive to iterate on a list, from a node in the list
78 * Note: the loop is unsafe and thus __dn should not be removed
79 *
80 * User _MUST_ add the loop statement curly braces enclosing its own code:
81 *
82 * SYS_DLIST_ITERATE_FROM_NODE(l, n) {
83 * <user code>
84 * }
85 *
86 * Like SYS_DLIST_FOR_EACH_NODE(), but __dn already contains a node in the list
87 * where to start searching for the next entry from. If NULL, it starts from
88 * the head.
89 *
90 * This and other SYS_DLIST_*() macros are not thread safe.
91 *
92 * @param __dl A pointer on a sys_dlist_t to iterate on
93 * @param __dn A sys_dnode_t pointer to peek each node of the list;
94 * it contains the starting node, or NULL to start from the head
95 */
96 #define SYS_DLIST_ITERATE_FROM_NODE(__dl, __dn) \
97 for (__dn = __dn ? sys_dlist_peek_next_no_check(__dl, __dn) \
98 : sys_dlist_peek_head(__dl); \
99 __dn != NULL; \
100 __dn = sys_dlist_peek_next(__dl, __dn))
101
102 /**
103 * @brief Provide the primitive to safely iterate on a list
104 * Note: __dn can be removed, it will not break the loop.
105 *
106 * User _MUST_ add the loop statement curly braces enclosing its own code:
107 *
108 * SYS_DLIST_FOR_EACH_NODE_SAFE(l, n, s) {
109 * <user code>
110 * }
111 *
112 * This and other SYS_DLIST_*() macros are not thread safe.
113 *
114 * @param __dl A pointer on a sys_dlist_t to iterate on
115 * @param __dn A sys_dnode_t pointer to peek each node of the list
116 * @param __dns A sys_dnode_t pointer for the loop to run safely
117 */
118 #define SYS_DLIST_FOR_EACH_NODE_SAFE(__dl, __dn, __dns) \
119 for ((__dn) = sys_dlist_peek_head(__dl), \
120 (__dns) = sys_dlist_peek_next((__dl), (__dn)); \
121 (__dn) != NULL; (__dn) = (__dns), \
122 (__dns) = sys_dlist_peek_next(__dl, __dn))
123
124 /**
125 * @brief Provide the primitive to resolve the container of a list node
126 * Note: it is safe to use with NULL pointer nodes
127 *
128 * @param __dn A pointer on a sys_dnode_t to get its container
129 * @param __cn Container struct type pointer
130 * @param __n The field name of sys_dnode_t within the container struct
131 */
132 #define SYS_DLIST_CONTAINER(__dn, __cn, __n) \
133 (((__dn) != NULL) ? CONTAINER_OF(__dn, __typeof__(*(__cn)), __n) : NULL)
134 /**
135 * @brief Provide the primitive to peek container of the list head
136 *
137 * @param __dl A pointer on a sys_dlist_t to peek
138 * @param __cn Container struct type pointer
139 * @param __n The field name of sys_dnode_t within the container struct
140 */
141 #define SYS_DLIST_PEEK_HEAD_CONTAINER(__dl, __cn, __n) \
142 SYS_DLIST_CONTAINER(sys_dlist_peek_head(__dl), __cn, __n)
143
144 /**
145 * @brief Provide the primitive to peek the next container
146 *
147 * @param __dl A pointer on a sys_dlist_t to peek
148 * @param __cn Container struct type pointer
149 * @param __n The field name of sys_dnode_t within the container struct
150 */
151 #define SYS_DLIST_PEEK_NEXT_CONTAINER(__dl, __cn, __n) \
152 (((__cn) != NULL) ? \
153 SYS_DLIST_CONTAINER(sys_dlist_peek_next((__dl), &((__cn)->__n)), \
154 __cn, __n) : NULL)
155
156 /**
157 * @brief Provide the primitive to iterate on a list under a container
158 * Note: the loop is unsafe and thus __cn should not be detached
159 *
160 * User _MUST_ add the loop statement curly braces enclosing its own code:
161 *
162 * SYS_DLIST_FOR_EACH_CONTAINER(l, c, n) {
163 * <user code>
164 * }
165 *
166 * @param __dl A pointer on a sys_dlist_t to iterate on
167 * @param __cn A container struct type pointer to peek each entry of the list
168 * @param __n The field name of sys_dnode_t within the container struct
169 */
170 #define SYS_DLIST_FOR_EACH_CONTAINER(__dl, __cn, __n) \
171 for ((__cn) = SYS_DLIST_PEEK_HEAD_CONTAINER(__dl, __cn, __n); \
172 (__cn) != NULL; \
173 (__cn) = SYS_DLIST_PEEK_NEXT_CONTAINER(__dl, __cn, __n))
174
175 /**
176 * @brief Provide the primitive to safely iterate on a list under a container
177 * Note: __cn can be detached, it will not break the loop.
178 *
179 * User _MUST_ add the loop statement curly braces enclosing its own code:
180 *
181 * SYS_DLIST_FOR_EACH_CONTAINER_SAFE(l, c, cn, n) {
182 * <user code>
183 * }
184 *
185 * @param __dl A pointer on a sys_dlist_t to iterate on
186 * @param __cn A container struct type pointer to peek each entry of the list
187 * @param __cns A container struct type pointer for the loop to run safely
188 * @param __n The field name of sys_dnode_t within the container struct
189 */
190 #define SYS_DLIST_FOR_EACH_CONTAINER_SAFE(__dl, __cn, __cns, __n) \
191 for ((__cn) = SYS_DLIST_PEEK_HEAD_CONTAINER(__dl, __cn, __n), \
192 (__cns) = SYS_DLIST_PEEK_NEXT_CONTAINER(__dl, __cn, __n); \
193 (__cn) != NULL; (__cn) = (__cns), \
194 (__cns) = SYS_DLIST_PEEK_NEXT_CONTAINER(__dl, __cn, __n))
195
196 /**
197 * @brief initialize list to its empty state
198 *
199 * @param list the doubly-linked list
200 */
201
sys_dlist_init(sys_dlist_t * list)202 static inline void sys_dlist_init(sys_dlist_t *list)
203 {
204 list->head = (sys_dnode_t *)list;
205 list->tail = (sys_dnode_t *)list;
206 }
207
208 /**
209 * @brief Static initializer for a doubly-linked list
210 */
211 #define SYS_DLIST_STATIC_INIT(ptr_to_list) { {(ptr_to_list)}, {(ptr_to_list)} }
212
213 /**
214 * @brief initialize node to its state when not in a list
215 *
216 * @param node the node
217 */
218
sys_dnode_init(sys_dnode_t * node)219 static inline void sys_dnode_init(sys_dnode_t *node)
220 {
221 node->next = NULL;
222 node->prev = NULL;
223 }
224
225 /**
226 * @brief check if a node is a member of any list
227 *
228 * @param node the node
229 *
230 * @return true if node is linked into a list, false if it is not
231 */
232
sys_dnode_is_linked(const sys_dnode_t * node)233 static inline bool sys_dnode_is_linked(const sys_dnode_t *node)
234 {
235 return node->next != NULL;
236 }
237
238 /**
239 * @brief check if a node is the list's head
240 *
241 * @param list the doubly-linked list to operate on
242 * @param node the node to check
243 *
244 * @return true if node is the head, false otherwise
245 */
246
sys_dlist_is_head(sys_dlist_t * list,sys_dnode_t * node)247 static inline bool sys_dlist_is_head(sys_dlist_t *list, sys_dnode_t *node)
248 {
249 return list->head == node;
250 }
251
252 /**
253 * @brief check if a node is the list's tail
254 *
255 * @param list the doubly-linked list to operate on
256 * @param node the node to check
257 *
258 * @return true if node is the tail, false otherwise
259 */
260
sys_dlist_is_tail(sys_dlist_t * list,sys_dnode_t * node)261 static inline bool sys_dlist_is_tail(sys_dlist_t *list, sys_dnode_t *node)
262 {
263 return list->tail == node;
264 }
265
266 /**
267 * @brief check if the list is empty
268 *
269 * @param list the doubly-linked list to operate on
270 *
271 * @return true if empty, false otherwise
272 */
273
sys_dlist_is_empty(sys_dlist_t * list)274 static inline bool sys_dlist_is_empty(sys_dlist_t *list)
275 {
276 return list->head == list;
277 }
278
279 /**
280 * @brief check if more than one node present
281 *
282 * This and other sys_dlist_*() functions are not thread safe.
283 *
284 * @param list the doubly-linked list to operate on
285 *
286 * @return true if multiple nodes, false otherwise
287 */
288
sys_dlist_has_multiple_nodes(sys_dlist_t * list)289 static inline bool sys_dlist_has_multiple_nodes(sys_dlist_t *list)
290 {
291 return list->head != list->tail;
292 }
293
294 /**
295 * @brief get a reference to the head item in the list
296 *
297 * @param list the doubly-linked list to operate on
298 *
299 * @return a pointer to the head element, NULL if list is empty
300 */
301
sys_dlist_peek_head(sys_dlist_t * list)302 static inline sys_dnode_t *sys_dlist_peek_head(sys_dlist_t *list)
303 {
304 return sys_dlist_is_empty(list) ? NULL : list->head;
305 }
306
307 /**
308 * @brief get a reference to the head item in the list
309 *
310 * The list must be known to be non-empty.
311 *
312 * @param list the doubly-linked list to operate on
313 *
314 * @return a pointer to the head element
315 */
316
sys_dlist_peek_head_not_empty(sys_dlist_t * list)317 static inline sys_dnode_t *sys_dlist_peek_head_not_empty(sys_dlist_t *list)
318 {
319 return list->head;
320 }
321
322 /**
323 * @brief get a reference to the next item in the list, node is not NULL
324 *
325 * Faster than sys_dlist_peek_next() if node is known not to be NULL.
326 *
327 * @param list the doubly-linked list to operate on
328 * @param node the node from which to get the next element in the list
329 *
330 * @return a pointer to the next element from a node, NULL if node is the tail
331 */
332
sys_dlist_peek_next_no_check(sys_dlist_t * list,sys_dnode_t * node)333 static inline sys_dnode_t *sys_dlist_peek_next_no_check(sys_dlist_t *list,
334 sys_dnode_t *node)
335 {
336 return (node == list->tail) ? NULL : node->next;
337 }
338
339 /**
340 * @brief get a reference to the next item in the list
341 *
342 * @param list the doubly-linked list to operate on
343 * @param node the node from which to get the next element in the list
344 *
345 * @return a pointer to the next element from a node, NULL if node is the tail
346 * or NULL (when node comes from reading the head of an empty list).
347 */
348
sys_dlist_peek_next(sys_dlist_t * list,sys_dnode_t * node)349 static inline sys_dnode_t *sys_dlist_peek_next(sys_dlist_t *list,
350 sys_dnode_t *node)
351 {
352 return (node != NULL) ? sys_dlist_peek_next_no_check(list, node) : NULL;
353 }
354
355 /**
356 * @brief get a reference to the previous item in the list, node is not NULL
357 *
358 * Faster than sys_dlist_peek_prev() if node is known not to be NULL.
359 *
360 * @param list the doubly-linked list to operate on
361 * @param node the node from which to get the previous element in the list
362 *
363 * @return a pointer to the previous element from a node, NULL if node is the
364 * tail
365 */
366
sys_dlist_peek_prev_no_check(sys_dlist_t * list,sys_dnode_t * node)367 static inline sys_dnode_t *sys_dlist_peek_prev_no_check(sys_dlist_t *list,
368 sys_dnode_t *node)
369 {
370 return (node == list->head) ? NULL : node->prev;
371 }
372
373 /**
374 * @brief get a reference to the previous item in the list
375 *
376 * @param list the doubly-linked list to operate on
377 * @param node the node from which to get the previous element in the list
378 *
379 * @return a pointer to the previous element from a node, NULL if node is the
380 * tail or NULL (when node comes from reading the head of an empty
381 * list).
382 */
383
sys_dlist_peek_prev(sys_dlist_t * list,sys_dnode_t * node)384 static inline sys_dnode_t *sys_dlist_peek_prev(sys_dlist_t *list,
385 sys_dnode_t *node)
386 {
387 return (node != NULL) ? sys_dlist_peek_prev_no_check(list, node) : NULL;
388 }
389
390 /**
391 * @brief get a reference to the tail item in the list
392 *
393 * @param list the doubly-linked list to operate on
394 *
395 * @return a pointer to the tail element, NULL if list is empty
396 */
397
sys_dlist_peek_tail(sys_dlist_t * list)398 static inline sys_dnode_t *sys_dlist_peek_tail(sys_dlist_t *list)
399 {
400 return sys_dlist_is_empty(list) ? NULL : list->tail;
401 }
402
403 /**
404 * @brief add node to tail of list
405 *
406 * This and other sys_dlist_*() functions are not thread safe.
407 *
408 * @param list the doubly-linked list to operate on
409 * @param node the element to append
410 */
411
sys_dlist_append(sys_dlist_t * list,sys_dnode_t * node)412 static inline void sys_dlist_append(sys_dlist_t *list, sys_dnode_t *node)
413 {
414 sys_dnode_t *const tail = list->tail;
415
416 node->next = list;
417 node->prev = tail;
418
419 tail->next = node;
420 list->tail = node;
421 }
422
423 /**
424 * @brief add node to head of list
425 *
426 * This and other sys_dlist_*() functions are not thread safe.
427 *
428 * @param list the doubly-linked list to operate on
429 * @param node the element to append
430 */
431
sys_dlist_prepend(sys_dlist_t * list,sys_dnode_t * node)432 static inline void sys_dlist_prepend(sys_dlist_t *list, sys_dnode_t *node)
433 {
434 sys_dnode_t *const head = list->head;
435
436 node->next = head;
437 node->prev = list;
438
439 head->prev = node;
440 list->head = node;
441 }
442
443 /**
444 * @brief Insert a node into a list
445 *
446 * Insert a node before a specified node in a dlist.
447 *
448 * @param successor the position before which "node" will be inserted
449 * @param node the element to insert
450 */
sys_dlist_insert(sys_dnode_t * successor,sys_dnode_t * node)451 static inline void sys_dlist_insert(sys_dnode_t *successor, sys_dnode_t *node)
452 {
453 sys_dnode_t *const prev = successor->prev;
454
455 node->prev = prev;
456 node->next = successor;
457 prev->next = node;
458 successor->prev = node;
459 }
460
461 /**
462 * @brief insert node at position
463 *
464 * Insert a node in a location depending on a external condition. The cond()
465 * function checks if the node is to be inserted _before_ the current node
466 * against which it is checked.
467 * This and other sys_dlist_*() functions are not thread safe.
468 *
469 * @param list the doubly-linked list to operate on
470 * @param node the element to insert
471 * @param cond a function that determines if the current node is the correct
472 * insert point
473 * @param data parameter to cond()
474 */
475
sys_dlist_insert_at(sys_dlist_t * list,sys_dnode_t * node,int (* cond)(sys_dnode_t * node,void * data),void * data)476 static inline void sys_dlist_insert_at(sys_dlist_t *list, sys_dnode_t *node,
477 int (*cond)(sys_dnode_t *node, void *data), void *data)
478 {
479 if (sys_dlist_is_empty(list)) {
480 sys_dlist_append(list, node);
481 } else {
482 sys_dnode_t *pos = sys_dlist_peek_head(list);
483
484 while ((pos != NULL) && (cond(pos, data) == 0)) {
485 pos = sys_dlist_peek_next(list, pos);
486 }
487 if (pos != NULL) {
488 sys_dlist_insert(pos, node);
489 } else {
490 sys_dlist_append(list, node);
491 }
492 }
493 }
494
495 /**
496 * @brief remove a specific node from a list
497 *
498 * The list is implicit from the node. The node must be part of a list.
499 * This and other sys_dlist_*() functions are not thread safe.
500 *
501 * @param node the node to remove
502 */
503
sys_dlist_remove(sys_dnode_t * node)504 static inline void sys_dlist_remove(sys_dnode_t *node)
505 {
506 sys_dnode_t *const prev = node->prev;
507 sys_dnode_t *const next = node->next;
508
509 prev->next = next;
510 next->prev = prev;
511 sys_dnode_init(node);
512 }
513
514 /**
515 * @brief get the first node in a list
516 *
517 * This and other sys_dlist_*() functions are not thread safe.
518 *
519 * @param list the doubly-linked list to operate on
520 *
521 * @return the first node in the list, NULL if list is empty
522 */
523
sys_dlist_get(sys_dlist_t * list)524 static inline sys_dnode_t *sys_dlist_get(sys_dlist_t *list)
525 {
526 sys_dnode_t *node = NULL;
527
528 if (!sys_dlist_is_empty(list)) {
529 node = list->head;
530 sys_dlist_remove(node);
531 }
532
533 return node;
534 }
535
536 /**
537 * @brief Compute the size of the given list in O(n) time
538 *
539 * @param list A pointer on the list
540 *
541 * @return an integer equal to the size of the list, or 0 if empty
542 */
sys_dlist_len(sys_dlist_t * list)543 static inline size_t sys_dlist_len(sys_dlist_t *list)
544 {
545 size_t len = 0;
546 sys_dnode_t *node = NULL;
547
548 SYS_DLIST_FOR_EACH_NODE(list, node) {
549 len++;
550 }
551 return len;
552 }
553
554 /** @} */
555
556 #ifdef __cplusplus
557 }
558 #endif
559
560 #endif /* ZEPHYR_INCLUDE_SYS_DLIST_H_ */
561