1 /* MIT License
2 *
3 * Copyright (c) 2023 Brad House
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a copy
6 * of this software and associated documentation files (the "Software"), to deal
7 * in the Software without restriction, including without limitation the rights
8 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 * copies of the Software, and to permit persons to whom the Software is
10 * furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice (including the next
13 * paragraph) shall be included in all copies or substantial portions of the
14 * Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 * SOFTWARE.
23 *
24 * SPDX-License-Identifier: MIT
25 */
26 #include "ares_private.h"
27 #include "ares_llist.h"
28
29 struct ares_llist {
30 ares_llist_node_t *head;
31 ares_llist_node_t *tail;
32 ares_llist_destructor_t destruct;
33 size_t cnt;
34 };
35
36 struct ares_llist_node {
37 void *data;
38 ares_llist_node_t *prev;
39 ares_llist_node_t *next;
40 ares_llist_t *parent;
41 };
42
ares_llist_create(ares_llist_destructor_t destruct)43 ares_llist_t *ares_llist_create(ares_llist_destructor_t destruct)
44 {
45 ares_llist_t *list = ares_malloc_zero(sizeof(*list));
46
47 if (list == NULL) {
48 return NULL;
49 }
50
51 list->destruct = destruct;
52
53 return list;
54 }
55
ares_llist_replace_destructor(ares_llist_t * list,ares_llist_destructor_t destruct)56 void ares_llist_replace_destructor(ares_llist_t *list,
57 ares_llist_destructor_t destruct)
58 {
59 if (list == NULL) {
60 return;
61 }
62
63 list->destruct = destruct;
64 }
65
66 typedef enum {
67 ARES__LLIST_INSERT_HEAD,
68 ARES__LLIST_INSERT_TAIL,
69 ARES__LLIST_INSERT_BEFORE
70 } ares_llist_insert_type_t;
71
ares_llist_attach_at(ares_llist_t * list,ares_llist_insert_type_t type,ares_llist_node_t * at,ares_llist_node_t * node)72 static void ares_llist_attach_at(ares_llist_t *list,
73 ares_llist_insert_type_t type,
74 ares_llist_node_t *at, ares_llist_node_t *node)
75 {
76 if (list == NULL || node == NULL) {
77 return; /* LCOV_EXCL_LINE: DefensiveCoding */
78 }
79
80 node->parent = list;
81
82 if (type == ARES__LLIST_INSERT_BEFORE && (at == list->head || at == NULL)) {
83 type = ARES__LLIST_INSERT_HEAD;
84 }
85
86 switch (type) {
87 case ARES__LLIST_INSERT_HEAD:
88 node->next = list->head;
89 node->prev = NULL;
90 if (list->head) {
91 list->head->prev = node;
92 }
93 list->head = node;
94 break;
95 case ARES__LLIST_INSERT_TAIL:
96 node->next = NULL;
97 node->prev = list->tail;
98 if (list->tail) {
99 list->tail->next = node;
100 }
101 list->tail = node;
102 break;
103 case ARES__LLIST_INSERT_BEFORE:
104 node->next = at;
105 node->prev = at->prev;
106 at->prev = node;
107 break;
108 }
109 if (list->tail == NULL) {
110 list->tail = node;
111 }
112 if (list->head == NULL) {
113 list->head = node;
114 }
115
116 list->cnt++;
117 }
118
ares_llist_insert_at(ares_llist_t * list,ares_llist_insert_type_t type,ares_llist_node_t * at,void * val)119 static ares_llist_node_t *ares_llist_insert_at(ares_llist_t *list,
120 ares_llist_insert_type_t type,
121 ares_llist_node_t *at, void *val)
122 {
123 ares_llist_node_t *node = NULL;
124
125 if (list == NULL || val == NULL) {
126 return NULL; /* LCOV_EXCL_LINE: DefensiveCoding */
127 }
128
129 node = ares_malloc_zero(sizeof(*node));
130
131 if (node == NULL) {
132 return NULL;
133 }
134
135 node->data = val;
136 ares_llist_attach_at(list, type, at, node);
137
138 return node;
139 }
140
ares_llist_insert_first(ares_llist_t * list,void * val)141 ares_llist_node_t *ares_llist_insert_first(ares_llist_t *list, void *val)
142 {
143 return ares_llist_insert_at(list, ARES__LLIST_INSERT_HEAD, NULL, val);
144 }
145
ares_llist_insert_last(ares_llist_t * list,void * val)146 ares_llist_node_t *ares_llist_insert_last(ares_llist_t *list, void *val)
147 {
148 return ares_llist_insert_at(list, ARES__LLIST_INSERT_TAIL, NULL, val);
149 }
150
ares_llist_insert_before(ares_llist_node_t * node,void * val)151 ares_llist_node_t *ares_llist_insert_before(ares_llist_node_t *node, void *val)
152 {
153 if (node == NULL) {
154 return NULL;
155 }
156
157 return ares_llist_insert_at(node->parent, ARES__LLIST_INSERT_BEFORE, node,
158 val);
159 }
160
ares_llist_insert_after(ares_llist_node_t * node,void * val)161 ares_llist_node_t *ares_llist_insert_after(ares_llist_node_t *node, void *val)
162 {
163 if (node == NULL) {
164 return NULL;
165 }
166
167 if (node->next == NULL) {
168 return ares_llist_insert_last(node->parent, val);
169 }
170
171 return ares_llist_insert_at(node->parent, ARES__LLIST_INSERT_BEFORE,
172 node->next, val);
173 }
174
ares_llist_node_first(ares_llist_t * list)175 ares_llist_node_t *ares_llist_node_first(ares_llist_t *list)
176 {
177 if (list == NULL) {
178 return NULL;
179 }
180 return list->head;
181 }
182
ares_llist_node_idx(ares_llist_t * list,size_t idx)183 ares_llist_node_t *ares_llist_node_idx(ares_llist_t *list, size_t idx)
184 {
185 ares_llist_node_t *node;
186 size_t cnt;
187
188 if (list == NULL) {
189 return NULL;
190 }
191 if (idx >= list->cnt) {
192 return NULL;
193 }
194
195 node = list->head;
196 for (cnt = 0; node != NULL && cnt < idx; cnt++) {
197 node = node->next;
198 }
199
200 return node;
201 }
202
ares_llist_node_last(ares_llist_t * list)203 ares_llist_node_t *ares_llist_node_last(ares_llist_t *list)
204 {
205 if (list == NULL) {
206 return NULL;
207 }
208 return list->tail;
209 }
210
ares_llist_node_next(ares_llist_node_t * node)211 ares_llist_node_t *ares_llist_node_next(ares_llist_node_t *node)
212 {
213 if (node == NULL) {
214 return NULL;
215 }
216 return node->next;
217 }
218
ares_llist_node_prev(ares_llist_node_t * node)219 ares_llist_node_t *ares_llist_node_prev(ares_llist_node_t *node)
220 {
221 if (node == NULL) {
222 return NULL;
223 }
224 return node->prev;
225 }
226
ares_llist_node_val(ares_llist_node_t * node)227 void *ares_llist_node_val(ares_llist_node_t *node)
228 {
229 if (node == NULL) {
230 return NULL;
231 }
232
233 return node->data;
234 }
235
ares_llist_len(const ares_llist_t * list)236 size_t ares_llist_len(const ares_llist_t *list)
237 {
238 if (list == NULL) {
239 return 0;
240 }
241 return list->cnt;
242 }
243
ares_llist_node_parent(ares_llist_node_t * node)244 ares_llist_t *ares_llist_node_parent(ares_llist_node_t *node)
245 {
246 if (node == NULL) {
247 return NULL;
248 }
249 return node->parent;
250 }
251
ares_llist_first_val(ares_llist_t * list)252 void *ares_llist_first_val(ares_llist_t *list)
253 {
254 return ares_llist_node_val(ares_llist_node_first(list));
255 }
256
ares_llist_last_val(ares_llist_t * list)257 void *ares_llist_last_val(ares_llist_t *list)
258 {
259 return ares_llist_node_val(ares_llist_node_last(list));
260 }
261
ares_llist_node_detach(ares_llist_node_t * node)262 static void ares_llist_node_detach(ares_llist_node_t *node)
263 {
264 ares_llist_t *list;
265
266 if (node == NULL) {
267 return; /* LCOV_EXCL_LINE: DefensiveCoding */
268 }
269
270 list = node->parent;
271
272 if (node->prev) {
273 node->prev->next = node->next;
274 }
275
276 if (node->next) {
277 node->next->prev = node->prev;
278 }
279
280 if (node == list->head) {
281 list->head = node->next;
282 }
283
284 if (node == list->tail) {
285 list->tail = node->prev;
286 }
287
288 node->parent = NULL;
289 list->cnt--;
290 }
291
ares_llist_node_claim(ares_llist_node_t * node)292 void *ares_llist_node_claim(ares_llist_node_t *node)
293 {
294 void *val;
295
296 if (node == NULL) {
297 return NULL;
298 }
299
300 val = node->data;
301 ares_llist_node_detach(node);
302 ares_free(node);
303
304 return val;
305 }
306
ares_llist_node_destroy(ares_llist_node_t * node)307 void ares_llist_node_destroy(ares_llist_node_t *node)
308 {
309 ares_llist_destructor_t destruct;
310 void *val;
311
312 if (node == NULL) {
313 return;
314 }
315
316 destruct = node->parent->destruct;
317
318 val = ares_llist_node_claim(node);
319 if (val != NULL && destruct != NULL) {
320 destruct(val);
321 }
322 }
323
ares_llist_node_replace(ares_llist_node_t * node,void * val)324 void ares_llist_node_replace(ares_llist_node_t *node, void *val)
325 {
326 ares_llist_destructor_t destruct;
327
328 if (node == NULL) {
329 return;
330 }
331
332 destruct = node->parent->destruct;
333 if (destruct != NULL) {
334 destruct(node->data);
335 }
336
337 node->data = val;
338 }
339
ares_llist_clear(ares_llist_t * list)340 void ares_llist_clear(ares_llist_t *list)
341 {
342 ares_llist_node_t *node;
343
344 if (list == NULL) {
345 return;
346 }
347
348 while ((node = ares_llist_node_first(list)) != NULL) {
349 ares_llist_node_destroy(node);
350 }
351 }
352
ares_llist_destroy(ares_llist_t * list)353 void ares_llist_destroy(ares_llist_t *list)
354 {
355 if (list == NULL) {
356 return;
357 }
358 ares_llist_clear(list);
359 ares_free(list);
360 }
361
ares_llist_node_mvparent_last(ares_llist_node_t * node,ares_llist_t * new_parent)362 void ares_llist_node_mvparent_last(ares_llist_node_t *node,
363 ares_llist_t *new_parent)
364 {
365 if (node == NULL || new_parent == NULL) {
366 return; /* LCOV_EXCL_LINE: DefensiveCoding */
367 }
368
369 ares_llist_node_detach(node);
370 ares_llist_attach_at(new_parent, ARES__LLIST_INSERT_TAIL, NULL, node);
371 }
372
ares_llist_node_mvparent_first(ares_llist_node_t * node,ares_llist_t * new_parent)373 void ares_llist_node_mvparent_first(ares_llist_node_t *node,
374 ares_llist_t *new_parent)
375 {
376 if (node == NULL || new_parent == NULL) {
377 return; /* LCOV_EXCL_LINE: DefensiveCoding */
378 }
379
380 ares_llist_node_detach(node);
381 ares_llist_attach_at(new_parent, ARES__LLIST_INSERT_HEAD, NULL, node);
382 }
383