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