2 Copyright (c) 2007-2016, Troy D. Hanson http://troydhanson.github.com/uthash/
4 Redistribution and use in source and binary forms, with or without
5 modification, are permitted provided that the following conditions are met:
6 * Redistributions of source code must retain the above copyright
7 notice, this list of conditions and the following disclaimer.
8 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
9 IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
10 TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
11 PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
12 OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
13 EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
14 PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
15 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
16 LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
17 NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
18 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 #define UTLIST_VERSION 2.0.1
29 * This file contains macros to manipulate singly and doubly-linked lists.
31 * 1. LL_ macros: singly-linked lists.
32 * 2. DL_ macros: doubly-linked lists.
33 * 3. CDL_ macros: circular doubly-linked lists.
35 * To use singly-linked lists, your structure must have a "next" pointer.
36 * To use doubly-linked lists, your structure must "prev" and "next" pointers.
37 * Either way, the pointer to the head of the list must be initialized to NULL.
39 * ----------------.EXAMPLE -------------------------
42 * struct item *prev, *next;
45 * struct item *list = NULL:
49 * ... allocate and populate item ...
50 * DL_APPEND(list, item);
52 * --------------------------------------------------
54 * For doubly-linked lists, the append and delete macros are O(1)
55 * For singly-linked lists, append and delete are O(n) but prepend is O(1)
56 * The sort macro is O(n log(n)) for all types of single/double/circular lists.
59 /* These macros use decltype or the earlier __typeof GNU extension.
60 As decltype is only available in newer compilers (VS2010 or gcc 4.3+
61 when compiling c++ code), this code uses whatever method is needed
62 or, for VS2008 where neither is available, uses casting workarounds. */
63 #ifdef _MSC_VER /* MS compiler */
64 #if _MSC_VER >= 1600 && defined(__cplusplus) /* VS2010 or newer in C++ mode */
65 #define LDECLTYPE(x) decltype(x)
66 #else /* VS2008 or older (or VS2010 in C mode) */
69 #elif defined(__ICCARM__)
71 #else /* GNU, Sun and other compilers */
72 #define LDECLTYPE(x) __typeof(x)
75 /* for VS2008 we use some workarounds to get around the lack of decltype,
76 * namely, we always reassign our tmp variable to the list head if we need
77 * to dereference its prev/next pointers, and save/restore the real head.*/
79 #define IF_NO_DECLTYPE(x) x
80 #define LDECLTYPE(x) char*
81 #define _SV(elt,list) _tmp = (char*)(list); {char **_alias = (char**)&(list); *_alias = (elt); }
82 #define _NEXT(elt,list,next) ((char*)((list)->next))
83 #define _NEXTASGN(elt,list,to,next) { char **_alias = (char**)&((list)->next); *_alias=(char*)(to); }
84 /* #define _PREV(elt,list,prev) ((char*)((list)->prev)) */
85 #define _PREVASGN(elt,list,to,prev) { char **_alias = (char**)&((list)->prev); *_alias=(char*)(to); }
86 #define _RS(list) { char **_alias = (char**)&(list); *_alias=_tmp; }
87 #define _CASTASGN(a,b) { char **_alias = (char**)&(a); *_alias=(char*)(b); }
89 #define IF_NO_DECLTYPE(x)
91 #define _NEXT(elt,list,next) ((elt)->next)
92 #define _NEXTASGN(elt,list,to,next) ((elt)->next)=(to)
93 /* #define _PREV(elt,list,prev) ((elt)->prev) */
94 #define _PREVASGN(elt,list,to,prev) ((elt)->prev)=(to)
96 #define _CASTASGN(a,b) (a)=(b)
99 /******************************************************************************
100 * The sort macro is an adaptation of Simon Tatham's O(n log(n)) mergesort *
101 * Unwieldy variable names used here to avoid shadowing passed-in variables. *
102 *****************************************************************************/
103 #define LL_SORT(list, cmp) \
104 LL_SORT2(list, cmp, next)
106 #define LL_SORT2(list, cmp, next) \
108 LDECLTYPE(list) _ls_p; \
109 LDECLTYPE(list) _ls_q; \
110 LDECLTYPE(list) _ls_e; \
111 LDECLTYPE(list) _ls_tail; \
112 IF_NO_DECLTYPE(LDECLTYPE(list) _tmp;) \
113 int _ls_insize, _ls_nmerges, _ls_psize, _ls_qsize, _ls_i, _ls_looping; \
117 while (_ls_looping) { \
118 _CASTASGN(_ls_p,list); \
126 for (_ls_i = 0; _ls_i < _ls_insize; _ls_i++) { \
128 _SV(_ls_q,list); _ls_q = _NEXT(_ls_q,list,next); _RS(list); \
131 _ls_qsize = _ls_insize; \
132 while (_ls_psize > 0 || (_ls_qsize > 0 && _ls_q)) { \
133 if (_ls_psize == 0) { \
134 _ls_e = _ls_q; _SV(_ls_q,list); _ls_q = \
135 _NEXT(_ls_q,list,next); _RS(list); _ls_qsize--; \
136 } else if (_ls_qsize == 0 || !_ls_q) { \
137 _ls_e = _ls_p; _SV(_ls_p,list); _ls_p = \
138 _NEXT(_ls_p,list,next); _RS(list); _ls_psize--; \
139 } else if (cmp(_ls_p,_ls_q) <= 0) { \
140 _ls_e = _ls_p; _SV(_ls_p,list); _ls_p = \
141 _NEXT(_ls_p,list,next); _RS(list); _ls_psize--; \
143 _ls_e = _ls_q; _SV(_ls_q,list); _ls_q = \
144 _NEXT(_ls_q,list,next); _RS(list); _ls_qsize--; \
147 _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,_ls_e,next); _RS(list); \
149 _CASTASGN(list,_ls_e); \
156 _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,NULL,next); _RS(list); \
158 if (_ls_nmerges <= 1) { \
167 #define DL_SORT(list, cmp) \
168 DL_SORT2(list, cmp, prev, next)
170 #define DL_SORT2(list, cmp, prev, next) \
172 LDECLTYPE(list) _ls_p; \
173 LDECLTYPE(list) _ls_q; \
174 LDECLTYPE(list) _ls_e; \
175 LDECLTYPE(list) _ls_tail; \
176 IF_NO_DECLTYPE(LDECLTYPE(list) _tmp;) \
177 int _ls_insize, _ls_nmerges, _ls_psize, _ls_qsize, _ls_i, _ls_looping; \
181 while (_ls_looping) { \
182 _CASTASGN(_ls_p,list); \
190 for (_ls_i = 0; _ls_i < _ls_insize; _ls_i++) { \
192 _SV(_ls_q,list); _ls_q = _NEXT(_ls_q,list,next); _RS(list); \
195 _ls_qsize = _ls_insize; \
196 while ((_ls_psize > 0) || ((_ls_qsize > 0) && _ls_q)) { \
197 if (_ls_psize == 0) { \
198 _ls_e = _ls_q; _SV(_ls_q,list); _ls_q = \
199 _NEXT(_ls_q,list,next); _RS(list); _ls_qsize--; \
200 } else if ((_ls_qsize == 0) || (!_ls_q)) { \
201 _ls_e = _ls_p; _SV(_ls_p,list); _ls_p = \
202 _NEXT(_ls_p,list,next); _RS(list); _ls_psize--; \
203 } else if (cmp(_ls_p,_ls_q) <= 0) { \
204 _ls_e = _ls_p; _SV(_ls_p,list); _ls_p = \
205 _NEXT(_ls_p,list,next); _RS(list); _ls_psize--; \
207 _ls_e = _ls_q; _SV(_ls_q,list); _ls_q = \
208 _NEXT(_ls_q,list,next); _RS(list); _ls_qsize--; \
211 _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,_ls_e,next); _RS(list); \
213 _CASTASGN(list,_ls_e); \
215 _SV(_ls_e,list); _PREVASGN(_ls_e,list,_ls_tail,prev); _RS(list); \
220 _CASTASGN((list)->prev, _ls_tail); \
221 _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,NULL,next); _RS(list); \
222 if (_ls_nmerges <= 1) { \
230 #define CDL_SORT(list, cmp) \
231 CDL_SORT2(list, cmp, prev, next)
233 #define CDL_SORT2(list, cmp, prev, next) \
235 LDECLTYPE(list) _ls_p; \
236 LDECLTYPE(list) _ls_q; \
237 LDECLTYPE(list) _ls_e; \
238 LDECLTYPE(list) _ls_tail; \
239 LDECLTYPE(list) _ls_oldhead; \
240 LDECLTYPE(list) _tmp; \
241 int _ls_insize, _ls_nmerges, _ls_psize, _ls_qsize, _ls_i, _ls_looping; \
245 while (_ls_looping) { \
246 _CASTASGN(_ls_p,list); \
247 _CASTASGN(_ls_oldhead,list); \
255 for (_ls_i = 0; _ls_i < _ls_insize; _ls_i++) { \
258 if (_NEXT(_ls_q,list,next) == _ls_oldhead) { \
261 _ls_q = _NEXT(_ls_q,list,next); \
266 _ls_qsize = _ls_insize; \
267 while (_ls_psize > 0 || (_ls_qsize > 0 && _ls_q)) { \
268 if (_ls_psize == 0) { \
269 _ls_e = _ls_q; _SV(_ls_q,list); _ls_q = \
270 _NEXT(_ls_q,list,next); _RS(list); _ls_qsize--; \
271 if (_ls_q == _ls_oldhead) { _ls_q = NULL; } \
272 } else if (_ls_qsize == 0 || !_ls_q) { \
273 _ls_e = _ls_p; _SV(_ls_p,list); _ls_p = \
274 _NEXT(_ls_p,list,next); _RS(list); _ls_psize--; \
275 if (_ls_p == _ls_oldhead) { _ls_p = NULL; } \
276 } else if (cmp(_ls_p,_ls_q) <= 0) { \
277 _ls_e = _ls_p; _SV(_ls_p,list); _ls_p = \
278 _NEXT(_ls_p,list,next); _RS(list); _ls_psize--; \
279 if (_ls_p == _ls_oldhead) { _ls_p = NULL; } \
281 _ls_e = _ls_q; _SV(_ls_q,list); _ls_q = \
282 _NEXT(_ls_q,list,next); _RS(list); _ls_qsize--; \
283 if (_ls_q == _ls_oldhead) { _ls_q = NULL; } \
286 _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,_ls_e,next); _RS(list); \
288 _CASTASGN(list,_ls_e); \
290 _SV(_ls_e,list); _PREVASGN(_ls_e,list,_ls_tail,prev); _RS(list); \
295 _CASTASGN((list)->prev,_ls_tail); \
296 _CASTASGN(_tmp,list); \
297 _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,_tmp,next); _RS(list); \
298 if (_ls_nmerges <= 1) { \
306 /******************************************************************************
307 * singly linked list macros (non-circular) *
308 *****************************************************************************/
309 #define LL_PREPEND(head,add) \
310 LL_PREPEND2(head,add,next)
312 #define LL_PREPEND2(head,add,next) \
314 (add)->next = (head); \
318 #define LL_CONCAT(head1,head2) \
319 LL_CONCAT2(head1,head2,next)
321 #define LL_CONCAT2(head1,head2,next) \
323 LDECLTYPE(head1) _tmp; \
326 while (_tmp->next) { _tmp = _tmp->next; } \
327 _tmp->next=(head2); \
333 #define LL_APPEND(head,add) \
334 LL_APPEND2(head,add,next)
336 #define LL_APPEND2(head,add,next) \
338 LDECLTYPE(head) _tmp; \
342 while (_tmp->next) { _tmp = _tmp->next; } \
349 #define LL_DELETE(head,del) \
350 LL_DELETE2(head,del,next)
352 #define LL_DELETE2(head,del,next) \
354 LDECLTYPE(head) _tmp; \
355 if ((head) == (del)) { \
356 (head)=(head)->next; \
359 while (_tmp->next && (_tmp->next != (del))) { \
363 _tmp->next = (del)->next; \
368 #define LL_COUNT(head,el,counter) \
369 LL_COUNT2(head,el,counter,next) \
371 #define LL_COUNT2(head,el,counter,next) \
374 LL_FOREACH2(head,el,next) { ++(counter); } \
377 #define LL_FOREACH(head,el) \
378 LL_FOREACH2(head,el,next)
380 #define LL_FOREACH2(head,el,next) \
381 for ((el) = (head); el; (el) = (el)->next)
383 #define LL_FOREACH_SAFE(head,el,tmp) \
384 LL_FOREACH_SAFE2(head,el,tmp,next)
386 #define LL_FOREACH_SAFE2(head,el,tmp,next) \
387 for ((el) = (head); (el) && ((tmp) = (el)->next, 1); (el) = (tmp))
389 #define LL_SEARCH_SCALAR(head,out,field,val) \
390 LL_SEARCH_SCALAR2(head,out,field,val,next)
392 #define LL_SEARCH_SCALAR2(head,out,field,val,next) \
394 LL_FOREACH2(head,out,next) { \
395 if ((out)->field == (val)) break; \
399 #define LL_SEARCH(head,out,elt,cmp) \
400 LL_SEARCH2(head,out,elt,cmp,next)
402 #define LL_SEARCH2(head,out,elt,cmp,next) \
404 LL_FOREACH2(head,out,next) { \
405 if ((cmp(out,elt))==0) break; \
409 #define LL_REPLACE_ELEM2(head, el, add, next) \
411 LDECLTYPE(head) _tmp; \
412 assert((head) != NULL); \
413 assert((el) != NULL); \
414 assert((add) != NULL); \
415 (add)->next = (el)->next; \
416 if ((head) == (el)) { \
420 while (_tmp->next && (_tmp->next != (el))) { \
424 _tmp->next = (add); \
429 #define LL_REPLACE_ELEM(head, el, add) \
430 LL_REPLACE_ELEM2(head, el, add, next)
432 #define LL_PREPEND_ELEM2(head, el, add, next) \
435 LDECLTYPE(head) _tmp; \
436 assert((head) != NULL); \
437 assert((add) != NULL); \
438 (add)->next = (el); \
439 if ((head) == (el)) { \
443 while (_tmp->next && (_tmp->next != (el))) { \
447 _tmp->next = (add); \
451 LL_APPEND2(head, add, next); \
455 #define LL_PREPEND_ELEM(head, el, add) \
456 LL_PREPEND_ELEM2(head, el, add, next)
458 #define LL_APPEND_ELEM2(head, el, add, next) \
461 assert((head) != NULL); \
462 assert((add) != NULL); \
463 (add)->next = (el)->next; \
464 (el)->next = (add); \
466 LL_PREPEND2(head, add, next); \
470 #define LL_APPEND_ELEM(head, el, add) \
471 LL_APPEND_ELEM2(head, el, add, next)
474 /* Here are VS2008 / NO_DECLTYPE replacements for a few functions */
477 #define LL_CONCAT2(head1,head2,next) \
481 _tmp = (char*)(head1); \
482 while ((head1)->next) { (head1) = (head1)->next; } \
483 (head1)->next = (head2); \
491 #define LL_APPEND2(head,add,next) \
494 (add)->next = head; /* use add->next as a temp variable */ \
495 while ((add)->next->next) { (add)->next = (add)->next->next; } \
496 (add)->next->next=(add); \
504 #define LL_DELETE2(head,del,next) \
506 if ((head) == (del)) { \
507 (head)=(head)->next; \
509 char *_tmp = (char*)(head); \
510 while ((head)->next && ((head)->next != (del))) { \
511 (head) = (head)->next; \
513 if ((head)->next) { \
514 (head)->next = ((del)->next); \
520 #undef LL_REPLACE_ELEM2
521 #define LL_REPLACE_ELEM2(head, el, add, next) \
523 assert((head) != NULL); \
524 assert((el) != NULL); \
525 assert((add) != NULL); \
526 if ((head) == (el)) { \
529 (add)->next = head; \
530 while ((add)->next->next && ((add)->next->next != (el))) { \
531 (add)->next = (add)->next->next; \
533 if ((add)->next->next) { \
534 (add)->next->next = (add); \
537 (add)->next = (el)->next; \
540 #undef LL_PREPEND_ELEM2
541 #define LL_PREPEND_ELEM2(head, el, add, next) \
544 assert((head) != NULL); \
545 assert((add) != NULL); \
546 if ((head) == (el)) { \
549 (add)->next = (head); \
550 while ((add)->next->next && ((add)->next->next != (el))) { \
551 (add)->next = (add)->next->next; \
553 if ((add)->next->next) { \
554 (add)->next->next = (add); \
557 (add)->next = (el); \
559 LL_APPEND2(head, add, next); \
563 #endif /* NO_DECLTYPE */
565 /******************************************************************************
566 * doubly linked list macros (non-circular) *
567 *****************************************************************************/
568 #define DL_PREPEND(head,add) \
569 DL_PREPEND2(head,add,prev,next)
571 #define DL_PREPEND2(head,add,prev,next) \
573 (add)->next = (head); \
575 (add)->prev = (head)->prev; \
576 (head)->prev = (add); \
578 (add)->prev = (add); \
583 #define DL_APPEND(head,add) \
584 DL_APPEND2(head,add,prev,next)
586 #define DL_APPEND2(head,add,prev,next) \
589 (add)->prev = (head)->prev; \
590 (head)->prev->next = (add); \
591 (head)->prev = (add); \
592 (add)->next = NULL; \
595 (head)->prev = (head); \
596 (head)->next = NULL; \
600 #define DL_CONCAT(head1,head2) \
601 DL_CONCAT2(head1,head2,prev,next)
603 #define DL_CONCAT2(head1,head2,prev,next) \
605 LDECLTYPE(head1) _tmp; \
608 _CASTASGN(_tmp, (head2)->prev); \
609 (head2)->prev = (head1)->prev; \
610 (head1)->prev->next = (head2); \
611 _CASTASGN((head1)->prev, _tmp); \
618 #define DL_DELETE(head,del) \
619 DL_DELETE2(head,del,prev,next)
621 #define DL_DELETE2(head,del,prev,next) \
623 assert((del)->prev != NULL); \
624 if ((del)->prev == (del)) { \
626 } else if ((del)==(head)) { \
627 (del)->next->prev = (del)->prev; \
628 (head) = (del)->next; \
630 (del)->prev->next = (del)->next; \
632 (del)->next->prev = (del)->prev; \
634 (head)->prev = (del)->prev; \
639 #define DL_COUNT(head,el,counter) \
640 DL_COUNT2(head,el,counter,next) \
642 #define DL_COUNT2(head,el,counter,next) \
645 DL_FOREACH2(head,el,next) { ++(counter); } \
648 #define DL_FOREACH(head,el) \
649 DL_FOREACH2(head,el,next)
651 #define DL_FOREACH2(head,el,next) \
652 for ((el) = (head); el; (el) = (el)->next)
654 /* this version is safe for deleting the elements during iteration */
655 #define DL_FOREACH_SAFE(head,el,tmp) \
656 DL_FOREACH_SAFE2(head,el,tmp,next)
658 #define DL_FOREACH_SAFE2(head,el,tmp,next) \
659 for ((el) = (head); (el) && ((tmp) = (el)->next, 1); (el) = (tmp))
661 /* these are identical to their singly-linked list counterparts */
662 #define DL_SEARCH_SCALAR LL_SEARCH_SCALAR
663 #define DL_SEARCH LL_SEARCH
664 #define DL_SEARCH_SCALAR2 LL_SEARCH_SCALAR2
665 #define DL_SEARCH2 LL_SEARCH2
667 #define DL_REPLACE_ELEM2(head, el, add, prev, next) \
669 assert((head) != NULL); \
670 assert((el) != NULL); \
671 assert((add) != NULL); \
672 if ((head) == (el)) { \
674 (add)->next = (el)->next; \
675 if ((el)->next == NULL) { \
676 (add)->prev = (add); \
678 (add)->prev = (el)->prev; \
679 (add)->next->prev = (add); \
682 (add)->next = (el)->next; \
683 (add)->prev = (el)->prev; \
684 (add)->prev->next = (add); \
685 if ((el)->next == NULL) { \
686 (head)->prev = (add); \
688 (add)->next->prev = (add); \
693 #define DL_REPLACE_ELEM(head, el, add) \
694 DL_REPLACE_ELEM2(head, el, add, prev, next)
696 #define DL_PREPEND_ELEM2(head, el, add, prev, next) \
699 assert((head) != NULL); \
700 assert((add) != NULL); \
701 (add)->next = (el); \
702 (add)->prev = (el)->prev; \
703 (el)->prev = (add); \
704 if ((head) == (el)) { \
707 (add)->prev->next = (add); \
710 DL_APPEND2(head, add, prev, next); \
714 #define DL_PREPEND_ELEM(head, el, add) \
715 DL_PREPEND_ELEM2(head, el, add, prev, next)
717 #define DL_APPEND_ELEM2(head, el, add, prev, next) \
720 assert((head) != NULL); \
721 assert((add) != NULL); \
722 (add)->next = (el)->next; \
723 (add)->prev = (el); \
724 (el)->next = (add); \
726 (add)->next->prev = (add); \
728 (head)->prev = (add); \
731 DL_PREPEND2(head, add, prev, next); \
735 #define DL_APPEND_ELEM(head, el, add) \
736 DL_APPEND_ELEM2(head, el, add, prev, next)
738 /******************************************************************************
739 * circular doubly linked list macros *
740 *****************************************************************************/
741 #define CDL_APPEND(head,add) \
742 CDL_APPEND2(head,add,prev,next)
744 #define CDL_APPEND2(head,add,prev,next) \
747 (add)->prev = (head)->prev; \
748 (add)->next = (head); \
749 (head)->prev = (add); \
750 (add)->prev->next = (add); \
752 (add)->prev = (add); \
753 (add)->next = (add); \
758 #define CDL_PREPEND(head,add) \
759 CDL_PREPEND2(head,add,prev,next)
761 #define CDL_PREPEND2(head,add,prev,next) \
764 (add)->prev = (head)->prev; \
765 (add)->next = (head); \
766 (head)->prev = (add); \
767 (add)->prev->next = (add); \
769 (add)->prev = (add); \
770 (add)->next = (add); \
775 #define CDL_DELETE(head,del) \
776 CDL_DELETE2(head,del,prev,next)
778 #define CDL_DELETE2(head,del,prev,next) \
780 if (((head)==(del)) && ((head)->next == (head))) { \
783 (del)->next->prev = (del)->prev; \
784 (del)->prev->next = (del)->next; \
785 if ((del) == (head)) (head)=(del)->next; \
789 #define CDL_COUNT(head,el,counter) \
790 CDL_COUNT2(head,el,counter,next) \
792 #define CDL_COUNT2(head, el, counter,next) \
795 CDL_FOREACH2(head,el,next) { ++(counter); } \
798 #define CDL_FOREACH(head,el) \
799 CDL_FOREACH2(head,el,next)
801 #define CDL_FOREACH2(head,el,next) \
802 for ((el)=(head);el;(el)=(((el)->next==(head)) ? NULL : (el)->next))
804 #define CDL_FOREACH_SAFE(head,el,tmp1,tmp2) \
805 CDL_FOREACH_SAFE2(head,el,tmp1,tmp2,prev,next)
807 #define CDL_FOREACH_SAFE2(head,el,tmp1,tmp2,prev,next) \
808 for ((el) = (head), (tmp1) = (head) ? (head)->prev : NULL; \
809 (el) && ((tmp2) = (el)->next, 1); \
810 (el) = ((el) == (tmp1) ? NULL : (tmp2)))
812 #define CDL_SEARCH_SCALAR(head,out,field,val) \
813 CDL_SEARCH_SCALAR2(head,out,field,val,next)
815 #define CDL_SEARCH_SCALAR2(head,out,field,val,next) \
817 CDL_FOREACH2(head,out,next) { \
818 if ((out)->field == (val)) break; \
822 #define CDL_SEARCH(head,out,elt,cmp) \
823 CDL_SEARCH2(head,out,elt,cmp,next)
825 #define CDL_SEARCH2(head,out,elt,cmp,next) \
827 CDL_FOREACH2(head,out,next) { \
828 if ((cmp(out,elt))==0) break; \
832 #define CDL_REPLACE_ELEM2(head, el, add, prev, next) \
834 assert((head) != NULL); \
835 assert((el) != NULL); \
836 assert((add) != NULL); \
837 if ((el)->next == (el)) { \
838 (add)->next = (add); \
839 (add)->prev = (add); \
842 (add)->next = (el)->next; \
843 (add)->prev = (el)->prev; \
844 (add)->next->prev = (add); \
845 (add)->prev->next = (add); \
846 if ((head) == (el)) { \
852 #define CDL_REPLACE_ELEM(head, el, add) \
853 CDL_REPLACE_ELEM2(head, el, add, prev, next)
855 #define CDL_PREPEND_ELEM2(head, el, add, prev, next) \
858 assert((head) != NULL); \
859 assert((add) != NULL); \
860 (add)->next = (el); \
861 (add)->prev = (el)->prev; \
862 (el)->prev = (add); \
863 (add)->prev->next = (add); \
864 if ((head) == (el)) { \
868 CDL_APPEND2(head, add, prev, next); \
872 #define CDL_PREPEND_ELEM(head, el, add) \
873 CDL_PREPEND_ELEM2(head, el, add, prev, next)
875 #define CDL_APPEND_ELEM2(head, el, add, prev, next) \
878 assert((head) != NULL); \
879 assert((add) != NULL); \
880 (add)->next = (el)->next; \
881 (add)->prev = (el); \
882 (el)->next = (add); \
883 (add)->next->prev = (add); \
885 CDL_PREPEND2(head, add, prev, next); \
889 #define CDL_APPEND_ELEM(head, el, add) \
890 CDL_APPEND_ELEM2(head, el, add, prev, next)
892 #endif /* UTLIST_H */