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