revert breaks some stupid old compilers
[oscam.git] / oscam-llist.c
blob9295ec9e2601691e099da8e8126c7c790e9b9a55
2 /* singularly linked-list */
4 #include "globals.h"
5 #include "oscam-garbage.h"
6 #include "oscam-lock.h"
7 #include "oscam-string.h"
9 extern char *LOG_LIST;
12 Locking rules:
14 mutex lock is needed when...
15 1. l->initial + l->last is modified/accessed
16 2. LL_NODE nxt modified/accessed
21 #ifdef WITH_DEBUG
22 static int8_t chk_debuglog(LLIST *l)
24 return (l && l->lock.name != LOG_LIST);
26 #endif
28 static void _destroy(LLIST *l)
30 if(!l) { return; }
31 if(!l->flag++)
33 cs_writelock(__func__, &l->lock); //just getting sure noone is using it
34 cs_writeunlock(__func__, &l->lock);
36 cs_lock_destroy(__func__, &l->lock);
37 add_garbage(l);
41 LLIST *ll_create(const char *name)
43 LLIST *l;
44 if(!cs_malloc(&l, sizeof(LLIST)))
45 { return NULL; }
46 cs_lock_create(__func__, &l->lock, name, 5000);
47 return l;
50 void ll_destroy(LLIST **pl)
52 LLIST *l = *pl;
53 if(!l || l->flag) { return; }
54 *pl = NULL;
55 ll_clear(l);
57 _destroy(l);
60 void ll_destroy_data(LLIST **pl)
62 LLIST *l = *pl;
63 if(!l) { return; }
64 *pl = NULL;
65 ll_clear_data(l);
67 _destroy(l);
71 void ll_destroy_free_data(LLIST **pl)
73 LLIST *l = *pl;
74 if(!l||l->flag) { return; }
75 *pl = NULL;
77 //*********************************
78 cs_writelock(__func__, &l->lock);
80 LL_NODE *n=l->initial, *nxt;
81 while(n)
83 nxt = n->nxt;
84 NULLFREE(n->obj);
85 NULLFREE(n);
86 n = nxt;
88 l->version++;
89 l->count = 0;
90 l->initial = 0;
91 l->last = 0;
92 cs_writeunlock(__func__, &l->lock);
93 //**********************************
95 if(!l->flag++)
97 cs_writelock(__func__, &l->lock); //just getting sure noone is using it
98 cs_writeunlock(__func__, &l->lock);
100 cs_lock_destroy(__func__, &l->lock);
101 NULLFREE(l);
106 /* Internal iteration function. Make sure that you don't have a lock and that it and it->l are set. */
107 static void *ll_iter_next_nolock(LL_ITER *it)
109 if(it->l->version != it->ll_version)
111 #ifdef WITH_DEBUG
112 if(chk_debuglog(it->l))
113 { cs_log_dbg(D_TRACE, "list changed, searching new position"); }
114 #endif
116 LL_NODE *ptr;
117 //cs_readlock(__func__, &it->l->lock);
118 if(!it->cur && !it->prv)
120 it->cur = it->l->initial;
122 else
124 for(ptr = it->l->initial; ptr; ptr = ptr->nxt)
126 if(ptr == it->cur)
128 it->prv = ptr;
129 it->cur = ptr->nxt;
130 break;
133 if(!ptr)
135 ll_iter_reset(it); // restart iteration
136 it->cur = it->l->initial;
139 it->ll_version = it->l->version;
140 //cs_readunlock(__func__, &it->l->lock);
142 if(it->cur)
143 { return it->cur->obj; }
146 else
148 if(it->cur)
150 it->prv = it->cur;
151 it->cur = it->cur->nxt;
153 else if(it->l->initial && !it->prv)
154 { it->cur = it->l->initial; }
156 if(it->cur)
157 { return it->cur->obj; }
159 return NULL;
162 static void ll_clear_int(LLIST *l, int32_t clear_data)
164 if(!l || l->flag) { return; }
166 cs_writelock(__func__, &l->lock);
168 LL_NODE *n = l->initial, *nxt;
169 while(n)
171 nxt = n->nxt;
172 if(clear_data)
173 { add_garbage(n->obj); }
174 add_garbage(n);
175 n = nxt;
177 l->version++;
178 l->count = 0;
179 l->initial = 0;
180 l->last = 0;
181 cs_writeunlock(__func__, &l->lock);
184 void ll_clear(LLIST *l)
186 ll_clear_int(l, 0);
190 void ll_clear_data(LLIST *l)
192 ll_clear_int(l, 1);
195 /* Appends to the list. Do not call this from outside without having a lock! */
196 static LL_NODE *ll_append_nolock(LLIST *l, void *obj)
198 if(l && obj && !l->flag)
200 LL_NODE *new;
201 if(!cs_malloc(&new, sizeof(LL_NODE)))
202 { return NULL; }
203 new->obj = obj;
205 if(l->last)
206 { l->last->nxt = new; }
207 else
208 { l->initial = new; }
209 l->last = new;
211 l->count++;
212 return new;
215 return NULL;
218 LL_NODE *ll_append(LLIST *l, void *obj)
220 if(l && obj && !l->flag)
222 cs_writelock(__func__, &l->lock);
224 LL_NODE *n = ll_append_nolock(l, obj);
225 cs_writeunlock(__func__, &l->lock);
226 return n;
228 return NULL;
231 LL_NODE *ll_prepend(LLIST *l, void *obj)
233 if(l && obj && !l->flag)
235 LL_NODE *new;
236 if(!cs_malloc(&new, sizeof(LL_NODE)))
237 { return NULL; }
238 new->obj = obj;
240 cs_writelock(__func__, &l->lock);
242 new->nxt = l->initial;
244 l->initial = new;
245 if(!l->last)
246 { l->last = l->initial; }
247 l->count++;
248 cs_writeunlock(__func__, &l->lock);
250 return new;
253 return NULL;
256 LL_ITER ll_iter_create(LLIST *l)
258 LL_ITER it;
259 memset(&it, 0, sizeof(it));
260 it.l = l;
261 if(it.l)
262 { it.ll_version = it.l->version; }
263 return it;
267 void *ll_iter_next(LL_ITER *it)
269 if(it && it->l && !it->l->flag)
271 cs_readlock(__func__, &it->l->lock);
272 void *res = ll_iter_next_nolock(it);
273 cs_readunlock(__func__, &it->l->lock);
274 return res;
276 return NULL;
279 void *ll_iter_remove_nolock(LL_ITER *it)
281 void *obj = NULL;
282 if(it)
284 LL_NODE *del = it->cur;
285 if(del)
287 obj = del->obj;
288 LL_NODE *prv = it->prv;
289 if(it->ll_version != it->l->version || !prv) // List has been modified so it->prv might be wrong!
291 LL_NODE *n = it->l->initial;
292 prv = NULL;
293 while(n && n != del)
295 prv = n;
296 n = n->nxt;
298 if(n != del)
299 { return NULL; }
302 if(prv)
303 { prv->nxt = del->nxt; }
304 else
305 { it->l->initial = del->nxt; }
306 if(!it->l->initial)
307 { it->l->last = NULL; }
308 else if(del == it->l->last)
309 { it->l->last = prv; }
311 it->cur = it->l->initial;
312 it->prv = NULL;
313 if(prv != NULL)
315 while(it->cur && it->cur != prv)
317 it->prv = it->cur;
318 it->cur = it->cur->nxt;
321 else
322 { it->cur = NULL; }
323 it->l->count--;
324 it->ll_version = ++it->l->version;
326 add_garbage(del);
329 return obj;
332 void *ll_iter_next_remove(LL_ITER *it)
334 if(it && it->l && !it->l->flag)
336 cs_writelock(__func__, &it->l->lock);
337 void *res = ll_iter_next_nolock(it);
338 ll_iter_remove_nolock(it);
339 cs_writeunlock(__func__, &it->l->lock);
340 return res;
342 return NULL;
345 void *ll_iter_move(LL_ITER *it, int32_t offset)
347 if(it && it->l && !it->l->flag)
349 int32_t i;
350 void *res = NULL;
351 for(i = 0; i < offset; i++)
353 res = ll_iter_next_nolock(it);
354 if(!res) { break; }
357 return res;
359 return NULL;
362 void *ll_iter_peek(const LL_ITER *it, int32_t offset)
364 if(it && it->l && !it->l->flag)
366 cs_readlock(__func__, &((LL_ITER *)it)->l->lock);
368 LL_NODE *n = it->cur;
369 int32_t i;
371 for(i = 0; i < offset; i++)
373 if(n)
374 { n = n->nxt; }
375 else
376 { break; }
378 cs_readunlock(__func__, &((LL_ITER *)it)->l->lock);
380 if(!n)
381 { return NULL; }
382 return n->obj;
384 return NULL;
387 void ll_iter_reset(LL_ITER *it)
389 if(it)
391 it->prv = NULL;
392 it->cur = NULL;
396 void ll_iter_insert(LL_ITER *it, void *obj)
398 if(it && obj && !it->l->flag)
400 cs_writelock(__func__, &it->l->lock);
402 if(!it->cur || !it->cur->nxt)
403 { ll_append_nolock(it->l, obj); }
404 else
406 LL_NODE *n;
407 if(!cs_malloc(&n, sizeof(LL_NODE)))
409 cs_writeunlock(__func__, &it->l->lock);
410 return;
413 n->obj = obj;
414 n->nxt = it->cur->nxt;
415 it->cur->nxt = n;
417 it->l->count++;
418 it->ll_version = ++it->l->version;
420 cs_writeunlock(__func__, &it->l->lock);
424 /* Removes the element to which the iterator currently points. */
425 void *ll_iter_remove(LL_ITER *it)
427 void *obj = NULL;
428 if(it && it->l && !it->l->flag)
430 LL_NODE *del = it->cur;
431 if(del)
433 cs_writelock(__func__, &it->l->lock);
434 obj = ll_iter_remove_nolock(it);
435 cs_writeunlock(__func__, &it->l->lock);
439 return obj;
442 /* Moves the element which is currently pointed to by the iterator to the head of the list.*/
443 int32_t ll_iter_move_first(LL_ITER *it)
445 int32_t moved = 0;
446 if(it && it->l && !it->l->flag)
448 LL_NODE *move = it->cur;
449 if(move)
451 if(move == it->l->initial) //Can't move self to first
452 { return 1; }
454 LL_NODE *prv = it->prv;
455 cs_writelock(__func__, &it->l->lock);
456 if(it->ll_version != it->l->version || !prv) // List has been modified so it->prv might be wrong!
458 LL_NODE *n = it->l->initial;
459 prv = NULL;
460 while(n && n != move)
462 prv = n;
463 n = n->nxt;
465 if(n != move)
467 cs_writeunlock(__func__, &it->l->lock);
468 return moved;
472 if(prv)
473 { prv->nxt = move->nxt; }
474 else
475 { it->l->initial = move->nxt; }
477 if(prv && it->l->last == move)
478 { it->l->last = prv; }
479 move->nxt = it->l->initial;
480 it->l->initial = move;
482 it->ll_version = ++it->l->version;
483 it->prv = NULL;
484 cs_writeunlock(__func__, &it->l->lock);
485 moved = 1;
488 return moved;
491 void ll_iter_remove_data(LL_ITER *it)
493 void *obj = ll_iter_remove(it);
494 add_garbage(obj);
497 void *ll_has_elements(const LLIST *l)
499 if(!l || !l->initial || l->flag)
500 { return NULL; }
501 return l->initial->obj;
504 void *ll_last_element(const LLIST *l)
506 if(!l || !l->last || l->flag)
507 { return NULL; }
508 return l->last->obj;
511 int32_t ll_contains(const LLIST *l, const void *obj)
513 if(!l || !obj || l->flag)
514 { return 0; }
515 LL_ITER it = ll_iter_create((LLIST *) l);
516 const void *data;
517 while((data = ll_iter_next(&it)))
519 if(data == obj)
520 { break; }
522 return (data == obj);
525 const void *ll_contains_data(const LLIST *l, const void *obj, uint32_t size)
527 if(!l || !obj || l->flag)
528 { return NULL; }
529 LL_ITER it = ll_iter_create((LLIST *) l);
530 const void *data;
531 while((data = ll_iter_next(&it)))
533 if(!memcmp(data, obj, size))
534 { break; }
536 return data;
539 int32_t ll_remove(LLIST *l, const void *obj)
541 int32_t n = 0;
542 LL_ITER it = ll_iter_create(l);
543 void *data;
544 while((data = ll_iter_next(&it)))
546 if(data == obj)
548 ll_iter_remove(&it);
549 n++;
552 return n;
555 void ll_remove_data(LLIST *l, void *obj)
557 LL_ITER it = ll_iter_create(l);
558 void *data;
559 while((data = ll_iter_next(&it)))
561 if(data == obj)
562 { ll_iter_remove_data(&it); }
566 // removes all elements from l where elements are in elements_to_remove
567 int32_t ll_remove_all(LLIST *l, const LLIST *elements_to_remove)
569 int32_t count = 0;
570 LL_ITER it1 = ll_iter_create(l);
571 LL_ITER it2 = ll_iter_create((LLIST *) elements_to_remove);
573 const void *data1, *data2;
574 while((data1 = ll_iter_next(&it1)))
576 ll_iter_reset(&it2);
577 while((data2 = ll_iter_next(&it2)))
579 if(data1 == data2)
581 ll_iter_remove(&it1);
582 count++;
583 break;
588 return count;
591 /* Returns an array with all elements sorted, the amount of elements is stored in size. We do not sort the original linked list
592 as this might harm running iterations. Furthermore, we need the array anyway for qsort() to work. Remember to free() the result. */
593 void **ll_sort(const LLIST *l, void *compare, int32_t *size)
595 if(!l || !l->initial || !compare)
597 *size = 0;
598 return NULL;
600 int32_t i = 0;
601 LL_NODE *n;
603 cs_readlock(__func__, &((LLIST *)l)->lock);
604 *size = l->count;
605 void **p;
606 if(!cs_malloc(&p, l->count * sizeof(p[0])))
608 cs_readunlock(__func__, &((LLIST *)l)->lock);
609 return NULL;
611 for(n = l->initial; n; n = n->nxt)
613 p[i++] = n->obj;
615 cs_readunlock(__func__, &((LLIST *)l)->lock);
616 #ifdef WITH_DEBUG
617 // if (chk_debugLog(it->l))
618 //cs_log_dbg(D_TRACE, "sort: count %d size %d", l->count, sizeof(p[0]));
619 #endif
620 qsort(p, l->count, sizeof(p[0]), compare);
622 return p;
625 void ll_putall(LLIST *dest, LLIST *src)
627 LL_ITER it = ll_iter_create(src);
628 void *data;
629 while((data = ll_iter_next(&it)))
631 ll_append(dest, data);
635 //New Iterator:
636 LL_LOCKITER *ll_li_create(LLIST *l, int32_t writelock)
638 if(!l || l->flag) { return NULL; }
640 LL_LOCKITER *li;
641 if(!cs_malloc(&li, sizeof(LL_LOCKITER)))
642 { return NULL; }
644 li->l = l;
645 li->writelock = writelock;
646 if(writelock)
647 { cs_writelock(__func__, &l->lock); }
648 else
649 { cs_readlock(__func__, &l->lock); }
650 li->it = ll_iter_create(l);
651 return li;
654 void ll_li_destroy(LL_LOCKITER *li)
656 if(li && li->l)
658 if(li->writelock)
659 { cs_writeunlock(__func__, &li->l->lock); }
660 else
661 { cs_readunlock(__func__, &li->l->lock); }
662 li->l = NULL;
663 add_garbage(li);
667 void *ll_li_next(LL_LOCKITER *li)
669 if(li && li->l)
671 return ll_iter_next_nolock(&li->it);
673 return NULL;
676 LLIST *ll_clone(LLIST *l, uint32_t copysize)
678 if(!l || l->flag) { return NULL; }
680 LLIST *cloned = ll_create(l->lock.name);
681 LL_LOCKITER *li = ll_li_create(l, 0);
682 void *data;
683 while((data = ll_li_next(li)))
685 void *new_data;
686 if(!cs_malloc(&new_data, copysize))
687 { break; }
688 memcpy(new_data, data, copysize);
689 ll_append_nolock(cloned, new_data);
691 ll_li_destroy(li);
692 return cloned;
695 void *ll_remove_first(LLIST *l)
697 if(l && !l->flag)
699 LL_ITER it = ll_iter_create(l);
700 void *data = ll_iter_next(&it);
701 if(data) { ll_iter_remove(&it); }
702 return data;
704 return NULL;
707 void ll_remove_first_data(LLIST *l)
709 void *data = ll_remove_first(l);
710 if(data) { NULLFREE(data); }