You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
486 lines
14 KiB
486 lines
14 KiB
/* |
|
* Copyright (c) 2016 Intel Corporation |
|
* |
|
* SPDX-License-Identifier: Apache-2.0 |
|
*/ |
|
|
|
/** |
|
* @file |
|
* |
|
* @brief Single-linked list implementation |
|
* |
|
* Single-linked list implementation using inline macros/functions. |
|
* This API is not thread safe, and thus if a list is used across threads, |
|
* calls to functions must be protected with synchronization primitives. |
|
*/ |
|
|
|
#ifndef ZEPHYR_INCLUDE_SYS_SFLIST_H_ |
|
#define ZEPHYR_INCLUDE_SYS_SFLIST_H_ |
|
|
|
#include <stddef.h> |
|
#include <stdbool.h> |
|
#include <sys/__assert.h> |
|
#include "list_gen.h" |
|
|
|
#ifdef __cplusplus |
|
extern "C" { |
|
#endif |
|
|
|
#ifdef __LP64__ |
|
typedef uint64_t unative_t; |
|
#else |
|
typedef uint32_t unative_t; |
|
#endif |
|
|
|
struct _sfnode { |
|
unative_t next_and_flags; |
|
}; |
|
|
|
typedef struct _sfnode sys_sfnode_t; |
|
|
|
struct _sflist { |
|
sys_sfnode_t *head; |
|
sys_sfnode_t *tail; |
|
}; |
|
|
|
typedef struct _sflist sys_sflist_t; |
|
|
|
/** |
|
* @defgroup flagged-single-linked-list_apis Flagged Single-linked list |
|
* @ingroup datastructure_apis |
|
* @{ |
|
*/ |
|
|
|
/** |
|
* @brief Provide the primitive to iterate on a list |
|
* Note: the loop is unsafe and thus __sn should not be removed |
|
* |
|
* User _MUST_ add the loop statement curly braces enclosing its own code: |
|
* |
|
* SYS_SFLIST_FOR_EACH_NODE(l, n) { |
|
* <user code> |
|
* } |
|
* |
|
* This and other SYS_SFLIST_*() macros are not thread safe. |
|
* |
|
* @param __sl A pointer on a sys_sflist_t to iterate on |
|
* @param __sn A sys_sfnode_t pointer to peek each node of the list |
|
*/ |
|
#define SYS_SFLIST_FOR_EACH_NODE(__sl, __sn) \ |
|
Z_GENLIST_FOR_EACH_NODE(sflist, __sl, __sn) |
|
|
|
/** |
|
* @brief Provide the primitive to iterate on a list, from a node in the list |
|
* Note: the loop is unsafe and thus __sn should not be removed |
|
* |
|
* User _MUST_ add the loop statement curly braces enclosing its own code: |
|
* |
|
* SYS_SFLIST_ITERATE_FROM_NODE(l, n) { |
|
* <user code> |
|
* } |
|
* |
|
* Like SYS_SFLIST_FOR_EACH_NODE(), but __dn already contains a node in the list |
|
* where to start searching for the next entry from. If NULL, it starts from |
|
* the head. |
|
* |
|
* This and other SYS_SFLIST_*() macros are not thread safe. |
|
* |
|
* @param __sl A pointer on a sys_sflist_t to iterate on |
|
* @param __sn A sys_sfnode_t pointer to peek each node of the list |
|
* it contains the starting node, or NULL to start from the head |
|
*/ |
|
#define SYS_SFLIST_ITERATE_FROM_NODE(__sl, __sn) \ |
|
Z_GENLIST_ITERATE_FROM_NODE(sflist, __sl, __sn) |
|
|
|
/** |
|
* @brief Provide the primitive to safely iterate on a list |
|
* Note: __sn can be removed, it will not break the loop. |
|
* |
|
* User _MUST_ add the loop statement curly braces enclosing its own code: |
|
* |
|
* SYS_SFLIST_FOR_EACH_NODE_SAFE(l, n, s) { |
|
* <user code> |
|
* } |
|
* |
|
* This and other SYS_SFLIST_*() macros are not thread safe. |
|
* |
|
* @param __sl A pointer on a sys_sflist_t to iterate on |
|
* @param __sn A sys_sfnode_t pointer to peek each node of the list |
|
* @param __sns A sys_sfnode_t pointer for the loop to run safely |
|
*/ |
|
#define SYS_SFLIST_FOR_EACH_NODE_SAFE(__sl, __sn, __sns) \ |
|
Z_GENLIST_FOR_EACH_NODE_SAFE(sflist, __sl, __sn, __sns) |
|
|
|
/* |
|
* @brief Provide the primitive to resolve the container of a list node |
|
* Note: it is safe to use with NULL pointer nodes |
|
* |
|
* @param __ln A pointer on a sys_sfnode_t to get its container |
|
* @param __cn Container struct type pointer |
|
* @param __n The field name of sys_sfnode_t within the container struct |
|
*/ |
|
#define SYS_SFLIST_CONTAINER(__ln, __cn, __n) \ |
|
Z_GENLIST_CONTAINER(__ln, __cn, __n) |
|
|
|
/* |
|
* @brief Provide the primitive to peek container of the list head |
|
* |
|
* @param __sl A pointer on a sys_sflist_t to peek |
|
* @param __cn Container struct type pointer |
|
* @param __n The field name of sys_sfnode_t within the container struct |
|
*/ |
|
#define SYS_SFLIST_PEEK_HEAD_CONTAINER(__sl, __cn, __n) \ |
|
Z_GENLIST_PEEK_HEAD_CONTAINER(sflist, __sl, __cn, __n) |
|
|
|
/* |
|
* @brief Provide the primitive to peek container of the list tail |
|
* |
|
* @param __sl A pointer on a sys_sflist_t to peek |
|
* @param __cn Container struct type pointer |
|
* @param __n The field name of sys_sfnode_t within the container struct |
|
*/ |
|
#define SYS_SFLIST_PEEK_TAIL_CONTAINER(__sl, __cn, __n) \ |
|
Z_GENLIST_PEEK_TAIL_CONTAINER(sflist, __sl, __cn, __n) |
|
|
|
/* |
|
* @brief Provide the primitive to peek the next container |
|
* |
|
* @param __cn Container struct type pointer |
|
* @param __n The field name of sys_sfnode_t within the container struct |
|
*/ |
|
#define SYS_SFLIST_PEEK_NEXT_CONTAINER(__cn, __n) \ |
|
Z_GENLIST_PEEK_NEXT_CONTAINER(sflist, __cn, __n) |
|
|
|
/** |
|
* @brief Provide the primitive to iterate on a list under a container |
|
* Note: the loop is unsafe and thus __cn should not be detached |
|
* |
|
* User _MUST_ add the loop statement curly braces enclosing its own code: |
|
* |
|
* SYS_SFLIST_FOR_EACH_CONTAINER(l, c, n) { |
|
* <user code> |
|
* } |
|
* |
|
* @param __sl A pointer on a sys_sflist_t to iterate on |
|
* @param __cn A pointer to peek each entry of the list |
|
* @param __n The field name of sys_sfnode_t within the container struct |
|
*/ |
|
#define SYS_SFLIST_FOR_EACH_CONTAINER(__sl, __cn, __n) \ |
|
Z_GENLIST_FOR_EACH_CONTAINER(sflist, __sl, __cn, __n) |
|
|
|
/** |
|
* @brief Provide the primitive to safely iterate on a list under a container |
|
* Note: __cn can be detached, it will not break the loop. |
|
* |
|
* User _MUST_ add the loop statement curly braces enclosing its own code: |
|
* |
|
* SYS_SFLIST_FOR_EACH_NODE_SAFE(l, c, cn, n) { |
|
* <user code> |
|
* } |
|
* |
|
* @param __sl A pointer on a sys_sflist_t to iterate on |
|
* @param __cn A pointer to peek each entry of the list |
|
* @param __cns A pointer for the loop to run safely |
|
* @param __n The field name of sys_sfnode_t within the container struct |
|
*/ |
|
#define SYS_SFLIST_FOR_EACH_CONTAINER_SAFE(__sl, __cn, __cns, __n) \ |
|
Z_GENLIST_FOR_EACH_CONTAINER_SAFE(sflist, __sl, __cn, __cns, __n) |
|
|
|
|
|
/* |
|
* Required function definitions for the list_gen.h interface |
|
* |
|
* These are the only functions that do not treat the list/node pointers |
|
* as completely opaque types. |
|
*/ |
|
|
|
/** |
|
* @brief Initialize a list |
|
* |
|
* @param list A pointer on the list to initialize |
|
*/ |
|
static inline void sys_sflist_init(sys_sflist_t *list) |
|
{ |
|
list->head = NULL; |
|
list->tail = NULL; |
|
} |
|
|
|
#define SYS_SFLIST_STATIC_INIT(ptr_to_list) {NULL, NULL} |
|
#define SYS_SFLIST_FLAGS_MASK 0x3UL |
|
|
|
static inline sys_sfnode_t *z_sfnode_next_peek(sys_sfnode_t *node) |
|
{ |
|
return (sys_sfnode_t *)(node->next_and_flags & ~SYS_SFLIST_FLAGS_MASK); |
|
} |
|
|
|
static inline uint8_t sys_sfnode_flags_get(sys_sfnode_t *node); |
|
|
|
static inline void z_sfnode_next_set(sys_sfnode_t *parent, |
|
sys_sfnode_t *child) |
|
{ |
|
uint8_t cur_flags = sys_sfnode_flags_get(parent); |
|
|
|
parent->next_and_flags = cur_flags | (unative_t)child; |
|
} |
|
|
|
static inline void z_sflist_head_set(sys_sflist_t *list, sys_sfnode_t *node) |
|
{ |
|
list->head = node; |
|
} |
|
|
|
static inline void z_sflist_tail_set(sys_sflist_t *list, sys_sfnode_t *node) |
|
{ |
|
list->tail = node; |
|
} |
|
|
|
/** |
|
* @brief Peek the first node from the list |
|
* |
|
* @param list A point on the list to peek the first node from |
|
* |
|
* @return A pointer on the first node of the list (or NULL if none) |
|
*/ |
|
static inline sys_sfnode_t *sys_sflist_peek_head(sys_sflist_t *list) |
|
{ |
|
return list->head; |
|
} |
|
|
|
/** |
|
* @brief Peek the last node from the list |
|
* |
|
* @param list A point on the list to peek the last node from |
|
* |
|
* @return A pointer on the last node of the list (or NULL if none) |
|
*/ |
|
static inline sys_sfnode_t *sys_sflist_peek_tail(sys_sflist_t *list) |
|
{ |
|
return list->tail; |
|
} |
|
|
|
/* |
|
* APIs specific to sflist type |
|
*/ |
|
|
|
/** |
|
* @brief Fetch flags value for a particular sfnode |
|
* |
|
* @param node A pointer to the node to fetch flags from |
|
* @return The value of flags, which will be between 0 and 3 |
|
*/ |
|
static inline uint8_t sys_sfnode_flags_get(sys_sfnode_t *node) |
|
{ |
|
return node->next_and_flags & SYS_SFLIST_FLAGS_MASK; |
|
} |
|
|
|
/** |
|
* @brief Initialize an sflist node |
|
* |
|
* Set an initial flags value for this slist node, which can be a value between |
|
* 0 and 3. These flags will persist even if the node is moved around |
|
* within a list, removed, or transplanted to a different slist. |
|
* |
|
* This is ever so slightly faster than sys_sfnode_flags_set() and should |
|
* only be used on a node that hasn't been added to any list. |
|
* |
|
* @param node A pointer to the node to set the flags on |
|
* @param flags A value between 0 and 3 to set the flags value |
|
*/ |
|
static inline void sys_sfnode_init(sys_sfnode_t *node, uint8_t flags) |
|
{ |
|
__ASSERT((flags & ~SYS_SFLIST_FLAGS_MASK) == 0UL, "flags too large"); |
|
node->next_and_flags = flags; |
|
} |
|
|
|
/** |
|
* @brief Set flags value for an sflist node |
|
* |
|
* Set a flags value for this slist node, which can be a value between |
|
* 0 and 3. These flags will persist even if the node is moved around |
|
* within a list, removed, or transplanted to a different slist. |
|
* |
|
* @param node A pointer to the node to set the flags on |
|
* @param flags A value between 0 and 3 to set the flags value |
|
*/ |
|
static inline void sys_sfnode_flags_set(sys_sfnode_t *node, uint8_t flags) |
|
{ |
|
__ASSERT((flags & ~SYS_SFLIST_FLAGS_MASK) == 0UL, "flags too large"); |
|
node->next_and_flags = (unative_t)(z_sfnode_next_peek(node)) | flags; |
|
} |
|
|
|
/* |
|
* Derived, generated APIs |
|
*/ |
|
|
|
/** |
|
* @brief Test if the given list is empty |
|
* |
|
* @param list A pointer on the list to test |
|
* |
|
* @return a boolean, true if it's empty, false otherwise |
|
*/ |
|
static inline bool sys_sflist_is_empty(sys_sflist_t *list); |
|
|
|
Z_GENLIST_IS_EMPTY(sflist) |
|
|
|
/** |
|
* @brief Peek the next node from current node, node is not NULL |
|
* |
|
* Faster then sys_sflist_peek_next() if node is known not to be NULL. |
|
* |
|
* @param node A pointer on the node where to peek the next node |
|
* |
|
* @return a pointer on the next node (or NULL if none) |
|
*/ |
|
static inline sys_sfnode_t *sys_sflist_peek_next_no_check(sys_sfnode_t *node); |
|
|
|
Z_GENLIST_PEEK_NEXT_NO_CHECK(sflist, sfnode) |
|
|
|
/** |
|
* @brief Peek the next node from current node |
|
* |
|
* @param node A pointer on the node where to peek the next node |
|
* |
|
* @return a pointer on the next node (or NULL if none) |
|
*/ |
|
static inline sys_sfnode_t *sys_sflist_peek_next(sys_sfnode_t *node); |
|
|
|
Z_GENLIST_PEEK_NEXT(sflist, sfnode) |
|
|
|
/** |
|
* @brief Prepend a node to the given list |
|
* |
|
* This and other sys_sflist_*() functions are not thread safe. |
|
* |
|
* @param list A pointer on the list to affect |
|
* @param node A pointer on the node to prepend |
|
*/ |
|
static inline void sys_sflist_prepend(sys_sflist_t *list, |
|
sys_sfnode_t *node); |
|
|
|
Z_GENLIST_PREPEND(sflist, sfnode) |
|
|
|
/** |
|
* @brief Append a node to the given list |
|
* |
|
* This and other sys_sflist_*() functions are not thread safe. |
|
* |
|
* @param list A pointer on the list to affect |
|
* @param node A pointer on the node to append |
|
*/ |
|
static inline void sys_sflist_append(sys_sflist_t *list, |
|
sys_sfnode_t *node); |
|
|
|
Z_GENLIST_APPEND(sflist, sfnode) |
|
|
|
/** |
|
* @brief Append a list to the given list |
|
* |
|
* Append a singly-linked, NULL-terminated list consisting of nodes containing |
|
* the pointer to the next node as the first element of a node, to @a list. |
|
* This and other sys_sflist_*() functions are not thread safe. |
|
* |
|
* FIXME: Why are the element parameters void *? |
|
* |
|
* @param list A pointer on the list to affect |
|
* @param head A pointer to the first element of the list to append |
|
* @param tail A pointer to the last element of the list to append |
|
*/ |
|
static inline void sys_sflist_append_list(sys_sflist_t *list, |
|
void *head, void *tail); |
|
|
|
Z_GENLIST_APPEND_LIST(sflist, sfnode) |
|
|
|
/** |
|
* @brief merge two sflists, appending the second one to the first |
|
* |
|
* When the operation is completed, the appending list is empty. |
|
* This and other sys_sflist_*() functions are not thread safe. |
|
* |
|
* @param list A pointer on the list to affect |
|
* @param list_to_append A pointer to the list to append. |
|
*/ |
|
static inline void sys_sflist_merge_sflist(sys_sflist_t *list, |
|
sys_sflist_t *list_to_append); |
|
|
|
Z_GENLIST_MERGE_LIST(sflist, sfnode) |
|
|
|
/** |
|
* @brief Insert a node to the given list |
|
* |
|
* This and other sys_sflist_*() functions are not thread safe. |
|
* |
|
* @param list A pointer on the list to affect |
|
* @param prev A pointer on the previous node |
|
* @param node A pointer on the node to insert |
|
*/ |
|
static inline void sys_sflist_insert(sys_sflist_t *list, |
|
sys_sfnode_t *prev, |
|
sys_sfnode_t *node); |
|
|
|
Z_GENLIST_INSERT(sflist, sfnode) |
|
|
|
/** |
|
* @brief Fetch and remove the first node of the given list |
|
* |
|
* List must be known to be non-empty. |
|
* This and other sys_sflist_*() functions are not thread safe. |
|
* |
|
* @param list A pointer on the list to affect |
|
* |
|
* @return A pointer to the first node of the list |
|
*/ |
|
static inline sys_sfnode_t *sys_sflist_get_not_empty(sys_sflist_t *list); |
|
|
|
Z_GENLIST_GET_NOT_EMPTY(sflist, sfnode) |
|
|
|
/** |
|
* @brief Fetch and remove the first node of the given list |
|
* |
|
* This and other sys_sflist_*() functions are not thread safe. |
|
* |
|
* @param list A pointer on the list to affect |
|
* |
|
* @return A pointer to the first node of the list (or NULL if empty) |
|
*/ |
|
static inline sys_sfnode_t *sys_sflist_get(sys_sflist_t *list); |
|
|
|
Z_GENLIST_GET(sflist, sfnode) |
|
|
|
/** |
|
* @brief Remove a node |
|
* |
|
* This and other sys_sflist_*() functions are not thread safe. |
|
* |
|
* @param list A pointer on the list to affect |
|
* @param prev_node A pointer on the previous node |
|
* (can be NULL, which means the node is the list's head) |
|
* @param node A pointer on the node to remove |
|
*/ |
|
static inline void sys_sflist_remove(sys_sflist_t *list, |
|
sys_sfnode_t *prev_node, |
|
sys_sfnode_t *node); |
|
|
|
Z_GENLIST_REMOVE(sflist, sfnode) |
|
|
|
/** |
|
* @brief Find and remove a node from a list |
|
* |
|
* This and other sys_sflist_*() functions are not thread safe. |
|
* |
|
* @param list A pointer on the list to affect |
|
* @param node A pointer on the node to remove from the list |
|
* |
|
* @return true if node was removed |
|
*/ |
|
static inline bool sys_sflist_find_and_remove(sys_sflist_t *list, |
|
sys_sfnode_t *node); |
|
|
|
Z_GENLIST_FIND_AND_REMOVE(sflist, sfnode) |
|
|
|
/** @} */ |
|
|
|
#ifdef __cplusplus |
|
} |
|
#endif |
|
|
|
#endif /* ZEPHYR_INCLUDE_SYS_SFLIST_H_ */
|
|
|