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