Nilorea Library
C utilities for networking, threading, graphics
Loading...
Searching...
No Matches
n_list.c
Go to the documentation of this file.
1/*
2 * Nilorea Library
3 * Copyright (C) 2005-2026 Castagnier Mickael
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <https://www.gnu.org/licenses/>.
17 */
18
27#include "nilorea/n_common.h"
28#include "nilorea/n_log.h"
29#include "nilorea/n_list.h"
30
36LIST* new_generic_list(size_t max_items) {
37 LIST* list = NULL;
38
39 Malloc(list, LIST, 1);
40 __n_assert(list, return NULL);
41
42 list->nb_max_items = max_items;
43 list->nb_items = 0;
44
45 list->start = list->end = NULL;
46
47 return list;
48} /* new_generic_list */
49
56LIST_NODE* new_list_node(void* ptr, void (*destructor)(void* ptr)) {
57 LIST_NODE* node = NULL;
58
59 Malloc(node, LIST_NODE, 1);
60 __n_assert(node, n_log(LOG_ERR, "Error allocating node for ptr %p", ptr); return NULL);
61
62 node->ptr = ptr;
63 node->destroy_func = destructor;
64 node->next = node->prev = NULL;
65
66 return node;
67} /* new_list_node(...) */
68
75void* remove_list_node_f(LIST* list, LIST_NODE* node) {
76 void* ptr = NULL;
77
78 __n_assert(list, n_log(LOG_ERR, "can't remove from NULL list"); return NULL);
79 __n_assert(list->start, n_log(LOG_ERR, "can't remove from NULL list->start"); return NULL);
80 __n_assert(list->end, n_log(LOG_ERR, "can't remove from NULL list->end"); return NULL);
81 __n_assert(node, n_log(LOG_ERR, "can't remove from NULL node"); return NULL);
82
83 ptr = node->ptr;
84 if (node->prev && node->next) {
85 node->prev->next = node->next;
86 node->next->prev = node->prev;
87 } else {
88 if (node->prev == NULL && node->next) {
89 node->next->prev = NULL;
90 list->start = node->next;
91 } else {
92 if (node->prev && node->next == NULL) {
93 node->prev->next = NULL;
94 list->end = node->prev;
95 } else {
96 if (node->prev == NULL && node->next == NULL) {
97 /* removing last item */
98 list->start = list->end = NULL;
99 }
100 }
101 }
102 }
103 Free(node);
104 if (list->nb_items > 0) {
105 list->nb_items--;
106 }
107 return ptr;
108} /* remove_list_node_f(...) */
109
116int list_node_push(LIST* list, LIST_NODE* node) {
117 __n_assert(list, n_log(LOG_ERR, "invalid list: NULL"); return FALSE);
118 __n_assert(node, n_log(LOG_ERR, "invalid node: NULL"); return FALSE);
119
120 if (list->nb_max_items > 0 && (list->nb_items >= list->nb_max_items)) {
121 n_log(LOG_ERR, "list is full");
122 return FALSE;
123 }
124 node->next = NULL;
125 if (list->end) {
126 list->end->next = node;
127 node->prev = list->end;
128 list->end = node;
129 } else {
130 node->prev = NULL;
131 list->start = list->end = node;
132 }
133 list->nb_items++;
134 return TRUE;
135} /* list_node_push() */
136
143 __n_assert(list, n_log(LOG_ERR, "invalid list: NULL"); return NULL);
144
145 if (list->nb_items == 0 || list->end == NULL)
146 return NULL;
147
148 LIST_NODE* nodeptr = NULL;
149
150 nodeptr = list->end;
151 if (list->end->prev) {
152 list->end = list->end->prev;
153 list->end->next = NULL;
154 }
155 list->nb_items--;
156 if (list->nb_items == 0)
157 list->start = list->end = NULL;
158
159 nodeptr->prev = NULL;
160 nodeptr->next = NULL;
161 return nodeptr;
162} /* list_node_pop() */
163
170 __n_assert(list, n_log(LOG_ERR, "invalid list: NULL"); return NULL);
171
172 if (list->nb_items == 0 || list->start == NULL)
173 return NULL;
174
175 LIST_NODE* nodeptr = NULL;
176 nodeptr = list->start;
177
178 if (list->start->next) {
179 list->start = list->start->next;
180 list->start->prev = NULL;
181 }
182
183 list->nb_items--;
184
185 if (list->nb_items == 0)
186 list->start = list->end = NULL;
187
188 nodeptr->prev = NULL;
189 nodeptr->next = NULL;
190 return nodeptr;
191} /* list_node_shift() */
192
200 __n_assert(list, n_log(LOG_ERR, "invalid list: NULL"); return FALSE);
201 __n_assert(node, n_log(LOG_ERR, "invalid node: NULL"); return FALSE);
202
203 if (list->nb_max_items > 0 && (list->nb_items >= list->nb_max_items)) {
204 n_log(LOG_ERR, "list is full");
205 return FALSE;
206 }
207 node->prev = NULL;
208 if (list->start) {
209 link_node(node, list->start);
210 list->start = node;
211 } else {
212 node->next = NULL;
213 list->start = list->end = node;
214 }
215 list->nb_items++;
216
217 return TRUE;
218} /* list_node_unshift() */
219
227int list_push(LIST* list, void* ptr, void (*destructor)(void* ptr)) {
228 LIST_NODE* node = NULL;
229
230 __n_assert(list, n_log(LOG_ERR, "invalid list: NULL"); return FALSE);
231 __n_assert(ptr, n_log(LOG_ERR, "invalid ptr: NULL"); return FALSE);
232
233 if (list->nb_max_items > 0 && (list->nb_items >= list->nb_max_items)) {
234 n_log(LOG_ERR, "list is full");
235 return FALSE;
236 }
237
238 node = new_list_node(ptr, destructor);
239 __n_assert(node, n_log(LOG_ERR, "Couldn't allocate new node"); return FALSE);
240
241 if (list->end) {
242 list->end->next = node;
243 node->prev = list->end;
244 list->end = node;
245 } else {
246 list->start = list->end = node;
247 }
248 list->nb_items++;
249 return TRUE;
250} /* list_push( ... ) */
251
260int list_push_sorted(LIST* list, void* ptr, int (*comparator)(const void* a, const void* b), void (*destructor)(void* ptr)) {
261 LIST_NODE* nodeptr = NULL;
262 int ret = TRUE;
263
264 __n_assert(list, n_log(LOG_ERR, "invalid list: NULL"); return FALSE);
265 __n_assert(ptr, n_log(LOG_ERR, "invalid ptr: NULL"); return FALSE);
266 __n_assert(comparator, n_log(LOG_ERR, "invalid comparator: NULL"); return FALSE);
267
268 if (list->nb_max_items > 0 && (list->nb_items >= list->nb_max_items)) {
269 n_log(LOG_ERR, "list is full");
270 return FALSE;
271 }
272
273 if (list->end) {
274 nodeptr = list->end;
275 while (nodeptr && (comparator(ptr, nodeptr->ptr) < 0))
276 nodeptr = nodeptr->prev;
277
278 if (!nodeptr) {
279 /* It's the lower ranked element in the sort */
280 ret = list_unshift(list, ptr, destructor);
281 if (ret == FALSE) {
282 n_log(LOG_ERR, "Couldn't list_unshift in list %p ptr %p with destructor %p", list, ptr, destructor);
283 return FALSE;
284 }
285 } else {
286 /* we have a match inside the list. let's insert the datas */
287 LIST_NODE* node_next = nodeptr->next;
288 LIST_NODE* newnode = new_list_node(ptr, destructor);
289 __n_assert(newnode, n_log(LOG_ERR, "Couldn't allocate new node"); return FALSE);
290
291 if (node_next) {
292 link_node(newnode, node_next);
293 } else
294 list->end = newnode;
295
296 link_node(nodeptr, newnode);
297 list->nb_items++;
298 }
299 } else {
300 ret = list_push(list, ptr, destructor);
301 if (ret == FALSE) {
302 n_log(LOG_ERR, "Couldn't list_push in list %p ptr %p with destructor %p", list, ptr, destructor);
303 return FALSE;
304 }
305 }
306 return ret;
307} /* list_push_sorted( ... ) */
308
316int list_unshift(LIST* list, void* ptr, void (*destructor)(void* ptr)) {
317 LIST_NODE* node = NULL;
318
319 __n_assert(list, n_log(LOG_ERR, "invalid list: NULL"); return FALSE);
320 __n_assert(ptr, n_log(LOG_ERR, "invalid ptr: NULL"); return FALSE);
321
322 if (list->nb_max_items > 0 && (list->nb_items >= list->nb_max_items)) {
323 n_log(LOG_ERR, "list is full");
324 return FALSE;
325 }
326 node = new_list_node(ptr, destructor);
327 __n_assert(node, n_log(LOG_ERR, "Couldn't allocate new node"); return FALSE);
328
329 if (list->start) {
330 link_node(node, list->start);
331 list->start = node;
332 } else {
333 list->start = list->end = node;
334 }
335 list->nb_items++;
336
337 return TRUE;
338} /* list_unshift_f(...) */
339
348int list_unshift_sorted(LIST* list, void* ptr, int (*comparator)(const void* a, const void* b), void (*destructor)(void* ptr)) {
349 __n_assert(list, n_log(LOG_ERR, "invalid list: NULL"); return FALSE);
350 __n_assert(ptr, n_log(LOG_ERR, "invalid ptr: NULL"); return FALSE);
351 __n_assert(comparator, n_log(LOG_ERR, "invalid comparator: NULL"); return FALSE);
352
353 LIST_NODE* nodeptr = NULL;
354 int ret = TRUE;
355
356 if (list->nb_max_items > 0 && (list->nb_items >= list->nb_max_items)) {
357 n_log(LOG_ERR, "list is full");
358 return FALSE;
359 }
360
361 if (list->start) {
362 nodeptr = list->start;
363 while (nodeptr && (comparator(ptr, nodeptr->ptr) > 0))
364 nodeptr = nodeptr->next;
365
366 if (!nodeptr) {
367 /* It's the higher ranked element in the sort */
368 ret = list_push(list, ptr, destructor);
369 if (ret == FALSE) {
370 n_log(LOG_ERR, "Couldn't list_push in list %p ptr %p with destructor %p", list, ptr, destructor);
371 return FALSE;
372 }
373 } else {
374 /* we have a match inside the list. let's insert the datas */
375 LIST_NODE* node_prev = nodeptr->prev;
376 LIST_NODE* newnode = new_list_node(ptr, destructor);
377 __n_assert(newnode, n_log(LOG_ERR, "Couldn't allocate new node"); return FALSE);
378
379 if (node_prev) {
380 link_node(node_prev, newnode);
381 } else
382 list->start = newnode;
383
384 link_node(newnode, nodeptr);
385 list->nb_items++;
386 }
387 } else {
388 ret = list_unshift(list, ptr, destructor);
389 if (ret == FALSE) {
390 n_log(LOG_ERR, "Couldn't list_unshift in list %p ptr %p with destructor %p", list, ptr, destructor);
391 return FALSE;
392 }
393 }
394 return ret;
395} /* list_unshift_sorted(...) */
396
402void* list_pop_f(LIST* list) {
403 LIST_NODE* nodeptr = NULL;
404 void* ptr = NULL;
405
406 __n_assert(list, n_log(LOG_ERR, "invalid list: NULL"); return NULL);
407
408 if (list->nb_items == 0 || list->end == NULL)
409 return NULL;
410
411 nodeptr = list->end;
412 ptr = nodeptr->ptr;
413
414 if (list->end->prev) {
415 list->end = list->end->prev;
416 list->end->next = NULL;
417 }
418
419 list->nb_items--;
420 if (list->nb_items == 0)
421 list->start = list->end = NULL;
422
423 Free(nodeptr);
424
425 return ptr;
426} /* list_pop_f( ... ) */
427
435void* list_shift_f(LIST* list, char* file, size_t line) {
436 LIST_NODE* nodeptr = NULL;
437 void* ptr = NULL;
438
439 __n_assert(list, n_log(LOG_ERR, "%s:%d: invalid list: NULL", file, line); return NULL);
440
441 if (list->nb_items == 0 || list->start == NULL)
442 return NULL;
443
444 nodeptr = list->start;
445 ptr = nodeptr->ptr;
446
447 if (list->start->next) {
448 list->start = list->start->next;
449 list->start->prev = NULL;
450 }
451
452 list->nb_items--;
453
454 if (list->nb_items == 0)
455 list->start = list->end = NULL;
456
457 Free(nodeptr);
458
459 return ptr;
460} /* list_shift_f(...)*/
461
468LIST_NODE* list_search(LIST* list, const void* ptr) {
469 __n_assert(list, return NULL);
470
471 list_foreach(node, list) {
472 if (node->ptr == ptr)
473 return node;
474 }
475 return NULL;
476} /* list_search */
477
484LIST_NODE* list_search_with_f(LIST* list, int (*checkfunk)(void* ptr)) {
485 __n_assert(list, return NULL);
486 __n_assert(checkfunk, return NULL);
487
488 list_foreach(node, list) {
489 if (checkfunk(node->ptr))
490 return node;
491 }
492 return NULL;
493} /* list_search */
494
500int list_empty(LIST* list) {
501 LIST_NODE* node = NULL;
502
503 __n_assert(list, n_log(LOG_ERR, "list is NULL"); return FALSE);
504
505 node = list->start;
506 while (node) {
507 LIST_NODE* node_ptr = node;
508 node = node->next;
509 if (node_ptr->destroy_func != NULL) {
510 node_ptr->destroy_func(node_ptr->ptr);
511 }
512 Free(node_ptr);
513 }
514 list->start = list->end = NULL;
515 list->nb_items = 0;
516 return TRUE;
517} /* list_empty( ... ) */
518
525int list_empty_with_f(LIST* list, void (*free_fnct)(void* ptr)) {
526 LIST_NODE* node = NULL;
527
528 __n_assert(list, n_log(LOG_ERR, "list is NULL"); return FALSE);
529
530 node = list->start;
531 while (node) {
532 LIST_NODE* node_ptr = node;
533 node = node->next;
534 if (free_fnct) free_fnct(node_ptr->ptr);
535 Free(node_ptr);
536 }
537 list->start = list->end = NULL;
538 list->nb_items = 0;
539 return TRUE;
540} /* list_empty_with_f */
541
547int list_destroy(LIST** list) {
548 __n_assert(list && (*list), n_log(LOG_ERR, "list already destroyed"); return FALSE);
549 list_empty((*list));
550 Free((*list));
551 return TRUE;
552} /* free_list( ... ) */
#define Malloc(__ptr, __struct, __size)
Malloc Handler to get errors and set to 0.
Definition n_common.h:203
#define __n_assert(__ptr, __ret)
macro to assert things
Definition n_common.h:278
#define Free(__ptr)
Free Handler to get errors.
Definition n_common.h:262
LIST_NODE * end
pointer to the end of the list
Definition n_list.h:67
void * ptr
void pointer to store
Definition n_list.h:45
size_t nb_max_items
Maximum number of items in the list.
Definition n_list.h:62
struct LIST_NODE * prev
pointer to the previous node
Definition n_list.h:53
LIST_NODE * start
pointer to the start of the list
Definition n_list.h:65
size_t nb_items
number of item currently in the list
Definition n_list.h:60
void(* destroy_func)(void *ptr)
pointer to destructor function if any, else NULL
Definition n_list.h:48
struct LIST_NODE * next
pointer to the next node
Definition n_list.h:51
void * list_pop_f(LIST *list)
Get a pointer from the end of the list.
Definition n_list.c:402
void * list_shift_f(LIST *list, char *file, size_t line)
Get a pointer from the start of the list.
Definition n_list.c:435
int list_empty(LIST *list)
Empty a LIST list of pointers.
Definition n_list.c:500
LIST_NODE * list_search(LIST *list, const void *ptr)
search ptr in list
Definition n_list.c:468
int list_push(LIST *list, void *ptr, void(*destructor)(void *ptr))
Add a pointer to the end of the list.
Definition n_list.c:227
int list_node_unshift(LIST *list, LIST_NODE *node)
Add a pointer at the start of the list.
Definition n_list.c:199
#define list_foreach(__ITEM_, __LIST_)
ForEach macro helper, safe for node removal during iteration.
Definition n_list.h:88
int list_unshift(LIST *list, void *ptr, void(*destructor)(void *ptr))
Add a pointer at the start of the list.
Definition n_list.c:316
LIST_NODE * list_node_shift(LIST *list)
Get a LIST_NODE pointer from the start of the list.
Definition n_list.c:169
LIST_NODE * new_list_node(void *ptr, void(*destructor)(void *ptr))
Allocate a new node to link in a list.
Definition n_list.c:56
#define link_node(__NODE_1, __NODE_2)
Macro helper for linking two nodes, with NULL safety.
Definition n_list.h:77
int list_destroy(LIST **list)
Empty and Free a list container.
Definition n_list.c:547
int list_unshift_sorted(LIST *list, void *ptr, int(*comparator)(const void *a, const void *b), void(*destructor)(void *ptr))
Add a pointer sorted in the list , starting by the start of the list.
Definition n_list.c:348
LIST_NODE * list_node_pop(LIST *list)
Get a LIST_NODE pointer from the end of the list.
Definition n_list.c:142
void * remove_list_node_f(LIST *list, LIST_NODE *node)
Internal function called each time we need to get a node out of a list.
Definition n_list.c:75
LIST * new_generic_list(size_t max_items)
Initialiaze a generic list container to max_items pointers.
Definition n_list.c:36
int list_push_sorted(LIST *list, void *ptr, int(*comparator)(const void *a, const void *b), void(*destructor)(void *ptr))
Add a pointer sorted in the list , starting by the end of the list.
Definition n_list.c:260
int list_empty_with_f(LIST *list, void(*free_fnct)(void *ptr))
Empty a LIST list of pointers.
Definition n_list.c:525
LIST_NODE * list_search_with_f(LIST *list, int(*checkfunk)(void *ptr))
search ptr in list
Definition n_list.c:484
int list_node_push(LIST *list, LIST_NODE *node)
Add a filled node to the end of the list.
Definition n_list.c:116
Structure of a generic LIST container.
Definition n_list.h:58
Structure of a generic list node.
Definition n_list.h:43
#define n_log(__LEVEL__,...)
Logging function wrapper to get line and func.
Definition n_log.h:88
#define LOG_ERR
error conditions
Definition n_log.h:75
Common headers and low-level functions & define.
List structures and definitions.
Generic log system.