Line data Source code
1 0 : /*
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 1 : typedef struct _dnode sys_dlist_t;
51 : /**
52 : * @brief Doubly-linked list node structure.
53 : */
54 1 : 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 1 : #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 1 : #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 1 : #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 1 : #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 1 : #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 1 : #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 1 : #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 1 : #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 :
202 1 : 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 1 : #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 :
219 1 : 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 :
233 1 : 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 :
247 1 : 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 :
261 1 : 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 :
274 1 : 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 :
289 1 : 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 :
302 1 : 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 :
317 1 : 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 :
333 1 : 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 :
349 1 : 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 :
367 1 : 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 :
384 1 : 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 :
398 1 : 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 :
412 1 : 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 :
432 1 : 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 : */
451 1 : 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 :
476 1 : 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 :
504 1 : 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 :
524 1 : 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 : */
543 1 : 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_ */
|