LCOV - code coverage report
Current view: top level - core - list.h (source / functions) Coverage Total Hit
Test: lcov.out Lines: 100.0 % 30 30
Test Date: 2025-05-09 22:39:08 Functions: 100.0 % 9 9

            Line data    Source code
       1              : /* SPDX-License-Identifier: GPL-2.0-only */
       2              : /*
       3              :  * Copyright (c) 2022 Meta Platforms, Inc. and affiliates.
       4              :  */
       5              : 
       6              : #pragma once
       7              : 
       8              : #include <stdbool.h>
       9              : #include <stddef.h>
      10              : 
      11              : #include "core/helper.h"
      12              : 
      13              : struct bf_marsh;
      14              : 
      15              : /* This has to be defined here, otherwise struct bf_list_node definition is
      16              :  * self-referencing... */
      17              : typedef struct bf_list_node bf_list_node;
      18              : 
      19              : typedef void (*bf_list_ops_free)(void **data);
      20              : typedef int (*bf_list_ops_marsh)(const void *data, struct bf_marsh **marsh);
      21              : 
      22              : /**
      23              :  * @struct bf_list_ops
      24              :  * Operation to manipulate @ref bf_list data.
      25              :  *
      26              :  * @var bf_list_ops::free
      27              :  *  Free the data stored in a node. Should be able to handle NULL data.
      28              :  */
      29              : typedef struct
      30              : {
      31              :     /** Callback to free a node's data. If NULL, the data won't be freed. */
      32              :     bf_list_ops_free free;
      33              : 
      34              :     /** Callback to serialize the data from a node. If NULL, the data won't be
      35              :      * serialized. */
      36              :     bf_list_ops_marsh marsh;
      37              : } bf_list_ops;
      38              : 
      39              : /**
      40              :  * @struct bf_list_node
      41              :  * Node composing a @ref bf_list.
      42              :  *
      43              :  * @warning From the user's perspective, the inside of this structure should
      44              :  * not be directly accessed. Directly modifying any of the fields should be
      45              :  * considered undefined behavior.
      46              :  *
      47              :  * @var bf_list_node::data
      48              :  *      The node's data.
      49              :  * @var bf_list_node::prev
      50              :  *      Pointer to the previous node. Can be NULL if node is first.
      51              :  * @var bf_list_node::next
      52              :  *      Pointer to the next node. Can be NULL if node is last.
      53              :  */
      54              : struct bf_list_node
      55              : {
      56              :     void *data;
      57              :     bf_list_node *prev;
      58              :     bf_list_node *next;
      59              : };
      60              : 
      61              : /**
      62              :  * @struct bf_list
      63              :  * Base structure for the doubly-linked-list data structure.
      64              :  *
      65              :  * @warning From the user's perspective, the inside of this structure should
      66              :  * not be directly accessed. Directly modifying any of the fields should be
      67              :  * considered undefined behavior.
      68              :  *
      69              :  * @var bf_list::len
      70              :  *      Number of elements in the list.
      71              :  * @var bf_list::head
      72              :  *      First element of the list, NULL if the list is empty.
      73              :  * @var bf_list::tail
      74              :  *      Last element of the list, NULL if the list is empty.
      75              :  */
      76              : typedef struct
      77              : {
      78              :     size_t len;
      79              :     bf_list_node *head;
      80              :     bf_list_node *tail;
      81              :     bf_list_ops ops;
      82              : } bf_list;
      83              : 
      84              : #define _cleanup_bf_list_ __attribute__((cleanup(bf_list_free)))
      85              : #define _clean_bf_list_ __attribute__((cleanup(bf_list_clean)))
      86              : 
      87              : /**
      88              :  * Iterate over a @ref bf_list.
      89              :  *
      90              :  * Use a temporary variable to store the next node (if any). Hence, a node
      91              :  * can be removed from the list during iteration.
      92              :  *
      93              :  * @param list Pointer to the list to iterate over. Must be non-NULL.
      94              :  * @param node Name of the variable containing the current node. This variable
      95              :  *        will be created automatically and the caller will be able to use it to
      96              :  *            access the node.
      97              :  */
      98              : #define bf_list_foreach(list, node)                                            \
      99              :     for (bf_list_node * (node) = (list)->head,                                 \
     100              :                         *__next = (list)->head ? (list)->head->next : NULL;    \
     101              :          (node); (node) = __next, __next = __next ? __next->next : NULL)
     102              : 
     103              : /**
     104              :  * Reverse iterate over a @ref bf_list.
     105              :  *
     106              :  * Use a temporary variable to store the next node (if any). Hence, a node
     107              :  * can be removed from the list during iteration.
     108              :  *
     109              :  * @param list Pointer to the list to iterate over. Must be non-NULL.
     110              :  * @param node Name of the variable containing the current node. This variable
     111              :  *            will be created automatically and the caller will be able to use it to
     112              :  *            access the node.
     113              :  */
     114              : #define bf_list_foreach_rev(list, node)                                        \
     115              :     for (bf_list_node * (node) = (list)->tail,                                 \
     116              :                         *__next = (list)->tail ? (list)->tail->prev : NULL;    \
     117              :          (node); (node) = __next, __next = __next ? __next->prev : NULL)
     118              : 
     119              : /**
     120              :  * Returns an initialised @ref bf_list_ops structure.
     121              :  *
     122              :  * @param free_cb Callback to free the data contained in a node. If NULL, a
     123              :  *        node's data won't be freed when the list is destroyed.
     124              :  * @param marsh_cb Callback to marsh the data contained in a node. If NULL, a
     125              :  *        node's data won't be marshed when the list is marshed.
     126              :  * @return An initialised @ref bf_list_ops .
     127              :  */
     128              : #define bf_list_ops_default(free_cb, marsh_cb)                                 \
     129              :     ((bf_list_ops) {.free = (bf_list_ops_free)(free_cb),                       \
     130              :                     .marsh = (bf_list_ops_marsh)(marsh_cb)})
     131              : 
     132              : /**
     133              :  * Returns an initialised @ref bf_list .
     134              :  *
     135              :  * @param free_cb Callback to free the data contained in a node. If NULL, a
     136              :  *        node's data won't be freed when the list is destroyed.
     137              :  * @param marsh_cb Callback to marsh the data contained in a node. If NULL, a
     138              :  *        node's data won't be marshed when the list is marshed.
     139              :  * @return An initialised @ref bf_list .
     140              :  */
     141              : #define bf_list_default(free_cb, marsh_cb)                                     \
     142              :     ((bf_list) {.ops = bf_list_ops_default(free_cb, marsh_cb)})
     143              : 
     144              : /**
     145              :  * Returns an initialized `bf_list` from an existing list.
     146              :  *
     147              :  * The returned list will be initialized with the callbacks defined in `list`.
     148              :  *
     149              :  * @param list Source list to initialize from.
     150              :  * @return An initialised `bf_list`.
     151              :  */
     152              : #define bf_list_default_from(list)                                             \
     153              :     ((bf_list) {.ops = bf_list_ops_default((list).ops.free, (list).ops.marsh)})
     154              : 
     155              : /**
     156              :  * Move a list.
     157              :  *
     158              :  * Move a list from `list` and return it. Once moved, the original list can
     159              :  * either be reused, discarded, or `bf_list_clean` can be called on it safely.
     160              :  * The list it has been moved to will be overriden and `bf_list_clean` should be
     161              :  * called on it.
     162              :  *
     163              :  * @param list List to move.
     164              :  * @return The moved list.
     165              :  */
     166              : #define bf_list_move(list)                                                     \
     167              :     ({                                                                         \
     168              :         bf_list *__list = &(list);                                             \
     169              :         bf_list _list = *__list;                                               \
     170              :         *__list = bf_list_default(__list->ops.free, __list->ops.marsh);        \
     171              :         _list;                                                                 \
     172              :     })
     173              : 
     174              : /**
     175              :  * Allocate and initialise a new list.
     176              :  *
     177              :  * @param list Pointer to the list to initialise. Must be non-NULL.
     178              :  * @param ops Operations to use to manipulate the list's data. If NULL, the
     179              :  *        list's ops are initialised to NULL: the node's data won't be free nor
     180              :  *        marshed.
     181              :  * @return 0 on success or negative errno code on failure.
     182              :  */
     183              : int bf_list_new(bf_list **list, const bf_list_ops *ops);
     184              : 
     185              : /**
     186              :  * Free a list.
     187              :  *
     188              :  * @param list Pointer to the list to free. Must be non-NULL.
     189              :  */
     190              : void bf_list_free(bf_list **list);
     191              : 
     192              : /**
     193              :  * Initialize an allocated list.
     194              :  *
     195              :  * @param list List to initialise. Must be non-NULL.
     196              :  * @param ops Operations to use to manipulate the list's data. If NULL, the
     197              :  *        list's ops are initialised to NULL: the node's data won't be free nor
     198              :  *        marshed.
     199              :  */
     200              : void bf_list_init(bf_list *list, const bf_list_ops *ops);
     201              : 
     202              : /**
     203              :  * Clean up a list.
     204              :  *
     205              :  * Every node in the list is freed. The node's data is freed using the function
     206              :  * provided during initialisation (through @ref bf_list_ops).
     207              :  *
     208              :  * @param list Pointer to the initialised list to clean. Must be non-NULL.
     209              :  */
     210              : void bf_list_clean(bf_list *list);
     211              : 
     212              : /**
     213              :  * Serialize a list.
     214              :  *
     215              :  * Allocate @c marsh and call @c list.ops.marsh for every node in the list. The
     216              :  * serialized node data is added to @c marsh .
     217              :  *
     218              :  * @c list.ops.marsh must be a pointer to a valid serializing function.
     219              :  *
     220              :  * @param list List to serialize. Can't be NULL.
     221              :  * @param marsh Serialized object. On success, @c *marsh points to the
     222              :  *        serialized list. On error, @c marsh is unchanged. Can't be NULL.
     223              :  * @return 0 on success, or a negative errno value on error.
     224              :  */
     225              : int bf_list_marsh(const bf_list *list, struct bf_marsh **marsh);
     226              : 
     227              : /**
     228              :  * Get the number of nodes in the list.
     229              :  *
     230              :  * @param list Initialised list. Must be non-NULL.
     231              :  * @return Number of nodes in the list.
     232              :  */
     233           52 : static inline size_t bf_list_size(const bf_list *list)
     234              : {
     235           56 :     bf_assert(list);
     236           38 :     return list->len;
     237              : }
     238              : 
     239              : /**
     240              :  * Check if a list is empty.
     241              :  *
     242              :  * @param list Initialised list. Must be non-NULL.
     243              :  * @return True if the list is empty, false otherwise.
     244              :  */
     245           11 : static inline bool bf_list_is_empty(const bf_list *list)
     246              : {
     247           11 :     bf_assert(list);
     248              : 
     249           11 :     return list->len == 0;
     250              : }
     251              : 
     252              : /**
     253              :  * Check if @p node is the head of @p list.
     254              :  *
     255              :  * @param list List. Must be non NULL.
     256              :  * @param node Node. Must be non NULL.
     257              :  * @return True if @p node is the head of @p list, false otherwise.
     258              :  */
     259              : static inline bool bf_list_is_head(const bf_list *list,
     260              :                                    const bf_list_node *node)
     261              : {
     262              :     bf_assert(list);
     263              :     bf_assert(node);
     264              : 
     265              :     return node == list->head;
     266              : }
     267              : 
     268              : /**
     269              :  * Check if @p node is the tail of @p list.
     270              :  *
     271              :  * @param list List. Must be non NULL.
     272              :  * @param node Node. Must be non NULL.
     273              :  * @return True if @p node is the tail of @p list, false otherwise.
     274              :  */
     275            4 : static inline bool bf_list_is_tail(const bf_list *list,
     276              :                                    const bf_list_node *node)
     277              : {
     278            4 :     bf_assert(list);
     279            3 :     bf_assert(node);
     280              : 
     281            2 :     return node == list->tail;
     282              : }
     283              : 
     284              : /**
     285              :  * Add data at the beginning of the list.
     286              :  *
     287              :  * @param list List to append data to. Must be initialised and non-NULL.
     288              :  * @param data Data to append to the list. Can be NULL. @p list takes
     289              :  *            ownership of the data: it should not be freed.
     290              :  * @return 0 on success or negative errno code on failure.
     291              :  */
     292              : int bf_list_add_head(bf_list *list, void *data);
     293              : 
     294              : /**
     295              :  * Add data at the end of the list.
     296              :  *
     297              :  * @param list List to append data to. Must be initialised and non-NULL.
     298              :  * @param data Data to append to the list. Can be NULL. @p list takes
     299              :  *            ownership of the data: it should not be freed.
     300              :  * @return 0 on success or negative errno code on failure.
     301              :  */
     302              : int bf_list_add_tail(bf_list *list, void *data);
     303              : 
     304              : /**
     305              :  * Delete @p node from @p list.
     306              :  *
     307              :  * @p node is freed and shouldn't be used once the function returns. The node's
     308              :  * data will be freed using the function provided during initialisation (through
     309              :  * @ref bf_list_ops).
     310              :  *
     311              :  * @param list List to remove node from. Must be non-NULL.
     312              :  * @param node Node to remove from the list. Must be non-NULL.
     313              :  */
     314              : void bf_list_delete(bf_list *list, bf_list_node *node);
     315              : 
     316              : /**
     317              :  * Get the data of a node based on the node's index.
     318              :  *
     319              :  * @param list List to get the data from. Can't be NULL.
     320              :  * @param index Index of the node to get the data from. Index 0 would be the
     321              :  *              first node. If the node doesn't exist, NULL is returned.
     322              :  * @return Data containing in the node at index @c index , or NULL if the
     323              :  *         node doesn't exist.
     324              :  */
     325              : void *bf_list_get_at(const bf_list *list, size_t index);
     326              : 
     327              : /**
     328              :  * Returns the first element of the list.
     329              :  *
     330              :  * A @p bf_list_node object it returned. Use @ref bf_list_node_get_data to
     331              :  * get a pointer to the data.
     332              :  *
     333              :  * @param list Initialised list. Must be non-NULL.
     334              :  * @return Pointer to the first node of the list, or NULL if empty.
     335              :  */
     336            7 : static inline bf_list_node *bf_list_get_head(const bf_list *list)
     337              : {
     338           10 :     bf_assert(list);
     339            3 :     return list->head;
     340              : }
     341              : 
     342              : /**
     343              :  * Returns the last element of the list.
     344              :  *
     345              :  * A @p bf_list_node object it returned. Use @ref bf_list_node_get_data to
     346              :  * get a pointer to the data.
     347              :  *
     348              :  * @param list Initialised list. Must be non-NULL.
     349              :  * @return Pointer to the last node of the list, or NULL if empty.
     350              :  */
     351           12 : static inline bf_list_node *bf_list_get_tail(const bf_list *list)
     352              : {
     353           13 :     bf_assert(list);
     354            6 :     return list->tail;
     355              : }
     356              : 
     357              : /**
     358              :  * Get next node.
     359              :  *
     360              :  * @param node Current node. Must be non-NULL.
     361              :  * @return Pointer to the next node, or NULL if end of list.
     362              :  */
     363            3 : static inline bf_list_node *bf_list_node_next(const bf_list_node *node)
     364              : {
     365            3 :     bf_assert(node);
     366            2 :     return node->next;
     367              : }
     368              : 
     369              : /**
     370              :  * Get previous node.
     371              :  *
     372              :  * @param node Current node. Must be non-NULL.
     373              :  * @return Pointer to the previous node, or NULL if end of list.
     374              :  */
     375            3 : static inline bf_list_node *bf_list_node_prev(const bf_list_node *node)
     376              : {
     377            3 :     bf_assert(node);
     378            2 :     return node->prev;
     379              : }
     380              : 
     381              : /**
     382              :  * Get the node's data.
     383              :  *
     384              :  * Note that the pointer returned can be NULL, as nothing prevents NULL data
     385              :  * to be stored in the node.
     386              :  * The pointer returned is owned by the node and should not be freed.
     387              :  *
     388              :  * @param node Current node. Must be non-NULL.
     389              :  * @return Pointer to the data stored in the iterator.
     390              :  */
     391          159 : static inline void *bf_list_node_get_data(const bf_list_node *node)
     392              : {
     393          159 :     bf_assert(node);
     394          158 :     return node->data;
     395              : }
     396              : 
     397              : /**
     398              :  * Get the node's data and remove it from the node.
     399              :  *
     400              :  * Once the function returns, the node's data is set to NULL. The pointer
     401              :  * returned is then owned by the caller.
     402              :  *
     403              :  * @param node Current node. Must be non-NULL.
     404              :  * @return Pointer to the data stored in the node.
     405              :  */
     406            5 : static inline void *bf_list_node_take_data(bf_list_node *node)
     407              : {
     408              :     void *data;
     409              : 
     410            5 :     bf_assert(node);
     411              : 
     412            5 :     data = node->data;
     413            5 :     node->data = NULL;
     414              : 
     415            5 :     return data;
     416              : }
        

Generated by: LCOV version 2.0-1