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