LCOV - code coverage report
Current view: top level - libbpfilter - list.c (source / functions) Coverage Total Hit
Test: lcov.out Lines: 96.3 % 109 105
Test Date: 2025-10-28 16:24:15 Functions: 100.0 % 12 12

            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              : #include "bpfilter/list.h"
       7              : 
       8              : #include <errno.h>
       9              : #include <stdlib.h>
      10              : 
      11              : #include "bpfilter/helper.h"
      12              : 
      13              : /**
      14              :  * Create a new list node, with the given data.
      15              :  *
      16              :  * @param node New node pointer. Must be non-NULL.. If the function fails, this
      17              :  *            parameter remains unchanged.
      18              :  * @param data Data to store in the new node. Can be NULL.
      19              :  * @return 0 on success or negative errno code on failure.
      20              :  */
      21          309 : static int bf_list_node_new(bf_list_node **node, void *data)
      22              : {
      23              :     bf_list_node *_node;
      24              : 
      25          309 :     bf_assert(node);
      26              : 
      27          309 :     _node = calloc(1, sizeof(*_node));
      28          309 :     if (!_node)
      29              :         return -ENOMEM;
      30              : 
      31          309 :     _node->data = data;
      32          309 :     *node = _node;
      33              : 
      34          309 :     return 0;
      35              : }
      36              : 
      37              : /**
      38              :  * Free a list node.
      39              :  *
      40              :  * @param node Node to free. Can't be NULL.
      41              :  * @param free_data Callback to use to free the data. If NULL, the data is not
      42              :  *        freed.
      43              :  */
      44          309 : static void bf_list_node_free(bf_list_node **node,
      45              :                               void (*free_data)(void **data))
      46              : {
      47          309 :     bf_assert(node);
      48              : 
      49          309 :     if (free_data)
      50          298 :         free_data(&(*node)->data);
      51              :     freep((void *)node);
      52          309 : }
      53              : 
      54           10 : int bf_list_new(bf_list **list, const bf_list_ops *ops)
      55              : {
      56            9 :     _free_bf_list_ bf_list *_list = NULL;
      57              : 
      58           10 :     bf_assert(list);
      59              : 
      60            9 :     _list = calloc(1, sizeof(*_list));
      61            9 :     if (!_list)
      62              :         return -ENOMEM;
      63              : 
      64            9 :     bf_list_init(_list, ops);
      65              : 
      66            9 :     *list = TAKE_PTR(_list);
      67              : 
      68            9 :     return 0;
      69              : }
      70              : 
      71           21 : void bf_list_free(bf_list **list)
      72              : {
      73           21 :     bf_assert(list);
      74              : 
      75           20 :     if (!*list)
      76              :         return;
      77              : 
      78            9 :     bf_list_clean(*list);
      79            9 :     free(*list);
      80            9 :     *list = NULL;
      81              : }
      82              : 
      83           51 : void bf_list_init(bf_list *list, const bf_list_ops *ops)
      84              : {
      85           51 :     bf_assert(list);
      86              : 
      87           50 :     list->len = 0;
      88           50 :     list->head = NULL;
      89           50 :     list->tail = NULL;
      90              : 
      91           50 :     if (ops)
      92           43 :         list->ops = *ops;
      93              :     else
      94            7 :         list->ops = bf_list_ops_default(NULL, NULL);
      95           50 : }
      96              : 
      97          149 : void bf_list_clean(bf_list *list)
      98              : {
      99          149 :     bf_assert(list);
     100              : 
     101          894 :     bf_list_foreach (list, node)
     102          299 :         bf_list_node_free(&node, list->ops.free);
     103              : 
     104          148 :     list->len = 0;
     105          148 :     list->head = NULL;
     106          148 :     list->tail = NULL;
     107          148 : }
     108              : 
     109           13 : int bf_list_pack(const bf_list *list, bf_wpack_t *pack)
     110              : {
     111           13 :     bf_assert(list);
     112           12 :     bf_assert(pack);
     113              : 
     114           11 :     if (!list->ops.pack)
     115              :         return -ENOTSUP;
     116              : 
     117          110 :     bf_list_foreach (list, node) {
     118           44 :         if (!bf_list_node_get_data(node)) {
     119            0 :             bf_wpack_nil(pack);
     120            0 :             continue;
     121              :         }
     122              : 
     123           44 :         if (list->ops.pack == (bf_list_ops_pack)bf_list_pack) {
     124              :             // Handle nested lists
     125            0 :             bf_wpack_list(pack, bf_list_node_get_data(node));
     126              :         } else {
     127           44 :             bf_wpack_open_object(pack, NULL);
     128           44 :             list->ops.pack(bf_list_node_get_data(node), pack);
     129           44 :             bf_wpack_close_object(pack);
     130              :         }
     131              :     }
     132              : 
     133           11 :     return bf_wpack_is_valid(pack) ? 0 : -EINVAL;
     134              : }
     135              : 
     136            5 : int bf_list_push(bf_list *list, void **data)
     137              : {
     138              :     int r;
     139              : 
     140            5 :     bf_assert(data);
     141              : 
     142            3 :     r = bf_list_add_tail(list, *data);
     143            2 :     if (r < 0)
     144              :         return r;
     145              : 
     146            2 :     TAKE_PTR(*data);
     147              : 
     148            2 :     return 0;
     149              : }
     150              : 
     151           49 : int bf_list_add_head(bf_list *list, void *data)
     152              : {
     153           49 :     bf_list_node *node = NULL;
     154              :     int r;
     155              : 
     156           49 :     bf_assert(list);
     157              : 
     158           48 :     r = bf_list_node_new(&node, data);
     159           48 :     if (r < 0)
     160              :         return r;
     161              : 
     162           48 :     node->next = list->head;
     163           48 :     if (list->head)
     164           38 :         list->head->prev = node;
     165              : 
     166           48 :     list->head = node;
     167              : 
     168           48 :     if (!list->tail)
     169           10 :         list->tail = node;
     170              : 
     171           48 :     ++list->len;
     172              : 
     173           48 :     return 0;
     174              : }
     175              : 
     176          263 : int bf_list_add_tail(bf_list *list, void *data)
     177              : {
     178          263 :     bf_list_node *node = NULL;
     179              :     int r;
     180              : 
     181          263 :     bf_assert(list);
     182              : 
     183          261 :     r = bf_list_node_new(&node, data);
     184          261 :     if (r < 0)
     185              :         return r;
     186              : 
     187          261 :     node->prev = list->tail;
     188          261 :     if (list->tail)
     189          196 :         list->tail->next = node;
     190              : 
     191          261 :     list->tail = node;
     192              : 
     193          261 :     if (!list->head)
     194           65 :         list->head = node;
     195              : 
     196          261 :     ++list->len;
     197              : 
     198          261 :     return 0;
     199              : }
     200              : 
     201           10 : void bf_list_delete(bf_list *list, bf_list_node *node)
     202              : {
     203           10 :     bf_assert(list);
     204           10 :     bf_assert(node);
     205              : 
     206           10 :     if (list->head == node)
     207           10 :         list->head = node->next;
     208           10 :     if (list->tail == node)
     209            1 :         list->tail = node->prev;
     210              : 
     211           10 :     if (node->prev)
     212            0 :         node->prev->next = node->next;
     213           10 :     if (node->next)
     214            9 :         node->next->prev = node->prev;
     215              : 
     216           10 :     bf_list_node_free(&node, list->ops.free);
     217              : 
     218           10 :     --list->len;
     219           10 : }
     220              : 
     221           11 : void *bf_list_get_at(const bf_list *list, size_t index)
     222              : {
     223           11 :     bf_assert(list);
     224              : 
     225           77 :     bf_list_foreach (list, node) {
     226           38 :         if (index == 0)
     227            9 :             return node->data;
     228           29 :         --index;
     229              :     }
     230              : 
     231              :     return NULL;
     232              : }
        

Generated by: LCOV version 2.0-1