LCOV - code coverage report
Current view: top level - libbpfilter - list.c (source / functions) Coverage Total Hit
Test: lcov.out Lines: 96.1 % 103 99
Test Date: 2025-09-16 14:46:44 Functions: 100.0 % 11 11

            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          306 : static int bf_list_node_new(bf_list_node **node, void *data)
      22              : {
      23              :     bf_list_node *_node;
      24              : 
      25          306 :     bf_assert(node);
      26              : 
      27          306 :     _node = calloc(1, sizeof(*_node));
      28          306 :     if (!_node)
      29              :         return -ENOMEM;
      30              : 
      31          306 :     _node->data = data;
      32          306 :     *node = _node;
      33              : 
      34          306 :     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          306 : static void bf_list_node_free(bf_list_node **node,
      45              :                               void (*free_data)(void **data))
      46              : {
      47          306 :     bf_assert(node);
      48              : 
      49          306 :     if (free_data)
      50          295 :         free_data(&(*node)->data);
      51              :     freep((void *)node);
      52          306 : }
      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           50 : void bf_list_init(bf_list *list, const bf_list_ops *ops)
      84              : {
      85           50 :     bf_assert(list);
      86              : 
      87           49 :     list->len = 0;
      88           49 :     list->head = NULL;
      89           49 :     list->tail = NULL;
      90              : 
      91           49 :     if (ops)
      92           42 :         list->ops = *ops;
      93              :     else
      94            7 :         list->ops = bf_list_ops_default(NULL, NULL);
      95           49 : }
      96              : 
      97          148 : void bf_list_clean(bf_list *list)
      98              : {
      99          148 :     bf_assert(list);
     100              : 
     101          886 :     bf_list_foreach (list, node)
     102          296 :         bf_list_node_free(&node, list->ops.free);
     103              : 
     104          147 :     list->len = 0;
     105          147 :     list->head = NULL;
     106          147 :     list->tail = NULL;
     107          147 : }
     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           49 : int bf_list_add_head(bf_list *list, void *data)
     137              : {
     138           49 :     bf_list_node *node = NULL;
     139              :     int r;
     140              : 
     141           49 :     bf_assert(list);
     142              : 
     143           48 :     r = bf_list_node_new(&node, data);
     144           48 :     if (r < 0)
     145              :         return r;
     146              : 
     147           48 :     node->next = list->head;
     148           48 :     if (list->head)
     149           38 :         list->head->prev = node;
     150              : 
     151           48 :     list->head = node;
     152              : 
     153           48 :     if (!list->tail)
     154           10 :         list->tail = node;
     155              : 
     156           48 :     ++list->len;
     157              : 
     158           48 :     return 0;
     159              : }
     160              : 
     161          259 : int bf_list_add_tail(bf_list *list, void *data)
     162              : {
     163          259 :     bf_list_node *node = NULL;
     164              :     int r;
     165              : 
     166          259 :     bf_assert(list);
     167              : 
     168          258 :     r = bf_list_node_new(&node, data);
     169          258 :     if (r < 0)
     170              :         return r;
     171              : 
     172          258 :     node->prev = list->tail;
     173          258 :     if (list->tail)
     174          194 :         list->tail->next = node;
     175              : 
     176          258 :     list->tail = node;
     177              : 
     178          258 :     if (!list->head)
     179           64 :         list->head = node;
     180              : 
     181          258 :     ++list->len;
     182              : 
     183          258 :     return 0;
     184              : }
     185              : 
     186           10 : void bf_list_delete(bf_list *list, bf_list_node *node)
     187              : {
     188           10 :     bf_assert(list);
     189           10 :     bf_assert(node);
     190              : 
     191           10 :     if (list->head == node)
     192           10 :         list->head = node->next;
     193           10 :     if (list->tail == node)
     194            1 :         list->tail = node->prev;
     195              : 
     196           10 :     if (node->prev)
     197            0 :         node->prev->next = node->next;
     198           10 :     if (node->next)
     199            9 :         node->next->prev = node->prev;
     200              : 
     201           10 :     bf_list_node_free(&node, list->ops.free);
     202              : 
     203           10 :     --list->len;
     204           10 : }
     205              : 
     206           11 : void *bf_list_get_at(const bf_list *list, size_t index)
     207              : {
     208           11 :     bf_assert(list);
     209              : 
     210           77 :     bf_list_foreach (list, node) {
     211           38 :         if (index == 0)
     212            9 :             return node->data;
     213           29 :         --index;
     214              :     }
     215              : 
     216              :     return NULL;
     217              : }
        

Generated by: LCOV version 2.0-1