Branch data 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 : 15393 : static int bf_list_node_new(bf_list_node **node, void *data)
22 : : {
23 : : bf_list_node *_node;
24 : :
25 : : assert(node);
26 : :
27 : 15393 : _node = calloc(1, sizeof(*_node));
28 [ + - ]: 15393 : if (!_node)
29 : : return -ENOMEM;
30 : :
31 : 15393 : _node->data = data;
32 : 15393 : *node = _node;
33 : :
34 : 15393 : 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 : 15391 : static void bf_list_node_free(bf_list_node **node,
45 : : void (*free_data)(void **data))
46 : : {
47 : : assert(node);
48 : :
49 [ + + ]: 15391 : if (free_data)
50 : 15360 : free_data(&(*node)->data);
51 : : freep((void *)node);
52 : 15391 : }
53 : :
54 : 1259 : int bf_list_new(bf_list **list, const bf_list_ops *ops)
55 : : {
56 : 1259 : _free_bf_list_ bf_list *_list = NULL;
57 : :
58 : : assert(list);
59 : :
60 : 1259 : _list = calloc(1, sizeof(*_list));
61 [ + - ]: 1259 : if (!_list)
62 : : return -ENOMEM;
63 : :
64 : 1259 : bf_list_init(_list, ops);
65 : :
66 : 1259 : *list = TAKE_PTR(_list);
67 : :
68 : 1259 : return 0;
69 : : }
70 : :
71 : 3823 : void bf_list_free(bf_list **list)
72 : : {
73 : : assert(list);
74 : :
75 [ + + ]: 3823 : if (!*list)
76 : : return;
77 : :
78 : 1259 : bf_list_clean(*list);
79 : 1259 : free(*list);
80 : 1259 : *list = NULL;
81 : : }
82 : :
83 : 1668 : void bf_list_init(bf_list *list, const bf_list_ops *ops)
84 : : {
85 : : assert(list);
86 : :
87 : 1668 : list->len = 0;
88 : 1668 : list->head = NULL;
89 : 1668 : list->tail = NULL;
90 : :
91 [ + + ]: 1668 : if (ops)
92 : 1666 : list->ops = *ops;
93 : : else
94 : 2 : list->ops = bf_list_ops_default(NULL, NULL);
95 : 1668 : }
96 : :
97 : 10503 : void bf_list_clean(bf_list *list)
98 : : {
99 : : assert(list);
100 : :
101 [ + + + + : 41664 : bf_list_foreach (list, node)
+ + ]
102 : 10329 : bf_list_node_free(&node, list->ops.free);
103 : :
104 : 10503 : list->len = 0;
105 : 10503 : list->head = NULL;
106 : 10503 : list->tail = NULL;
107 : 10503 : }
108 : :
109 : 3100 : int bf_list_pack(const bf_list *list, bf_wpack_t *pack)
110 : : {
111 : : assert(list);
112 : : assert(pack);
113 : :
114 [ + - ]: 3100 : if (!list->ops.pack)
115 : : return -ENOTSUP;
116 : :
117 [ + + + + : 32014 : bf_list_foreach (list, node) {
+ + ]
118 [ + + ]: 12907 : if (!bf_list_node_get_data(node)) {
119 : 8 : bf_wpack_nil(pack);
120 : 8 : continue;
121 : : }
122 : :
123 [ + + ]: 12899 : if (list->ops.pack == (bf_list_ops_pack)bf_list_pack) {
124 : : // Handle nested lists
125 : 5 : bf_wpack_list(pack, bf_list_node_get_data(node));
126 : : } else {
127 : 12894 : bf_wpack_open_object(pack, NULL);
128 : 12894 : list->ops.pack(bf_list_node_get_data(node), pack);
129 : 12894 : bf_wpack_close_object(pack);
130 : : }
131 : : }
132 : :
133 [ - + ]: 3100 : return bf_wpack_is_valid(pack) ? 0 : -EINVAL;
134 : : }
135 : :
136 : 206 : int bf_list_push(bf_list *list, void **data)
137 : : {
138 : : int r;
139 : :
140 : : assert(list);
141 : : assert(data);
142 : :
143 : 206 : r = bf_list_add_tail(list, *data);
144 [ + - ]: 206 : if (r < 0)
145 : : return r;
146 : :
147 : 206 : TAKE_PTR(*data);
148 : :
149 : 206 : return 0;
150 : : }
151 : :
152 : 80 : int bf_list_add_head(bf_list *list, void *data)
153 : : {
154 : 80 : bf_list_node *node = NULL;
155 : : int r;
156 : :
157 : : assert(list);
158 : :
159 : 80 : r = bf_list_node_new(&node, data);
160 [ + - ]: 80 : if (r < 0)
161 : : return r;
162 : :
163 : 80 : node->next = list->head;
164 [ + + ]: 80 : if (list->head)
165 : 72 : list->head->prev = node;
166 : :
167 : 80 : list->head = node;
168 : :
169 [ + + ]: 80 : if (!list->tail)
170 : 8 : list->tail = node;
171 : :
172 : 80 : ++list->len;
173 : :
174 : 80 : return 0;
175 : : }
176 : :
177 : 15313 : int bf_list_add_tail(bf_list *list, void *data)
178 : : {
179 : 15313 : bf_list_node *node = NULL;
180 : : int r;
181 : :
182 : : assert(list);
183 : :
184 : 15313 : r = bf_list_node_new(&node, data);
185 [ + - ]: 15313 : if (r < 0)
186 : : return r;
187 : :
188 : 15313 : node->prev = list->tail;
189 [ + + ]: 15313 : if (list->tail)
190 : 10596 : list->tail->next = node;
191 : :
192 : 15313 : list->tail = node;
193 : :
194 [ + + ]: 15313 : if (!list->head)
195 : 4717 : list->head = node;
196 : :
197 : 15313 : ++list->len;
198 : :
199 : 15313 : return 0;
200 : : }
201 : :
202 : 5062 : void bf_list_delete(bf_list *list, bf_list_node *node)
203 : : {
204 : : assert(list);
205 : : assert(node);
206 : :
207 [ + + ]: 5062 : if (list->head == node)
208 : 568 : list->head = node->next;
209 [ + + ]: 5062 : if (list->tail == node)
210 : 189 : list->tail = node->prev;
211 : :
212 [ + + ]: 5062 : if (node->prev)
213 : 4494 : node->prev->next = node->next;
214 [ + + ]: 5062 : if (node->next)
215 : 4873 : node->next->prev = node->prev;
216 : :
217 : 5062 : bf_list_node_free(&node, list->ops.free);
218 : :
219 : 5062 : --list->len;
220 : 5062 : }
221 : :
222 : 504 : void *bf_list_get_at(const bf_list *list, size_t index)
223 : : {
224 : : assert(list);
225 : :
226 [ + - + + ]: 3595 : bf_list_foreach (list, node) {
227 [ + + ]: 1797 : if (index == 0)
228 : 503 : return node->data;
229 [ + + ]: 1294 : --index;
230 : : }
231 : :
232 : : return NULL;
233 : : }
|