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/core/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 : 62592 : static int bf_list_node_new(bf_list_node **node, void *data)
22 : : {
23 : : bf_list_node *_node;
24 : :
25 : : assert(node);
26 : :
27 : 62592 : _node = calloc(1, sizeof(*_node));
28 [ + - ]: 62592 : if (!_node)
29 : : return -ENOMEM;
30 : :
31 : 62592 : _node->data = data;
32 : 62592 : *node = _node;
33 : :
34 : 62592 : 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 : 62592 : static void bf_list_node_free(bf_list_node **node,
45 : : void (*free_data)(void **data))
46 : : {
47 : : assert(node);
48 : :
49 [ + + ]: 62592 : if (free_data)
50 : 62251 : free_data(&(*node)->data);
51 : 62592 : BF_FREEP(node);
52 : 62592 : }
53 : :
54 : 2952 : int bf_list_new(bf_list **list, const bf_list_ops *ops)
55 : : {
56 : 2952 : _free_bf_list_ bf_list *_list = NULL;
57 : :
58 : : assert(list);
59 : :
60 : 2952 : _list = calloc(1, sizeof(*_list));
61 [ + - ]: 2952 : if (!_list)
62 : : return -ENOMEM;
63 : :
64 : 2952 : bf_list_init(_list, ops);
65 : :
66 : 2952 : *list = TAKE_PTR(_list);
67 : :
68 : 2952 : return 0;
69 : : }
70 : :
71 : 8658 : void bf_list_free(bf_list **list)
72 : : {
73 : : assert(list);
74 : :
75 [ + + ]: 8658 : if (!*list)
76 : : return;
77 : :
78 : 2952 : bf_list_clean(*list);
79 : 2952 : free(*list);
80 : 2952 : *list = NULL;
81 : : }
82 : :
83 : 6562 : void bf_list_init(bf_list *list, const bf_list_ops *ops)
84 : : {
85 : : assert(list);
86 : :
87 : 6562 : list->len = 0;
88 : 6562 : list->head = NULL;
89 : 6562 : list->tail = NULL;
90 : :
91 [ + + ]: 6562 : if (ops)
92 : 6560 : list->ops = *ops;
93 : : else
94 : 2 : list->ops = bf_list_ops_default(NULL, NULL);
95 : 6562 : }
96 : :
97 : 68135 : void bf_list_clean(bf_list *list)
98 : : {
99 : : assert(list);
100 : :
101 [ + + + + : 218148 : bf_list_foreach (list, node)
+ + ]
102 : 40939 : bf_list_node_free(&node, list->ops.free);
103 : :
104 : 68135 : list->len = 0;
105 : 68135 : list->head = NULL;
106 : 68135 : list->tail = NULL;
107 : 68135 : }
108 : :
109 : 9795 : int bf_list_pack(const bf_list *list, bf_wpack_t *pack)
110 : : {
111 : : assert(list);
112 : : assert(pack);
113 : :
114 [ + - ]: 9795 : if (!list->ops.pack)
115 : : return -ENOTSUP;
116 : :
117 [ + + + + : 39136 : bf_list_foreach (list, node) {
+ + ]
118 [ - + ]: 9773 : if (!bf_list_node_get_data(node)) {
119 : 0 : bf_wpack_nil(pack);
120 : 0 : continue;
121 : : }
122 : :
123 [ - + ]: 9773 : 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 : 9773 : bf_wpack_open_object(pack, NULL);
128 : 9773 : list->ops.pack(bf_list_node_get_data(node), pack);
129 : 9773 : bf_wpack_close_object(pack);
130 : : }
131 : : }
132 : :
133 [ - + ]: 9795 : return bf_wpack_is_valid(pack) ? 0 : -EINVAL;
134 : : }
135 : :
136 : 1361 : int bf_list_push(bf_list *list, void **data)
137 : : {
138 : : int r;
139 : :
140 : : assert(list);
141 : : assert(data);
142 : :
143 : 1361 : r = bf_list_add_tail(list, *data);
144 [ + - ]: 1361 : if (r < 0)
145 : : return r;
146 : :
147 : 1361 : TAKE_PTR(*data);
148 : :
149 : 1361 : 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 : 62512 : int bf_list_add_tail(bf_list *list, void *data)
178 : : {
179 : 62512 : bf_list_node *node = NULL;
180 : : int r;
181 : :
182 : : assert(list);
183 : :
184 : 62512 : r = bf_list_node_new(&node, data);
185 [ + - ]: 62512 : if (r < 0)
186 : : return r;
187 : :
188 : 62512 : node->prev = list->tail;
189 [ + + ]: 62512 : if (list->tail)
190 : 31358 : list->tail->next = node;
191 : :
192 : 62512 : list->tail = node;
193 : :
194 [ + + ]: 62512 : if (!list->head)
195 : 31154 : list->head = node;
196 : :
197 : 62512 : ++list->len;
198 : :
199 : 62512 : return 0;
200 : : }
201 : :
202 : 21653 : void bf_list_delete(bf_list *list, bf_list_node *node)
203 : : {
204 : : assert(list);
205 : : assert(node);
206 : :
207 [ + + ]: 21653 : if (list->head == node)
208 : 8036 : list->head = node->next;
209 [ + + ]: 21653 : if (list->tail == node)
210 : 1391 : list->tail = node->prev;
211 : :
212 [ + + ]: 21653 : if (node->prev)
213 : 13617 : node->prev->next = node->next;
214 [ + + ]: 21653 : if (node->next)
215 : 20262 : node->next->prev = node->prev;
216 : :
217 : 21653 : bf_list_node_free(&node, list->ops.free);
218 : :
219 : 21653 : --list->len;
220 : 21653 : }
221 : :
222 : 7061 : void *bf_list_get_at(const bf_list *list, size_t index)
223 : : {
224 : : assert(list);
225 : :
226 [ + - + + ]: 18311 : bf_list_foreach (list, node) {
227 [ + + ]: 9155 : if (index == 0)
228 : 7060 : return node->data;
229 [ + + ]: 2095 : --index;
230 : : }
231 : :
232 : : return NULL;
233 : : }
|