1 /*
2  * Copyright (c) 2016 Intel Corporation
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7  /**
8   * @file
9   * @defgroup flagged-single-linked-list_apis Flagged Single-linked list
10   * @ingroup datastructure_apis
11   *
12   * @brief Flagged single-linked list implementation.
13   *
14   * Similar to @ref single-linked-list_apis with the added ability to define
15   * user "flags" bits for each node. They can be accessed and modified
16   * using the sys_sfnode_flags_get() and sys_sfnode_flags_set() APIs.
17   *
18   * Flagged single-linked list implementation using inline macros/functions.
19   * This API is not thread safe, and thus if a list is used across threads,
20   * calls to functions must be protected with synchronization primitives.
21   *
22   * @{
23   */
24 
25 #ifndef ZEPHYR_INCLUDE_SYS_SFLIST_H_
26 #define ZEPHYR_INCLUDE_SYS_SFLIST_H_
27 
28 #include <stdint.h>
29 #include <stdbool.h>
30 #include <zephyr/sys/__assert.h>
31 #include "list_gen.h"
32 
33 #ifdef __cplusplus
34 extern "C" {
35 #endif
36 
37 /** @cond INTERNAL_HIDDEN */
38 struct _sfnode {
39 	uintptr_t next_and_flags;
40 };
41 /** @endcond */
42 
43 /** Flagged single-linked list node structure. */
44 typedef struct _sfnode sys_sfnode_t;
45 
46 /** @cond INTERNAL_HIDDEN */
47 struct _sflist {
48 	sys_sfnode_t *head;
49 	sys_sfnode_t *tail;
50 };
51 /** @endcond */
52 
53 /** Flagged single-linked list structure. */
54 typedef struct _sflist sys_sflist_t;
55 
56 /**
57  * @brief Provide the primitive to iterate on a list
58  * Note: the loop is unsafe and thus __sn should not be removed
59  *
60  * User _MUST_ add the loop statement curly braces enclosing its own code:
61  *
62  *     SYS_SFLIST_FOR_EACH_NODE(l, n) {
63  *         <user code>
64  *     }
65  *
66  * This and other SYS_SFLIST_*() macros are not thread safe.
67  *
68  * @param __sl A pointer on a sys_sflist_t to iterate on
69  * @param __sn A sys_sfnode_t pointer to peek each node of the list
70  */
71 #define SYS_SFLIST_FOR_EACH_NODE(__sl, __sn)				\
72 	Z_GENLIST_FOR_EACH_NODE(sflist, __sl, __sn)
73 
74 /**
75  * @brief Provide the primitive to iterate on a list, from a node in the list
76  * Note: the loop is unsafe and thus __sn should not be removed
77  *
78  * User _MUST_ add the loop statement curly braces enclosing its own code:
79  *
80  *     SYS_SFLIST_ITERATE_FROM_NODE(l, n) {
81  *         <user code>
82  *     }
83  *
84  * Like SYS_SFLIST_FOR_EACH_NODE(), but __dn already contains a node in the list
85  * where to start searching for the next entry from. If NULL, it starts from
86  * the head.
87  *
88  * This and other SYS_SFLIST_*() macros are not thread safe.
89  *
90  * @param __sl A pointer on a sys_sflist_t to iterate on
91  * @param __sn A sys_sfnode_t pointer to peek each node of the list
92  *             it contains the starting node, or NULL to start from the head
93  */
94 #define SYS_SFLIST_ITERATE_FROM_NODE(__sl, __sn)				\
95 	Z_GENLIST_ITERATE_FROM_NODE(sflist, __sl, __sn)
96 
97 /**
98  * @brief Provide the primitive to safely iterate on a list
99  * Note: __sn can be removed, it will not break the loop.
100  *
101  * User _MUST_ add the loop statement curly braces enclosing its own code:
102  *
103  *     SYS_SFLIST_FOR_EACH_NODE_SAFE(l, n, s) {
104  *         <user code>
105  *     }
106  *
107  * This and other SYS_SFLIST_*() macros are not thread safe.
108  *
109  * @param __sl A pointer on a sys_sflist_t to iterate on
110  * @param __sn A sys_sfnode_t pointer to peek each node of the list
111  * @param __sns A sys_sfnode_t pointer for the loop to run safely
112  */
113 #define SYS_SFLIST_FOR_EACH_NODE_SAFE(__sl, __sn, __sns)			\
114 	Z_GENLIST_FOR_EACH_NODE_SAFE(sflist, __sl, __sn, __sns)
115 
116 /**
117  * @brief Provide the primitive to resolve the container of a list node
118  * Note: it is safe to use with NULL pointer nodes
119  *
120  * @param __ln A pointer on a sys_sfnode_t to get its container
121  * @param __cn Container struct type pointer
122  * @param __n The field name of sys_sfnode_t within the container struct
123  */
124 #define SYS_SFLIST_CONTAINER(__ln, __cn, __n) \
125 	Z_GENLIST_CONTAINER(__ln, __cn, __n)
126 
127 /**
128  * @brief Provide the primitive to peek container of the list head
129  *
130  * @param __sl A pointer on a sys_sflist_t to peek
131  * @param __cn Container struct type pointer
132  * @param __n The field name of sys_sfnode_t within the container struct
133  */
134 #define SYS_SFLIST_PEEK_HEAD_CONTAINER(__sl, __cn, __n) \
135 	Z_GENLIST_PEEK_HEAD_CONTAINER(sflist, __sl, __cn, __n)
136 
137 /**
138  * @brief Provide the primitive to peek container of the list tail
139  *
140  * @param __sl A pointer on a sys_sflist_t to peek
141  * @param __cn Container struct type pointer
142  * @param __n The field name of sys_sfnode_t within the container struct
143  */
144 #define SYS_SFLIST_PEEK_TAIL_CONTAINER(__sl, __cn, __n) \
145 	Z_GENLIST_PEEK_TAIL_CONTAINER(sflist, __sl, __cn, __n)
146 
147 /**
148  * @brief Provide the primitive to peek the next container
149  *
150  * @param __cn Container struct type pointer
151  * @param __n The field name of sys_sfnode_t within the container struct
152  */
153 #define SYS_SFLIST_PEEK_NEXT_CONTAINER(__cn, __n) \
154 	Z_GENLIST_PEEK_NEXT_CONTAINER(sflist, __cn, __n)
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_SFLIST_FOR_EACH_CONTAINER(l, c, n) {
163  *         <user code>
164  *     }
165  *
166  * @param __sl A pointer on a sys_sflist_t to iterate on
167  * @param __cn A pointer to peek each entry of the list
168  * @param __n The field name of sys_sfnode_t within the container struct
169  */
170 #define SYS_SFLIST_FOR_EACH_CONTAINER(__sl, __cn, __n)			\
171 	Z_GENLIST_FOR_EACH_CONTAINER(sflist, __sl, __cn, __n)
172 
173 /**
174  * @brief Provide the primitive to safely iterate on a list under a container
175  * Note: __cn can be detached, it will not break the loop.
176  *
177  * User _MUST_ add the loop statement curly braces enclosing its own code:
178  *
179  *     SYS_SFLIST_FOR_EACH_NODE_SAFE(l, c, cn, n) {
180  *         <user code>
181  *     }
182  *
183  * @param __sl A pointer on a sys_sflist_t to iterate on
184  * @param __cn A pointer to peek each entry of the list
185  * @param __cns A pointer for the loop to run safely
186  * @param __n The field name of sys_sfnode_t within the container struct
187  */
188 #define SYS_SFLIST_FOR_EACH_CONTAINER_SAFE(__sl, __cn, __cns, __n)	\
189 	Z_GENLIST_FOR_EACH_CONTAINER_SAFE(sflist, __sl, __cn, __cns, __n)
190 
191 
192 /*
193  * Required function definitions for the list_gen.h interface
194  *
195  * These are the only functions that do not treat the list/node pointers
196  * as completely opaque types.
197  */
198 
199 /**
200  * @brief Initialize a list
201  *
202  * @param list A pointer on the list to initialize
203  */
sys_sflist_init(sys_sflist_t * list)204 static inline void sys_sflist_init(sys_sflist_t *list)
205 {
206 	list->head = NULL;
207 	list->tail = NULL;
208 }
209 
210 /**
211  * @brief Statically initialize a flagged single-linked list
212  * @param ptr_to_list A pointer on the list to initialize
213  */
214 #define SYS_SFLIST_STATIC_INIT(ptr_to_list) {NULL, NULL}
215 
216 /* Flag bits are stored in unused LSB of the sys_sfnode_t pointer */
217 #define SYS_SFLIST_FLAGS_MASK	((uintptr_t)(__alignof__(sys_sfnode_t) - 1))
218 /* At least 2 available flag bits are expected */
219 BUILD_ASSERT(SYS_SFLIST_FLAGS_MASK >= 0x3);
220 
z_sfnode_next_peek(sys_sfnode_t * node)221 static inline sys_sfnode_t *z_sfnode_next_peek(sys_sfnode_t *node)
222 {
223 	return (sys_sfnode_t *)(node->next_and_flags & ~SYS_SFLIST_FLAGS_MASK);
224 }
225 
226 static inline uint8_t sys_sfnode_flags_get(sys_sfnode_t *node);
227 
z_sfnode_next_set(sys_sfnode_t * parent,sys_sfnode_t * child)228 static inline void z_sfnode_next_set(sys_sfnode_t *parent,
229 				       sys_sfnode_t *child)
230 {
231 	uint8_t cur_flags = sys_sfnode_flags_get(parent);
232 
233 	parent->next_and_flags = cur_flags | (uintptr_t)child;
234 }
235 
z_sflist_head_set(sys_sflist_t * list,sys_sfnode_t * node)236 static inline void z_sflist_head_set(sys_sflist_t *list, sys_sfnode_t *node)
237 {
238 	list->head = node;
239 }
240 
z_sflist_tail_set(sys_sflist_t * list,sys_sfnode_t * node)241 static inline void z_sflist_tail_set(sys_sflist_t *list, sys_sfnode_t *node)
242 {
243 	list->tail = node;
244 }
245 
246 /**
247  * @brief Peek the first node from the list
248  *
249  * @param list A point on the list to peek the first node from
250  *
251  * @return A pointer on the first node of the list (or NULL if none)
252  */
sys_sflist_peek_head(sys_sflist_t * list)253 static inline sys_sfnode_t *sys_sflist_peek_head(sys_sflist_t *list)
254 {
255 	return list->head;
256 }
257 
258 /**
259  * @brief Peek the last node from the list
260  *
261  * @param list A point on the list to peek the last node from
262  *
263  * @return A pointer on the last node of the list (or NULL if none)
264  */
sys_sflist_peek_tail(sys_sflist_t * list)265 static inline sys_sfnode_t *sys_sflist_peek_tail(sys_sflist_t *list)
266 {
267 	return list->tail;
268 }
269 
270 /*
271  * APIs specific to sflist type
272  */
273 
274 /**
275  * @brief Fetch flags value for a particular sfnode
276  *
277  * @param node A pointer to the node to fetch flags from
278  * @return The value of flags, which will be between 0 and 3 on 32-bit
279  *         architectures, or between 0 and 7 on 64-bit architectures
280  */
sys_sfnode_flags_get(sys_sfnode_t * node)281 static inline uint8_t sys_sfnode_flags_get(sys_sfnode_t *node)
282 {
283 	return node->next_and_flags & SYS_SFLIST_FLAGS_MASK;
284 }
285 
286 /**
287  * @brief Initialize an sflist node
288  *
289  * Set an initial flags value for this slist node, which can be a value between
290  * 0 and 3 on 32-bit architectures, or between 0 and 7 on 64-bit architectures.
291  * These flags will persist even if the node is moved around within a list,
292  * removed, or transplanted to a different slist.
293  *
294  * This is ever so slightly faster than sys_sfnode_flags_set() and should
295  * only be used on a node that hasn't been added to any list.
296  *
297  * @param node A pointer to the node to set the flags on
298  * @param flags The flags value to set
299  */
sys_sfnode_init(sys_sfnode_t * node,uint8_t flags)300 static inline void sys_sfnode_init(sys_sfnode_t *node, uint8_t flags)
301 {
302 	__ASSERT((flags & ~SYS_SFLIST_FLAGS_MASK) == 0UL, "flags too large");
303 	node->next_and_flags = flags;
304 }
305 
306 /**
307  * @brief Set flags value for an sflist node
308  *
309  * Set a flags value for this slist node, which can be a value between
310  * 0 and 3 on 32-bit architectures, or between 0 and 7 on 64-bit architectures.
311  * These flags will persist even if the node is moved around within a list,
312  * removed, or transplanted to a different slist.
313  *
314  * @param node A pointer to the node to set the flags on
315  * @param flags The flags value to set
316  */
sys_sfnode_flags_set(sys_sfnode_t * node,uint8_t flags)317 static inline void sys_sfnode_flags_set(sys_sfnode_t *node, uint8_t flags)
318 {
319 	__ASSERT((flags & ~SYS_SFLIST_FLAGS_MASK) == 0UL, "flags too large");
320 	node->next_and_flags = (uintptr_t)(z_sfnode_next_peek(node)) | flags;
321 }
322 
323 /*
324  * Derived, generated APIs
325  */
326 
327 /**
328  * @brief Test if the given list is empty
329  *
330  * @param list A pointer on the list to test
331  *
332  * @return a boolean, true if it's empty, false otherwise
333  */
334 static inline bool sys_sflist_is_empty(sys_sflist_t *list);
335 
336 Z_GENLIST_IS_EMPTY(sflist)
337 
338 /**
339  * @brief Peek the next node from current node, node is not NULL
340  *
341  * Faster then sys_sflist_peek_next() if node is known not to be NULL.
342  *
343  * @param node A pointer on the node where to peek the next node
344  *
345  * @return a pointer on the next node (or NULL if none)
346  */
347 static inline sys_sfnode_t *sys_sflist_peek_next_no_check(sys_sfnode_t *node);
348 
349 Z_GENLIST_PEEK_NEXT_NO_CHECK(sflist, sfnode)
350 
351 /**
352  * @brief Peek the next node from current node
353  *
354  * @param node A pointer on the node where to peek the next node
355  *
356  * @return a pointer on the next node (or NULL if none)
357  */
358 static inline sys_sfnode_t *sys_sflist_peek_next(sys_sfnode_t *node);
359 
360 Z_GENLIST_PEEK_NEXT(sflist, sfnode)
361 
362 /**
363  * @brief Prepend a node to the given list
364  *
365  * This and other sys_sflist_*() functions are not thread safe.
366  *
367  * @param list A pointer on the list to affect
368  * @param node A pointer on the node to prepend
369  */
370 static inline void sys_sflist_prepend(sys_sflist_t *list,
371 				      sys_sfnode_t *node);
372 
373 Z_GENLIST_PREPEND(sflist, sfnode)
374 
375 /**
376  * @brief Append a node to the given list
377  *
378  * This and other sys_sflist_*() functions are not thread safe.
379  *
380  * @param list A pointer on the list to affect
381  * @param node A pointer on the node to append
382  */
383 static inline void sys_sflist_append(sys_sflist_t *list,
384 				     sys_sfnode_t *node);
385 
386 Z_GENLIST_APPEND(sflist, sfnode)
387 
388 /**
389  * @brief Append a list to the given list
390  *
391  * Append a singly-linked, NULL-terminated list consisting of nodes containing
392  * the pointer to the next node as the first element of a node, to @a list.
393  * This and other sys_sflist_*() functions are not thread safe.
394  *
395  * FIXME: Why are the element parameters void *?
396  *
397  * @param list A pointer on the list to affect
398  * @param head A pointer to the first element of the list to append
399  * @param tail A pointer to the last element of the list to append
400  */
401 static inline void sys_sflist_append_list(sys_sflist_t *list,
402 					  void *head, void *tail);
403 
404 Z_GENLIST_APPEND_LIST(sflist, sfnode)
405 
406 /**
407  * @brief merge two sflists, appending the second one to the first
408  *
409  * When the operation is completed, the appending list is empty.
410  * This and other sys_sflist_*() functions are not thread safe.
411  *
412  * @param list A pointer on the list to affect
413  * @param list_to_append A pointer to the list to append.
414  */
415 static inline void sys_sflist_merge_sflist(sys_sflist_t *list,
416 					   sys_sflist_t *list_to_append);
417 
418 Z_GENLIST_MERGE_LIST(sflist, sfnode)
419 
420 /**
421  * @brief Insert a node to the given list
422  *
423  * This and other sys_sflist_*() functions are not thread safe.
424  *
425  * @param list A pointer on the list to affect
426  * @param prev A pointer on the previous node
427  * @param node A pointer on the node to insert
428  */
429 static inline void sys_sflist_insert(sys_sflist_t *list,
430 				     sys_sfnode_t *prev,
431 				     sys_sfnode_t *node);
432 
433 Z_GENLIST_INSERT(sflist, sfnode)
434 
435 /**
436  * @brief Fetch and remove the first node of the given list
437  *
438  * List must be known to be non-empty.
439  * This and other sys_sflist_*() functions are not thread safe.
440  *
441  * @param list A pointer on the list to affect
442  *
443  * @return A pointer to the first node of the list
444  */
445 static inline sys_sfnode_t *sys_sflist_get_not_empty(sys_sflist_t *list);
446 
447 Z_GENLIST_GET_NOT_EMPTY(sflist, sfnode)
448 
449 /**
450  * @brief Fetch and remove the first node of the given list
451  *
452  * This and other sys_sflist_*() functions are not thread safe.
453  *
454  * @param list A pointer on the list to affect
455  *
456  * @return A pointer to the first node of the list (or NULL if empty)
457  */
458 static inline sys_sfnode_t *sys_sflist_get(sys_sflist_t *list);
459 
460 Z_GENLIST_GET(sflist, sfnode)
461 
462 /**
463  * @brief Remove a node
464  *
465  * This and other sys_sflist_*() functions are not thread safe.
466  *
467  * @param list A pointer on the list to affect
468  * @param prev_node A pointer on the previous node
469  *        (can be NULL, which means the node is the list's head)
470  * @param node A pointer on the node to remove
471  */
472 static inline void sys_sflist_remove(sys_sflist_t *list,
473 				     sys_sfnode_t *prev_node,
474 				     sys_sfnode_t *node);
475 
476 Z_GENLIST_REMOVE(sflist, sfnode)
477 
478 /**
479  * @brief Find and remove a node from a list
480  *
481  * This and other sys_sflist_*() functions are not thread safe.
482  *
483  * @param list A pointer on the list to affect
484  * @param node A pointer on the node to remove from the list
485  *
486  * @return true if node was removed
487  */
488 static inline bool sys_sflist_find_and_remove(sys_sflist_t *list,
489 					      sys_sfnode_t *node);
490 
491 Z_GENLIST_FIND_AND_REMOVE(sflist, sfnode)
492 
493 /**
494  * @brief Compute the size of the given list in O(n) time
495  *
496  * @param list A pointer on the list
497  *
498  * @return an integer equal to the size of the list, or 0 if empty
499  */
500 static inline size_t sys_sflist_len(sys_sflist_t *list);
501 
502 Z_GENLIST_LEN(sflist, sfnode)
503 
504 /** @} */
505 
506 #ifdef __cplusplus
507 }
508 #endif
509 
510 #endif /* ZEPHYR_INCLUDE_SYS_SFLIST_H_ */
511