2 Copyright (c) 2007-2017, Troy D. Hanson http://troydhanson.github.com/uthash/
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions are met:
8 * Redistributions of source code must retain the above copyright
9 notice, this list of conditions and the following disclaimer.
11 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
12 IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
13 TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
14 PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
15 OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
16 EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
17 PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
18 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
19 LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
20 NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
21 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 #define UTLIST_VERSION 2.0.2
32 * This file contains macros to manipulate singly and doubly-linked lists.
34 * 1. LL_ macros: singly-linked lists.
35 * 2. DL_ macros: doubly-linked lists.
36 * 3. CDL_ macros: circular doubly-linked lists.
38 * To use singly-linked lists, your structure must have a "next" pointer.
39 * To use doubly-linked lists, your structure must "prev" and "next" pointers.
40 * Either way, the pointer to the head of the list must be initialized to NULL.
42 * ----------------.EXAMPLE -------------------------
45 * struct item *prev, *next;
48 * struct item *list = NULL:
52 * ... allocate and populate item ...
53 * DL_APPEND(list, item);
55 * --------------------------------------------------
57 * For doubly-linked lists, the append and delete macros are O(1)
58 * For singly-linked lists, append and delete are O(n) but prepend is O(1)
59 * The sort macro is O(n log(n)) for all types of single/double/circular lists.
62 /* These macros use decltype or the earlier __typeof GNU extension.
63 As decltype is only available in newer compilers (VS2010 or gcc 4.3+
64 when compiling c++ code), this code uses whatever method is needed
65 or, for VS2008 where neither is available, uses casting workarounds. */
66 #ifdef _MSC_VER /* MS compiler */
67 #if _MSC_VER >= 1600 && defined(__cplusplus) /* VS2010 or newer in C++ mode */
68 #define LDECLTYPE(x) decltype(x)
69 #else /* VS2008 or older (or VS2010 in C mode) */
72 #elif defined(__ICCARM__)
74 #else /* GNU, Sun and other compilers */
75 #define LDECLTYPE(x) __typeof(x)
78 /* for VS2008 we use some workarounds to get around the lack of decltype,
79 * namely, we always reassign our tmp variable to the list head if we need
80 * to dereference its prev/next pointers, and save/restore the real head.*/
82 #define IF_NO_DECLTYPE(x) x
83 #define LDECLTYPE(x) char*
84 #define _SV(elt,list) _tmp = (char*)(list); {char **_alias = (char**)&(list); *_alias = (elt); }
85 #define _NEXT(elt,list,next) ((char*)((list)->next))
86 #define _NEXTASGN(elt,list,to,next) { char **_alias = (char**)&((list)->next); *_alias=(char*)(to); }
87 /* #define _PREV(elt,list,prev) ((char*)((list)->prev)) */
88 #define _PREVASGN(elt,list,to,prev) { char **_alias = (char**)&((list)->prev); *_alias=(char*)(to); }
89 #define _RS(list) { char **_alias = (char**)&(list); *_alias=_tmp; }
90 #define _CASTASGN(a,b) { char **_alias = (char**)&(a); *_alias=(char*)(b); }
92 #define IF_NO_DECLTYPE(x)
94 #define _NEXT(elt,list,next) ((elt)->next)
95 #define _NEXTASGN(elt,list,to,next) ((elt)->next)=(to)
96 /* #define _PREV(elt,list,prev) ((elt)->prev) */
97 #define _PREVASGN(elt,list,to,prev) ((elt)->prev)=(to)
99 #define _CASTASGN(a,b) (a)=(b)
102 /******************************************************************************
103 * The sort macro is an adaptation of Simon Tatham's O(n log(n)) mergesort *
104 * Unwieldy variable names used here to avoid shadowing passed-in variables. *
105 *****************************************************************************/
106 #define LL_SORT(list, cmp) \
107 LL_SORT2(list, cmp, next)
109 #define LL_SORT2(list, cmp, next) \
111 LDECLTYPE(list) _ls_p; \
112 LDECLTYPE(list) _ls_q; \
113 LDECLTYPE(list) _ls_e; \
114 LDECLTYPE(list) _ls_tail; \
115 IF_NO_DECLTYPE(LDECLTYPE(list) _tmp;) \
116 int _ls_insize, _ls_nmerges, _ls_psize, _ls_qsize, _ls_i, _ls_looping; \
120 while (_ls_looping) { \
121 _CASTASGN(_ls_p,list); \
129 for (_ls_i = 0; _ls_i < _ls_insize; _ls_i++) { \
131 _SV(_ls_q,list); _ls_q = _NEXT(_ls_q,list,next); _RS(list); \
134 _ls_qsize = _ls_insize; \
135 while (_ls_psize > 0 || (_ls_qsize > 0 && _ls_q)) { \
136 if (_ls_psize == 0) { \
137 _ls_e = _ls_q; _SV(_ls_q,list); _ls_q = \
138 _NEXT(_ls_q,list,next); _RS(list); _ls_qsize--; \
139 } else if (_ls_qsize == 0 || !_ls_q) { \
140 _ls_e = _ls_p; _SV(_ls_p,list); _ls_p = \
141 _NEXT(_ls_p,list,next); _RS(list); _ls_psize--; \
142 } else if (cmp(_ls_p,_ls_q) <= 0) { \
143 _ls_e = _ls_p; _SV(_ls_p,list); _ls_p = \
144 _NEXT(_ls_p,list,next); _RS(list); _ls_psize--; \
146 _ls_e = _ls_q; _SV(_ls_q,list); _ls_q = \
147 _NEXT(_ls_q,list,next); _RS(list); _ls_qsize--; \
150 _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,_ls_e,next); _RS(list); \
152 _CASTASGN(list,_ls_e); \
159 _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,NULL,next); _RS(list); \
161 if (_ls_nmerges <= 1) { \
170 #define DL_SORT(list, cmp) \
171 DL_SORT2(list, cmp, prev, next)
173 #define DL_SORT2(list, cmp, prev, next) \
175 LDECLTYPE(list) _ls_p; \
176 LDECLTYPE(list) _ls_q; \
177 LDECLTYPE(list) _ls_e; \
178 LDECLTYPE(list) _ls_tail; \
179 IF_NO_DECLTYPE(LDECLTYPE(list) _tmp;) \
180 int _ls_insize, _ls_nmerges, _ls_psize, _ls_qsize, _ls_i, _ls_looping; \
184 while (_ls_looping) { \
185 _CASTASGN(_ls_p,list); \
193 for (_ls_i = 0; _ls_i < _ls_insize; _ls_i++) { \
195 _SV(_ls_q,list); _ls_q = _NEXT(_ls_q,list,next); _RS(list); \
198 _ls_qsize = _ls_insize; \
199 while ((_ls_psize > 0) || ((_ls_qsize > 0) && _ls_q)) { \
200 if (_ls_psize == 0) { \
201 _ls_e = _ls_q; _SV(_ls_q,list); _ls_q = \
202 _NEXT(_ls_q,list,next); _RS(list); _ls_qsize--; \
203 } else if ((_ls_qsize == 0) || (!_ls_q)) { \
204 _ls_e = _ls_p; _SV(_ls_p,list); _ls_p = \
205 _NEXT(_ls_p,list,next); _RS(list); _ls_psize--; \
206 } else if (cmp(_ls_p,_ls_q) <= 0) { \
207 _ls_e = _ls_p; _SV(_ls_p,list); _ls_p = \
208 _NEXT(_ls_p,list,next); _RS(list); _ls_psize--; \
210 _ls_e = _ls_q; _SV(_ls_q,list); _ls_q = \
211 _NEXT(_ls_q,list,next); _RS(list); _ls_qsize--; \
214 _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,_ls_e,next); _RS(list); \
216 _CASTASGN(list,_ls_e); \
218 _SV(_ls_e,list); _PREVASGN(_ls_e,list,_ls_tail,prev); _RS(list); \
223 _CASTASGN((list)->prev, _ls_tail); \
224 _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,NULL,next); _RS(list); \
225 if (_ls_nmerges <= 1) { \
233 #define CDL_SORT(list, cmp) \
234 CDL_SORT2(list, cmp, prev, next)
236 #define CDL_SORT2(list, cmp, prev, next) \
238 LDECLTYPE(list) _ls_p; \
239 LDECLTYPE(list) _ls_q; \
240 LDECLTYPE(list) _ls_e; \
241 LDECLTYPE(list) _ls_tail; \
242 LDECLTYPE(list) _ls_oldhead; \
243 LDECLTYPE(list) _tmp; \
244 int _ls_insize, _ls_nmerges, _ls_psize, _ls_qsize, _ls_i, _ls_looping; \
248 while (_ls_looping) { \
249 _CASTASGN(_ls_p,list); \
250 _CASTASGN(_ls_oldhead,list); \
258 for (_ls_i = 0; _ls_i < _ls_insize; _ls_i++) { \
261 if (_NEXT(_ls_q,list,next) == _ls_oldhead) { \
264 _ls_q = _NEXT(_ls_q,list,next); \
269 _ls_qsize = _ls_insize; \
270 while (_ls_psize > 0 || (_ls_qsize > 0 && _ls_q)) { \
271 if (_ls_psize == 0) { \
272 _ls_e = _ls_q; _SV(_ls_q,list); _ls_q = \
273 _NEXT(_ls_q,list,next); _RS(list); _ls_qsize--; \
274 if (_ls_q == _ls_oldhead) { _ls_q = NULL; } \
275 } else if (_ls_qsize == 0 || !_ls_q) { \
276 _ls_e = _ls_p; _SV(_ls_p,list); _ls_p = \
277 _NEXT(_ls_p,list,next); _RS(list); _ls_psize--; \
278 if (_ls_p == _ls_oldhead) { _ls_p = NULL; } \
279 } else if (cmp(_ls_p,_ls_q) <= 0) { \
280 _ls_e = _ls_p; _SV(_ls_p,list); _ls_p = \
281 _NEXT(_ls_p,list,next); _RS(list); _ls_psize--; \
282 if (_ls_p == _ls_oldhead) { _ls_p = NULL; } \
284 _ls_e = _ls_q; _SV(_ls_q,list); _ls_q = \
285 _NEXT(_ls_q,list,next); _RS(list); _ls_qsize--; \
286 if (_ls_q == _ls_oldhead) { _ls_q = NULL; } \
289 _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,_ls_e,next); _RS(list); \
291 _CASTASGN(list,_ls_e); \
293 _SV(_ls_e,list); _PREVASGN(_ls_e,list,_ls_tail,prev); _RS(list); \
298 _CASTASGN((list)->prev,_ls_tail); \
299 _CASTASGN(_tmp,list); \
300 _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,_tmp,next); _RS(list); \
301 if (_ls_nmerges <= 1) { \
309 /******************************************************************************
310 * singly linked list macros (non-circular) *
311 *****************************************************************************/
312 #define LL_PREPEND(head,add) \
313 LL_PREPEND2(head,add,next)
315 #define LL_PREPEND2(head,add,next) \
317 (add)->next = (head); \
321 #define LL_CONCAT(head1,head2) \
322 LL_CONCAT2(head1,head2,next)
324 #define LL_CONCAT2(head1,head2,next) \
326 LDECLTYPE(head1) _tmp; \
329 while (_tmp->next) { _tmp = _tmp->next; } \
330 _tmp->next=(head2); \
336 #define LL_APPEND(head,add) \
337 LL_APPEND2(head,add,next)
339 #define LL_APPEND2(head,add,next) \
341 LDECLTYPE(head) _tmp; \
345 while (_tmp->next) { _tmp = _tmp->next; } \
352 #define LL_DELETE(head,del) \
353 LL_DELETE2(head,del,next)
355 #define LL_DELETE2(head,del,next) \
357 LDECLTYPE(head) _tmp; \
358 if ((head) == (del)) { \
359 (head)=(head)->next; \
362 while (_tmp->next && (_tmp->next != (del))) { \
366 _tmp->next = (del)->next; \
371 #define LL_COUNT(head,el,counter) \
372 LL_COUNT2(head,el,counter,next) \
374 #define LL_COUNT2(head,el,counter,next) \
377 LL_FOREACH2(head,el,next) { ++(counter); } \
380 #define LL_FOREACH(head,el) \
381 LL_FOREACH2(head,el,next)
383 #define LL_FOREACH2(head,el,next) \
384 for ((el) = (head); el; (el) = (el)->next)
386 #define LL_FOREACH_SAFE(head,el,tmp) \
387 LL_FOREACH_SAFE2(head,el,tmp,next)
389 #define LL_FOREACH_SAFE2(head,el,tmp,next) \
390 for ((el) = (head); (el) && ((tmp) = (el)->next, 1); (el) = (tmp))
392 #define LL_SEARCH_SCALAR(head,out,field,val) \
393 LL_SEARCH_SCALAR2(head,out,field,val,next)
395 #define LL_SEARCH_SCALAR2(head,out,field,val,next) \
397 LL_FOREACH2(head,out,next) { \
398 if ((out)->field == (val)) break; \
402 #define LL_SEARCH(head,out,elt,cmp) \
403 LL_SEARCH2(head,out,elt,cmp,next)
405 #define LL_SEARCH2(head,out,elt,cmp,next) \
407 LL_FOREACH2(head,out,next) { \
408 if ((cmp(out,elt))==0) break; \
412 #define LL_REPLACE_ELEM2(head, el, add, next) \
414 LDECLTYPE(head) _tmp; \
415 assert((head) != NULL); \
416 assert((el) != NULL); \
417 assert((add) != NULL); \
418 (add)->next = (el)->next; \
419 if ((head) == (el)) { \
423 while (_tmp->next && (_tmp->next != (el))) { \
427 _tmp->next = (add); \
432 #define LL_REPLACE_ELEM(head, el, add) \
433 LL_REPLACE_ELEM2(head, el, add, next)
435 #define LL_PREPEND_ELEM2(head, el, add, next) \
438 LDECLTYPE(head) _tmp; \
439 assert((head) != NULL); \
440 assert((add) != NULL); \
441 (add)->next = (el); \
442 if ((head) == (el)) { \
446 while (_tmp->next && (_tmp->next != (el))) { \
450 _tmp->next = (add); \
454 LL_APPEND2(head, add, next); \
458 #define LL_PREPEND_ELEM(head, el, add) \
459 LL_PREPEND_ELEM2(head, el, add, next)
461 #define LL_APPEND_ELEM2(head, el, add, next) \
464 assert((head) != NULL); \
465 assert((add) != NULL); \
466 (add)->next = (el)->next; \
467 (el)->next = (add); \
469 LL_PREPEND2(head, add, next); \
473 #define LL_APPEND_ELEM(head, el, add) \
474 LL_APPEND_ELEM2(head, el, add, next)
477 /* Here are VS2008 / NO_DECLTYPE replacements for a few functions */
480 #define LL_CONCAT2(head1,head2,next) \
484 _tmp = (char*)(head1); \
485 while ((head1)->next) { (head1) = (head1)->next; } \
486 (head1)->next = (head2); \
494 #define LL_APPEND2(head,add,next) \
497 (add)->next = head; /* use add->next as a temp variable */ \
498 while ((add)->next->next) { (add)->next = (add)->next->next; } \
499 (add)->next->next=(add); \
507 #define LL_DELETE2(head,del,next) \
509 if ((head) == (del)) { \
510 (head)=(head)->next; \
512 char *_tmp = (char*)(head); \
513 while ((head)->next && ((head)->next != (del))) { \
514 (head) = (head)->next; \
516 if ((head)->next) { \
517 (head)->next = ((del)->next); \
523 #undef LL_REPLACE_ELEM2
524 #define LL_REPLACE_ELEM2(head, el, add, next) \
526 assert((head) != NULL); \
527 assert((el) != NULL); \
528 assert((add) != NULL); \
529 if ((head) == (el)) { \
532 (add)->next = head; \
533 while ((add)->next->next && ((add)->next->next != (el))) { \
534 (add)->next = (add)->next->next; \
536 if ((add)->next->next) { \
537 (add)->next->next = (add); \
540 (add)->next = (el)->next; \
543 #undef LL_PREPEND_ELEM2
544 #define LL_PREPEND_ELEM2(head, el, add, next) \
547 assert((head) != NULL); \
548 assert((add) != NULL); \
549 if ((head) == (el)) { \
552 (add)->next = (head); \
553 while ((add)->next->next && ((add)->next->next != (el))) { \
554 (add)->next = (add)->next->next; \
556 if ((add)->next->next) { \
557 (add)->next->next = (add); \
560 (add)->next = (el); \
562 LL_APPEND2(head, add, next); \
566 #endif /* NO_DECLTYPE */
568 /******************************************************************************
569 * doubly linked list macros (non-circular) *
570 *****************************************************************************/
571 #define DL_PREPEND(head,add) \
572 DL_PREPEND2(head,add,prev,next)
574 #define DL_PREPEND2(head,add,prev,next) \
576 (add)->next = (head); \
578 (add)->prev = (head)->prev; \
579 (head)->prev = (add); \
581 (add)->prev = (add); \
586 #define DL_APPEND(head,add) \
587 DL_APPEND2(head,add,prev,next)
589 #define DL_APPEND2(head,add,prev,next) \
592 (add)->prev = (head)->prev; \
593 (head)->prev->next = (add); \
594 (head)->prev = (add); \
595 (add)->next = NULL; \
598 (head)->prev = (head); \
599 (head)->next = NULL; \
603 #define DL_CONCAT(head1,head2) \
604 DL_CONCAT2(head1,head2,prev,next)
606 #define DL_CONCAT2(head1,head2,prev,next) \
608 LDECLTYPE(head1) _tmp; \
611 _CASTASGN(_tmp, (head2)->prev); \
612 (head2)->prev = (head1)->prev; \
613 (head1)->prev->next = (head2); \
614 _CASTASGN((head1)->prev, _tmp); \
621 #define DL_DELETE(head,del) \
622 DL_DELETE2(head,del,prev,next)
624 #define DL_DELETE2(head,del,prev,next) \
626 assert((del)->prev != NULL); \
627 if ((del)->prev == (del)) { \
629 } else if ((del)==(head)) { \
630 (del)->next->prev = (del)->prev; \
631 (head) = (del)->next; \
633 (del)->prev->next = (del)->next; \
635 (del)->next->prev = (del)->prev; \
637 (head)->prev = (del)->prev; \
642 #define DL_COUNT(head,el,counter) \
643 DL_COUNT2(head,el,counter,next) \
645 #define DL_COUNT2(head,el,counter,next) \
648 DL_FOREACH2(head,el,next) { ++(counter); } \
651 #define DL_FOREACH(head,el) \
652 DL_FOREACH2(head,el,next)
654 #define DL_FOREACH2(head,el,next) \
655 for ((el) = (head); el; (el) = (el)->next)
657 /* this version is safe for deleting the elements during iteration */
658 #define DL_FOREACH_SAFE(head,el,tmp) \
659 DL_FOREACH_SAFE2(head,el,tmp,next)
661 #define DL_FOREACH_SAFE2(head,el,tmp,next) \
662 for ((el) = (head); (el) && ((tmp) = (el)->next, 1); (el) = (tmp))
664 /* these are identical to their singly-linked list counterparts */
665 #define DL_SEARCH_SCALAR LL_SEARCH_SCALAR
666 #define DL_SEARCH LL_SEARCH
667 #define DL_SEARCH_SCALAR2 LL_SEARCH_SCALAR2
668 #define DL_SEARCH2 LL_SEARCH2
670 #define DL_REPLACE_ELEM2(head, el, add, prev, next) \
672 assert((head) != NULL); \
673 assert((el) != NULL); \
674 assert((add) != NULL); \
675 if ((head) == (el)) { \
677 (add)->next = (el)->next; \
678 if ((el)->next == NULL) { \
679 (add)->prev = (add); \
681 (add)->prev = (el)->prev; \
682 (add)->next->prev = (add); \
685 (add)->next = (el)->next; \
686 (add)->prev = (el)->prev; \
687 (add)->prev->next = (add); \
688 if ((el)->next == NULL) { \
689 (head)->prev = (add); \
691 (add)->next->prev = (add); \
696 #define DL_REPLACE_ELEM(head, el, add) \
697 DL_REPLACE_ELEM2(head, el, add, prev, next)
699 #define DL_PREPEND_ELEM2(head, el, add, prev, next) \
702 assert((head) != NULL); \
703 assert((add) != NULL); \
704 (add)->next = (el); \
705 (add)->prev = (el)->prev; \
706 (el)->prev = (add); \
707 if ((head) == (el)) { \
710 (add)->prev->next = (add); \
713 DL_APPEND2(head, add, prev, next); \
717 #define DL_PREPEND_ELEM(head, el, add) \
718 DL_PREPEND_ELEM2(head, el, add, prev, next)
720 #define DL_APPEND_ELEM2(head, el, add, prev, next) \
723 assert((head) != NULL); \
724 assert((add) != NULL); \
725 (add)->next = (el)->next; \
726 (add)->prev = (el); \
727 (el)->next = (add); \
729 (add)->next->prev = (add); \
731 (head)->prev = (add); \
734 DL_PREPEND2(head, add, prev, next); \
738 #define DL_APPEND_ELEM(head, el, add) \
739 DL_APPEND_ELEM2(head, el, add, prev, next)
741 /******************************************************************************
742 * circular doubly linked list macros *
743 *****************************************************************************/
744 #define CDL_APPEND(head,add) \
745 CDL_APPEND2(head,add,prev,next)
747 #define CDL_APPEND2(head,add,prev,next) \
750 (add)->prev = (head)->prev; \
751 (add)->next = (head); \
752 (head)->prev = (add); \
753 (add)->prev->next = (add); \
755 (add)->prev = (add); \
756 (add)->next = (add); \
761 #define CDL_PREPEND(head,add) \
762 CDL_PREPEND2(head,add,prev,next)
764 #define CDL_PREPEND2(head,add,prev,next) \
767 (add)->prev = (head)->prev; \
768 (add)->next = (head); \
769 (head)->prev = (add); \
770 (add)->prev->next = (add); \
772 (add)->prev = (add); \
773 (add)->next = (add); \
778 #define CDL_DELETE(head,del) \
779 CDL_DELETE2(head,del,prev,next)
781 #define CDL_DELETE2(head,del,prev,next) \
783 if (((head)==(del)) && ((head)->next == (head))) { \
786 (del)->next->prev = (del)->prev; \
787 (del)->prev->next = (del)->next; \
788 if ((del) == (head)) (head)=(del)->next; \
792 #define CDL_COUNT(head,el,counter) \
793 CDL_COUNT2(head,el,counter,next) \
795 #define CDL_COUNT2(head, el, counter,next) \
798 CDL_FOREACH2(head,el,next) { ++(counter); } \
801 #define CDL_FOREACH(head,el) \
802 CDL_FOREACH2(head,el,next)
804 #define CDL_FOREACH2(head,el,next) \
805 for ((el)=(head);el;(el)=(((el)->next==(head)) ? NULL : (el)->next))
807 #define CDL_FOREACH_SAFE(head,el,tmp1,tmp2) \
808 CDL_FOREACH_SAFE2(head,el,tmp1,tmp2,prev,next)
810 #define CDL_FOREACH_SAFE2(head,el,tmp1,tmp2,prev,next) \
811 for ((el) = (head), (tmp1) = (head) ? (head)->prev : NULL; \
812 (el) && ((tmp2) = (el)->next, 1); \
813 (el) = ((el) == (tmp1) ? NULL : (tmp2)))
815 #define CDL_SEARCH_SCALAR(head,out,field,val) \
816 CDL_SEARCH_SCALAR2(head,out,field,val,next)
818 #define CDL_SEARCH_SCALAR2(head,out,field,val,next) \
820 CDL_FOREACH2(head,out,next) { \
821 if ((out)->field == (val)) break; \
825 #define CDL_SEARCH(head,out,elt,cmp) \
826 CDL_SEARCH2(head,out,elt,cmp,next)
828 #define CDL_SEARCH2(head,out,elt,cmp,next) \
830 CDL_FOREACH2(head,out,next) { \
831 if ((cmp(out,elt))==0) break; \
835 #define CDL_REPLACE_ELEM2(head, el, add, prev, next) \
837 assert((head) != NULL); \
838 assert((el) != NULL); \
839 assert((add) != NULL); \
840 if ((el)->next == (el)) { \
841 (add)->next = (add); \
842 (add)->prev = (add); \
845 (add)->next = (el)->next; \
846 (add)->prev = (el)->prev; \
847 (add)->next->prev = (add); \
848 (add)->prev->next = (add); \
849 if ((head) == (el)) { \
855 #define CDL_REPLACE_ELEM(head, el, add) \
856 CDL_REPLACE_ELEM2(head, el, add, prev, next)
858 #define CDL_PREPEND_ELEM2(head, el, add, prev, next) \
861 assert((head) != NULL); \
862 assert((add) != NULL); \
863 (add)->next = (el); \
864 (add)->prev = (el)->prev; \
865 (el)->prev = (add); \
866 (add)->prev->next = (add); \
867 if ((head) == (el)) { \
871 CDL_APPEND2(head, add, prev, next); \
875 #define CDL_PREPEND_ELEM(head, el, add) \
876 CDL_PREPEND_ELEM2(head, el, add, prev, next)
878 #define CDL_APPEND_ELEM2(head, el, add, prev, next) \
881 assert((head) != NULL); \
882 assert((add) != NULL); \
883 (add)->next = (el)->next; \
884 (add)->prev = (el); \
885 (el)->next = (add); \
886 (add)->next->prev = (add); \
888 CDL_PREPEND2(head, add, prev, next); \
892 #define CDL_APPEND_ELEM(head, el, add) \
893 CDL_APPEND_ELEM2(head, el, add, prev, next)
895 #endif /* UTLIST_H */