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