xref: /freebsd-src/contrib/libucl/uthash/utlist.h (revision 6cec9cad762b6476313fb1f8e931a1647822db6b)
1*c99fb5f9SBaptiste Daroussin /*
2*c99fb5f9SBaptiste Daroussin Copyright (c) 2007-2013, Troy D. Hanson   http://troydhanson.github.com/uthash/
3*c99fb5f9SBaptiste Daroussin All rights reserved.
4*c99fb5f9SBaptiste Daroussin 
5*c99fb5f9SBaptiste Daroussin Redistribution and use in source and binary forms, with or without
6*c99fb5f9SBaptiste Daroussin modification, are permitted provided that the following conditions are met:
7*c99fb5f9SBaptiste Daroussin 
8*c99fb5f9SBaptiste Daroussin     * Redistributions of source code must retain the above copyright
9*c99fb5f9SBaptiste Daroussin       notice, this list of conditions and the following disclaimer.
10*c99fb5f9SBaptiste Daroussin 
11*c99fb5f9SBaptiste Daroussin THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
12*c99fb5f9SBaptiste Daroussin IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
13*c99fb5f9SBaptiste Daroussin TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
14*c99fb5f9SBaptiste Daroussin PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
15*c99fb5f9SBaptiste Daroussin OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
16*c99fb5f9SBaptiste Daroussin EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
17*c99fb5f9SBaptiste Daroussin PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
18*c99fb5f9SBaptiste Daroussin PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
19*c99fb5f9SBaptiste Daroussin LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
20*c99fb5f9SBaptiste Daroussin NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
21*c99fb5f9SBaptiste Daroussin SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
22*c99fb5f9SBaptiste Daroussin */
23*c99fb5f9SBaptiste Daroussin 
24*c99fb5f9SBaptiste Daroussin #ifndef UTLIST_H
25*c99fb5f9SBaptiste Daroussin #define UTLIST_H
26*c99fb5f9SBaptiste Daroussin 
27*c99fb5f9SBaptiste Daroussin #define UTLIST_VERSION 1.9.8
28*c99fb5f9SBaptiste Daroussin 
29*c99fb5f9SBaptiste Daroussin #include <assert.h>
30*c99fb5f9SBaptiste Daroussin 
31*c99fb5f9SBaptiste Daroussin /*
32*c99fb5f9SBaptiste Daroussin  * This file contains macros to manipulate singly and doubly-linked lists.
33*c99fb5f9SBaptiste Daroussin  *
34*c99fb5f9SBaptiste Daroussin  * 1. LL_ macros:  singly-linked lists.
35*c99fb5f9SBaptiste Daroussin  * 2. DL_ macros:  doubly-linked lists.
36*c99fb5f9SBaptiste Daroussin  * 3. CDL_ macros: circular doubly-linked lists.
37*c99fb5f9SBaptiste Daroussin  *
38*c99fb5f9SBaptiste Daroussin  * To use singly-linked lists, your structure must have a "next" pointer.
39*c99fb5f9SBaptiste Daroussin  * To use doubly-linked lists, your structure must "prev" and "next" pointers.
40*c99fb5f9SBaptiste Daroussin  * Either way, the pointer to the head of the list must be initialized to NULL.
41*c99fb5f9SBaptiste Daroussin  *
42*c99fb5f9SBaptiste Daroussin  * ----------------.EXAMPLE -------------------------
43*c99fb5f9SBaptiste Daroussin  * struct item {
44*c99fb5f9SBaptiste Daroussin  *      int id;
45*c99fb5f9SBaptiste Daroussin  *      struct item *prev, *next;
46*c99fb5f9SBaptiste Daroussin  * }
47*c99fb5f9SBaptiste Daroussin  *
48*c99fb5f9SBaptiste Daroussin  * struct item *list = NULL:
49*c99fb5f9SBaptiste Daroussin  *
50*c99fb5f9SBaptiste Daroussin  * int main() {
51*c99fb5f9SBaptiste Daroussin  *      struct item *item;
52*c99fb5f9SBaptiste Daroussin  *      ... allocate and populate item ...
53*c99fb5f9SBaptiste Daroussin  *      DL_APPEND(list, item);
54*c99fb5f9SBaptiste Daroussin  * }
55*c99fb5f9SBaptiste Daroussin  * --------------------------------------------------
56*c99fb5f9SBaptiste Daroussin  *
57*c99fb5f9SBaptiste Daroussin  * For doubly-linked lists, the append and delete macros are O(1)
58*c99fb5f9SBaptiste Daroussin  * For singly-linked lists, append and delete are O(n) but prepend is O(1)
59*c99fb5f9SBaptiste Daroussin  * The sort macro is O(n log(n)) for all types of single/double/circular lists.
60*c99fb5f9SBaptiste Daroussin  */
61*c99fb5f9SBaptiste Daroussin 
62*c99fb5f9SBaptiste Daroussin /* These macros use decltype or the earlier __typeof GNU extension.
63*c99fb5f9SBaptiste Daroussin    As decltype is only available in newer compilers (VS2010 or gcc 4.3+
64*c99fb5f9SBaptiste Daroussin    when compiling c++ code), this code uses whatever method is needed
65*c99fb5f9SBaptiste Daroussin    or, for VS2008 where neither is available, uses casting workarounds. */
66*c99fb5f9SBaptiste Daroussin #ifdef _MSC_VER            /* MS compiler */
67*c99fb5f9SBaptiste Daroussin #if _MSC_VER >= 1600 && defined(__cplusplus)  /* VS2010 or newer in C++ mode */
68*c99fb5f9SBaptiste Daroussin #define LDECLTYPE(x) decltype(x)
69*c99fb5f9SBaptiste Daroussin #else                     /* VS2008 or older (or VS2010 in C mode) */
70*c99fb5f9SBaptiste Daroussin #define NO_DECLTYPE
71*c99fb5f9SBaptiste Daroussin #define LDECLTYPE(x) char*
72*c99fb5f9SBaptiste Daroussin #endif
73*c99fb5f9SBaptiste Daroussin #elif defined(__ICCARM__)
74*c99fb5f9SBaptiste Daroussin #define NO_DECLTYPE
75*c99fb5f9SBaptiste Daroussin #define LDECLTYPE(x) char*
76*c99fb5f9SBaptiste Daroussin #else                      /* GNU, Sun and other compilers */
77*c99fb5f9SBaptiste Daroussin #define LDECLTYPE(x) __typeof(x)
78*c99fb5f9SBaptiste Daroussin #endif
79*c99fb5f9SBaptiste Daroussin 
80*c99fb5f9SBaptiste Daroussin /* for VS2008 we use some workarounds to get around the lack of decltype,
81*c99fb5f9SBaptiste Daroussin  * namely, we always reassign our tmp variable to the list head if we need
82*c99fb5f9SBaptiste Daroussin  * to dereference its prev/next pointers, and save/restore the real head.*/
83*c99fb5f9SBaptiste Daroussin #ifdef NO_DECLTYPE
84*c99fb5f9SBaptiste Daroussin #define _SV(elt,list) _tmp = (char*)(list); {char **_alias = (char**)&(list); *_alias = (elt); }
85*c99fb5f9SBaptiste Daroussin #define _NEXT(elt,list,next) ((char*)((list)->next))
86*c99fb5f9SBaptiste Daroussin #define _NEXTASGN(elt,list,to,next) { char **_alias = (char**)&((list)->next); *_alias=(char*)(to); }
87*c99fb5f9SBaptiste Daroussin /* #define _PREV(elt,list,prev) ((char*)((list)->prev)) */
88*c99fb5f9SBaptiste Daroussin #define _PREVASGN(elt,list,to,prev) { char **_alias = (char**)&((list)->prev); *_alias=(char*)(to); }
89*c99fb5f9SBaptiste Daroussin #define _RS(list) { char **_alias = (char**)&(list); *_alias=_tmp; }
90*c99fb5f9SBaptiste Daroussin #define _CASTASGN(a,b) { char **_alias = (char**)&(a); *_alias=(char*)(b); }
91*c99fb5f9SBaptiste Daroussin #else
92*c99fb5f9SBaptiste Daroussin #define _SV(elt,list)
93*c99fb5f9SBaptiste Daroussin #define _NEXT(elt,list,next) ((elt)->next)
94*c99fb5f9SBaptiste Daroussin #define _NEXTASGN(elt,list,to,next) ((elt)->next)=(to)
95*c99fb5f9SBaptiste Daroussin /* #define _PREV(elt,list,prev) ((elt)->prev) */
96*c99fb5f9SBaptiste Daroussin #define _PREVASGN(elt,list,to,prev) ((elt)->prev)=(to)
97*c99fb5f9SBaptiste Daroussin #define _RS(list)
98*c99fb5f9SBaptiste Daroussin #define _CASTASGN(a,b) (a)=(b)
99*c99fb5f9SBaptiste Daroussin #endif
100*c99fb5f9SBaptiste Daroussin 
101*c99fb5f9SBaptiste Daroussin /******************************************************************************
102*c99fb5f9SBaptiste Daroussin  * The sort macro is an adaptation of Simon Tatham's O(n log(n)) mergesort    *
103*c99fb5f9SBaptiste Daroussin  * Unwieldy variable names used here to avoid shadowing passed-in variables.  *
104*c99fb5f9SBaptiste Daroussin  *****************************************************************************/
105*c99fb5f9SBaptiste Daroussin #define LL_SORT(list, cmp)                                                                     \
106*c99fb5f9SBaptiste Daroussin     LL_SORT2(list, cmp, next)
107*c99fb5f9SBaptiste Daroussin 
108*c99fb5f9SBaptiste Daroussin #define LL_SORT2(list, cmp, next)                                                              \
109*c99fb5f9SBaptiste Daroussin do {                                                                                           \
110*c99fb5f9SBaptiste Daroussin   LDECLTYPE(list) _ls_p;                                                                       \
111*c99fb5f9SBaptiste Daroussin   LDECLTYPE(list) _ls_q;                                                                       \
112*c99fb5f9SBaptiste Daroussin   LDECLTYPE(list) _ls_e;                                                                       \
113*c99fb5f9SBaptiste Daroussin   LDECLTYPE(list) _ls_tail;                                                                    \
114*c99fb5f9SBaptiste Daroussin   int _ls_insize, _ls_nmerges, _ls_psize, _ls_qsize, _ls_i, _ls_looping;                       \
115*c99fb5f9SBaptiste Daroussin   if (list) {                                                                                  \
116*c99fb5f9SBaptiste Daroussin     _ls_insize = 1;                                                                            \
117*c99fb5f9SBaptiste Daroussin     _ls_looping = 1;                                                                           \
118*c99fb5f9SBaptiste Daroussin     while (_ls_looping) {                                                                      \
119*c99fb5f9SBaptiste Daroussin       _CASTASGN(_ls_p,list);                                                                   \
120*c99fb5f9SBaptiste Daroussin       list = NULL;                                                                             \
121*c99fb5f9SBaptiste Daroussin       _ls_tail = NULL;                                                                         \
122*c99fb5f9SBaptiste Daroussin       _ls_nmerges = 0;                                                                         \
123*c99fb5f9SBaptiste Daroussin       while (_ls_p) {                                                                          \
124*c99fb5f9SBaptiste Daroussin         _ls_nmerges++;                                                                         \
125*c99fb5f9SBaptiste Daroussin         _ls_q = _ls_p;                                                                         \
126*c99fb5f9SBaptiste Daroussin         _ls_psize = 0;                                                                         \
127*c99fb5f9SBaptiste Daroussin         for (_ls_i = 0; _ls_i < _ls_insize; _ls_i++) {                                         \
128*c99fb5f9SBaptiste Daroussin           _ls_psize++;                                                                         \
129*c99fb5f9SBaptiste Daroussin           _SV(_ls_q,list); _ls_q = _NEXT(_ls_q,list,next); _RS(list);                          \
130*c99fb5f9SBaptiste Daroussin           if (!_ls_q) break;                                                                   \
131*c99fb5f9SBaptiste Daroussin         }                                                                                      \
132*c99fb5f9SBaptiste Daroussin         _ls_qsize = _ls_insize;                                                                \
133*c99fb5f9SBaptiste Daroussin         while (_ls_psize > 0 || (_ls_qsize > 0 && _ls_q)) {                                    \
134*c99fb5f9SBaptiste Daroussin           if (_ls_psize == 0) {                                                                \
135*c99fb5f9SBaptiste Daroussin             _ls_e = _ls_q; _SV(_ls_q,list); _ls_q =                                            \
136*c99fb5f9SBaptiste Daroussin               _NEXT(_ls_q,list,next); _RS(list); _ls_qsize--;                                  \
137*c99fb5f9SBaptiste Daroussin           } else if (_ls_qsize == 0 || !_ls_q) {                                               \
138*c99fb5f9SBaptiste Daroussin             _ls_e = _ls_p; _SV(_ls_p,list); _ls_p =                                            \
139*c99fb5f9SBaptiste Daroussin               _NEXT(_ls_p,list,next); _RS(list); _ls_psize--;                                  \
140*c99fb5f9SBaptiste Daroussin           } else if (cmp(_ls_p,_ls_q) <= 0) {                                                  \
141*c99fb5f9SBaptiste Daroussin             _ls_e = _ls_p; _SV(_ls_p,list); _ls_p =                                            \
142*c99fb5f9SBaptiste Daroussin               _NEXT(_ls_p,list,next); _RS(list); _ls_psize--;                                  \
143*c99fb5f9SBaptiste Daroussin           } else {                                                                             \
144*c99fb5f9SBaptiste Daroussin             _ls_e = _ls_q; _SV(_ls_q,list); _ls_q =                                            \
145*c99fb5f9SBaptiste Daroussin               _NEXT(_ls_q,list,next); _RS(list); _ls_qsize--;                                  \
146*c99fb5f9SBaptiste Daroussin           }                                                                                    \
147*c99fb5f9SBaptiste Daroussin           if (_ls_tail) {                                                                      \
148*c99fb5f9SBaptiste Daroussin             _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,_ls_e,next); _RS(list);                \
149*c99fb5f9SBaptiste Daroussin           } else {                                                                             \
150*c99fb5f9SBaptiste Daroussin             _CASTASGN(list,_ls_e);                                                             \
151*c99fb5f9SBaptiste Daroussin           }                                                                                    \
152*c99fb5f9SBaptiste Daroussin           _ls_tail = _ls_e;                                                                    \
153*c99fb5f9SBaptiste Daroussin         }                                                                                      \
154*c99fb5f9SBaptiste Daroussin         _ls_p = _ls_q;                                                                         \
155*c99fb5f9SBaptiste Daroussin       }                                                                                        \
156*c99fb5f9SBaptiste Daroussin       if (_ls_tail) {                                                                          \
157*c99fb5f9SBaptiste Daroussin         _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,NULL,next); _RS(list);                     \
158*c99fb5f9SBaptiste Daroussin       }                                                                                        \
159*c99fb5f9SBaptiste Daroussin       if (_ls_nmerges <= 1) {                                                                  \
160*c99fb5f9SBaptiste Daroussin         _ls_looping=0;                                                                         \
161*c99fb5f9SBaptiste Daroussin       }                                                                                        \
162*c99fb5f9SBaptiste Daroussin       _ls_insize *= 2;                                                                         \
163*c99fb5f9SBaptiste Daroussin     }                                                                                          \
164*c99fb5f9SBaptiste Daroussin   }                                                                                            \
165*c99fb5f9SBaptiste Daroussin } while (0)
166*c99fb5f9SBaptiste Daroussin 
167*c99fb5f9SBaptiste Daroussin 
168*c99fb5f9SBaptiste Daroussin #define DL_SORT(list, cmp)                                                                     \
169*c99fb5f9SBaptiste Daroussin     DL_SORT2(list, cmp, prev, next)
170*c99fb5f9SBaptiste Daroussin 
171*c99fb5f9SBaptiste Daroussin #define DL_SORT2(list, cmp, prev, next)                                                        \
172*c99fb5f9SBaptiste Daroussin do {                                                                                           \
173*c99fb5f9SBaptiste Daroussin   LDECLTYPE(list) _ls_p;                                                                       \
174*c99fb5f9SBaptiste Daroussin   LDECLTYPE(list) _ls_q;                                                                       \
175*c99fb5f9SBaptiste Daroussin   LDECLTYPE(list) _ls_e;                                                                       \
176*c99fb5f9SBaptiste Daroussin   LDECLTYPE(list) _ls_tail;                                                                    \
177*c99fb5f9SBaptiste Daroussin   int _ls_insize, _ls_nmerges, _ls_psize, _ls_qsize, _ls_i, _ls_looping;                       \
178*c99fb5f9SBaptiste Daroussin   if (list) {                                                                                  \
179*c99fb5f9SBaptiste Daroussin     _ls_insize = 1;                                                                            \
180*c99fb5f9SBaptiste Daroussin     _ls_looping = 1;                                                                           \
181*c99fb5f9SBaptiste Daroussin     while (_ls_looping) {                                                                      \
182*c99fb5f9SBaptiste Daroussin       _CASTASGN(_ls_p,list);                                                                   \
183*c99fb5f9SBaptiste Daroussin       list = NULL;                                                                             \
184*c99fb5f9SBaptiste Daroussin       _ls_tail = NULL;                                                                         \
185*c99fb5f9SBaptiste Daroussin       _ls_nmerges = 0;                                                                         \
186*c99fb5f9SBaptiste Daroussin       while (_ls_p) {                                                                          \
187*c99fb5f9SBaptiste Daroussin         _ls_nmerges++;                                                                         \
188*c99fb5f9SBaptiste Daroussin         _ls_q = _ls_p;                                                                         \
189*c99fb5f9SBaptiste Daroussin         _ls_psize = 0;                                                                         \
190*c99fb5f9SBaptiste Daroussin         for (_ls_i = 0; _ls_i < _ls_insize; _ls_i++) {                                         \
191*c99fb5f9SBaptiste Daroussin           _ls_psize++;                                                                         \
192*c99fb5f9SBaptiste Daroussin           _SV(_ls_q,list); _ls_q = _NEXT(_ls_q,list,next); _RS(list);                          \
193*c99fb5f9SBaptiste Daroussin           if (!_ls_q) break;                                                                   \
194*c99fb5f9SBaptiste Daroussin         }                                                                                      \
195*c99fb5f9SBaptiste Daroussin         _ls_qsize = _ls_insize;                                                                \
196*c99fb5f9SBaptiste Daroussin         while (_ls_psize > 0 || (_ls_qsize > 0 && _ls_q)) {                                    \
197*c99fb5f9SBaptiste Daroussin           if (_ls_psize == 0) {                                                                \
198*c99fb5f9SBaptiste Daroussin             _ls_e = _ls_q; _SV(_ls_q,list); _ls_q =                                            \
199*c99fb5f9SBaptiste Daroussin               _NEXT(_ls_q,list,next); _RS(list); _ls_qsize--;                                  \
200*c99fb5f9SBaptiste Daroussin           } else if (_ls_qsize == 0 || !_ls_q) {                                               \
201*c99fb5f9SBaptiste Daroussin             _ls_e = _ls_p; _SV(_ls_p,list); _ls_p =                                            \
202*c99fb5f9SBaptiste Daroussin               _NEXT(_ls_p,list,next); _RS(list); _ls_psize--;                                  \
203*c99fb5f9SBaptiste Daroussin           } else if (cmp(_ls_p,_ls_q) <= 0) {                                                  \
204*c99fb5f9SBaptiste Daroussin             _ls_e = _ls_p; _SV(_ls_p,list); _ls_p =                                            \
205*c99fb5f9SBaptiste Daroussin               _NEXT(_ls_p,list,next); _RS(list); _ls_psize--;                                  \
206*c99fb5f9SBaptiste Daroussin           } else {                                                                             \
207*c99fb5f9SBaptiste Daroussin             _ls_e = _ls_q; _SV(_ls_q,list); _ls_q =                                            \
208*c99fb5f9SBaptiste Daroussin               _NEXT(_ls_q,list,next); _RS(list); _ls_qsize--;                                  \
209*c99fb5f9SBaptiste Daroussin           }                                                                                    \
210*c99fb5f9SBaptiste Daroussin           if (_ls_tail) {                                                                      \
211*c99fb5f9SBaptiste Daroussin             _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,_ls_e,next); _RS(list);                \
212*c99fb5f9SBaptiste Daroussin           } else {                                                                             \
213*c99fb5f9SBaptiste Daroussin             _CASTASGN(list,_ls_e);                                                             \
214*c99fb5f9SBaptiste Daroussin           }                                                                                    \
215*c99fb5f9SBaptiste Daroussin           _SV(_ls_e,list); _PREVASGN(_ls_e,list,_ls_tail,prev); _RS(list);                     \
216*c99fb5f9SBaptiste Daroussin           _ls_tail = _ls_e;                                                                    \
217*c99fb5f9SBaptiste Daroussin         }                                                                                      \
218*c99fb5f9SBaptiste Daroussin         _ls_p = _ls_q;                                                                         \
219*c99fb5f9SBaptiste Daroussin       }                                                                                        \
220*c99fb5f9SBaptiste Daroussin       _CASTASGN(list->prev, _ls_tail);                                                         \
221*c99fb5f9SBaptiste Daroussin       _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,NULL,next); _RS(list);                       \
222*c99fb5f9SBaptiste Daroussin       if (_ls_nmerges <= 1) {                                                                  \
223*c99fb5f9SBaptiste Daroussin         _ls_looping=0;                                                                         \
224*c99fb5f9SBaptiste Daroussin       }                                                                                        \
225*c99fb5f9SBaptiste Daroussin       _ls_insize *= 2;                                                                         \
226*c99fb5f9SBaptiste Daroussin     }                                                                                          \
227*c99fb5f9SBaptiste Daroussin   }                                                                                            \
228*c99fb5f9SBaptiste Daroussin } while (0)
229*c99fb5f9SBaptiste Daroussin 
230*c99fb5f9SBaptiste Daroussin #define CDL_SORT(list, cmp)                                                                    \
231*c99fb5f9SBaptiste Daroussin     CDL_SORT2(list, cmp, prev, next)
232*c99fb5f9SBaptiste Daroussin 
233*c99fb5f9SBaptiste Daroussin #define CDL_SORT2(list, cmp, prev, next)                                                       \
234*c99fb5f9SBaptiste Daroussin do {                                                                                           \
235*c99fb5f9SBaptiste Daroussin   LDECLTYPE(list) _ls_p;                                                                       \
236*c99fb5f9SBaptiste Daroussin   LDECLTYPE(list) _ls_q;                                                                       \
237*c99fb5f9SBaptiste Daroussin   LDECLTYPE(list) _ls_e;                                                                       \
238*c99fb5f9SBaptiste Daroussin   LDECLTYPE(list) _ls_tail;                                                                    \
239*c99fb5f9SBaptiste Daroussin   LDECLTYPE(list) _ls_oldhead;                                                                 \
240*c99fb5f9SBaptiste Daroussin   LDECLTYPE(list) _tmp;                                                                        \
241*c99fb5f9SBaptiste Daroussin   int _ls_insize, _ls_nmerges, _ls_psize, _ls_qsize, _ls_i, _ls_looping;                       \
242*c99fb5f9SBaptiste Daroussin   if (list) {                                                                                  \
243*c99fb5f9SBaptiste Daroussin     _ls_insize = 1;                                                                            \
244*c99fb5f9SBaptiste Daroussin     _ls_looping = 1;                                                                           \
245*c99fb5f9SBaptiste Daroussin     while (_ls_looping) {                                                                      \
246*c99fb5f9SBaptiste Daroussin       _CASTASGN(_ls_p,list);                                                                   \
247*c99fb5f9SBaptiste Daroussin       _CASTASGN(_ls_oldhead,list);                                                             \
248*c99fb5f9SBaptiste Daroussin       list = NULL;                                                                             \
249*c99fb5f9SBaptiste Daroussin       _ls_tail = NULL;                                                                         \
250*c99fb5f9SBaptiste Daroussin       _ls_nmerges = 0;                                                                         \
251*c99fb5f9SBaptiste Daroussin       while (_ls_p) {                                                                          \
252*c99fb5f9SBaptiste Daroussin         _ls_nmerges++;                                                                         \
253*c99fb5f9SBaptiste Daroussin         _ls_q = _ls_p;                                                                         \
254*c99fb5f9SBaptiste Daroussin         _ls_psize = 0;                                                                         \
255*c99fb5f9SBaptiste Daroussin         for (_ls_i = 0; _ls_i < _ls_insize; _ls_i++) {                                         \
256*c99fb5f9SBaptiste Daroussin           _ls_psize++;                                                                         \
257*c99fb5f9SBaptiste Daroussin           _SV(_ls_q,list);                                                                     \
258*c99fb5f9SBaptiste Daroussin           if (_NEXT(_ls_q,list,next) == _ls_oldhead) {                                         \
259*c99fb5f9SBaptiste Daroussin             _ls_q = NULL;                                                                      \
260*c99fb5f9SBaptiste Daroussin           } else {                                                                             \
261*c99fb5f9SBaptiste Daroussin             _ls_q = _NEXT(_ls_q,list,next);                                                    \
262*c99fb5f9SBaptiste Daroussin           }                                                                                    \
263*c99fb5f9SBaptiste Daroussin           _RS(list);                                                                           \
264*c99fb5f9SBaptiste Daroussin           if (!_ls_q) break;                                                                   \
265*c99fb5f9SBaptiste Daroussin         }                                                                                      \
266*c99fb5f9SBaptiste Daroussin         _ls_qsize = _ls_insize;                                                                \
267*c99fb5f9SBaptiste Daroussin         while (_ls_psize > 0 || (_ls_qsize > 0 && _ls_q)) {                                    \
268*c99fb5f9SBaptiste Daroussin           if (_ls_psize == 0) {                                                                \
269*c99fb5f9SBaptiste Daroussin             _ls_e = _ls_q; _SV(_ls_q,list); _ls_q =                                            \
270*c99fb5f9SBaptiste Daroussin               _NEXT(_ls_q,list,next); _RS(list); _ls_qsize--;                                  \
271*c99fb5f9SBaptiste Daroussin             if (_ls_q == _ls_oldhead) { _ls_q = NULL; }                                        \
272*c99fb5f9SBaptiste Daroussin           } else if (_ls_qsize == 0 || !_ls_q) {                                               \
273*c99fb5f9SBaptiste Daroussin             _ls_e = _ls_p; _SV(_ls_p,list); _ls_p =                                            \
274*c99fb5f9SBaptiste Daroussin               _NEXT(_ls_p,list,next); _RS(list); _ls_psize--;                                  \
275*c99fb5f9SBaptiste Daroussin             if (_ls_p == _ls_oldhead) { _ls_p = NULL; }                                        \
276*c99fb5f9SBaptiste Daroussin           } else if (cmp(_ls_p,_ls_q) <= 0) {                                                  \
277*c99fb5f9SBaptiste Daroussin             _ls_e = _ls_p; _SV(_ls_p,list); _ls_p =                                            \
278*c99fb5f9SBaptiste Daroussin               _NEXT(_ls_p,list,next); _RS(list); _ls_psize--;                                  \
279*c99fb5f9SBaptiste Daroussin             if (_ls_p == _ls_oldhead) { _ls_p = NULL; }                                        \
280*c99fb5f9SBaptiste Daroussin           } else {                                                                             \
281*c99fb5f9SBaptiste Daroussin             _ls_e = _ls_q; _SV(_ls_q,list); _ls_q =                                            \
282*c99fb5f9SBaptiste Daroussin               _NEXT(_ls_q,list,next); _RS(list); _ls_qsize--;                                  \
283*c99fb5f9SBaptiste Daroussin             if (_ls_q == _ls_oldhead) { _ls_q = NULL; }                                        \
284*c99fb5f9SBaptiste Daroussin           }                                                                                    \
285*c99fb5f9SBaptiste Daroussin           if (_ls_tail) {                                                                      \
286*c99fb5f9SBaptiste Daroussin             _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,_ls_e,next); _RS(list);                \
287*c99fb5f9SBaptiste Daroussin           } else {                                                                             \
288*c99fb5f9SBaptiste Daroussin             _CASTASGN(list,_ls_e);                                                             \
289*c99fb5f9SBaptiste Daroussin           }                                                                                    \
290*c99fb5f9SBaptiste Daroussin           _SV(_ls_e,list); _PREVASGN(_ls_e,list,_ls_tail,prev); _RS(list);                     \
291*c99fb5f9SBaptiste Daroussin           _ls_tail = _ls_e;                                                                    \
292*c99fb5f9SBaptiste Daroussin         }                                                                                      \
293*c99fb5f9SBaptiste Daroussin         _ls_p = _ls_q;                                                                         \
294*c99fb5f9SBaptiste Daroussin       }                                                                                        \
295*c99fb5f9SBaptiste Daroussin       _CASTASGN(list->prev,_ls_tail);                                                          \
296*c99fb5f9SBaptiste Daroussin       _CASTASGN(_tmp,list);                                                                    \
297*c99fb5f9SBaptiste Daroussin       _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,_tmp,next); _RS(list);                       \
298*c99fb5f9SBaptiste Daroussin       if (_ls_nmerges <= 1) {                                                                  \
299*c99fb5f9SBaptiste Daroussin         _ls_looping=0;                                                                         \
300*c99fb5f9SBaptiste Daroussin       }                                                                                        \
301*c99fb5f9SBaptiste Daroussin       _ls_insize *= 2;                                                                         \
302*c99fb5f9SBaptiste Daroussin     }                                                                                          \
303*c99fb5f9SBaptiste Daroussin   }                                                                                            \
304*c99fb5f9SBaptiste Daroussin } while (0)
305*c99fb5f9SBaptiste Daroussin 
306*c99fb5f9SBaptiste Daroussin /******************************************************************************
307*c99fb5f9SBaptiste Daroussin  * singly linked list macros (non-circular)                                   *
308*c99fb5f9SBaptiste Daroussin  *****************************************************************************/
309*c99fb5f9SBaptiste Daroussin #define LL_PREPEND(head,add)                                                                   \
310*c99fb5f9SBaptiste Daroussin     LL_PREPEND2(head,add,next)
311*c99fb5f9SBaptiste Daroussin 
312*c99fb5f9SBaptiste Daroussin #define LL_PREPEND2(head,add,next)                                                             \
313*c99fb5f9SBaptiste Daroussin do {                                                                                           \
314*c99fb5f9SBaptiste Daroussin   (add)->next = head;                                                                          \
315*c99fb5f9SBaptiste Daroussin   head = add;                                                                                  \
316*c99fb5f9SBaptiste Daroussin } while (0)
317*c99fb5f9SBaptiste Daroussin 
318*c99fb5f9SBaptiste Daroussin #define LL_CONCAT(head1,head2)                                                                 \
319*c99fb5f9SBaptiste Daroussin     LL_CONCAT2(head1,head2,next)
320*c99fb5f9SBaptiste Daroussin 
321*c99fb5f9SBaptiste Daroussin #define LL_CONCAT2(head1,head2,next)                                                           \
322*c99fb5f9SBaptiste Daroussin do {                                                                                           \
323*c99fb5f9SBaptiste Daroussin   LDECLTYPE(head1) _tmp;                                                                       \
324*c99fb5f9SBaptiste Daroussin   if (head1) {                                                                                 \
325*c99fb5f9SBaptiste Daroussin     _tmp = head1;                                                                              \
326*c99fb5f9SBaptiste Daroussin     while (_tmp->next) { _tmp = _tmp->next; }                                                  \
327*c99fb5f9SBaptiste Daroussin     _tmp->next=(head2);                                                                        \
328*c99fb5f9SBaptiste Daroussin   } else {                                                                                     \
329*c99fb5f9SBaptiste Daroussin     (head1)=(head2);                                                                           \
330*c99fb5f9SBaptiste Daroussin   }                                                                                            \
331*c99fb5f9SBaptiste Daroussin } while (0)
332*c99fb5f9SBaptiste Daroussin 
333*c99fb5f9SBaptiste Daroussin #define LL_APPEND(head,add)                                                                    \
334*c99fb5f9SBaptiste Daroussin     LL_APPEND2(head,add,next)
335*c99fb5f9SBaptiste Daroussin 
336*c99fb5f9SBaptiste Daroussin #define LL_APPEND2(head,add,next)                                                              \
337*c99fb5f9SBaptiste Daroussin do {                                                                                           \
338*c99fb5f9SBaptiste Daroussin   LDECLTYPE(head) _tmp;                                                                        \
339*c99fb5f9SBaptiste Daroussin   (add)->next=NULL;                                                                            \
340*c99fb5f9SBaptiste Daroussin   if (head) {                                                                                  \
341*c99fb5f9SBaptiste Daroussin     _tmp = head;                                                                               \
342*c99fb5f9SBaptiste Daroussin     while (_tmp->next) { _tmp = _tmp->next; }                                                  \
343*c99fb5f9SBaptiste Daroussin     _tmp->next=(add);                                                                          \
344*c99fb5f9SBaptiste Daroussin   } else {                                                                                     \
345*c99fb5f9SBaptiste Daroussin     (head)=(add);                                                                              \
346*c99fb5f9SBaptiste Daroussin   }                                                                                            \
347*c99fb5f9SBaptiste Daroussin } while (0)
348*c99fb5f9SBaptiste Daroussin 
349*c99fb5f9SBaptiste Daroussin #define LL_DELETE(head,del)                                                                    \
350*c99fb5f9SBaptiste Daroussin     LL_DELETE2(head,del,next)
351*c99fb5f9SBaptiste Daroussin 
352*c99fb5f9SBaptiste Daroussin #define LL_DELETE2(head,del,next)                                                              \
353*c99fb5f9SBaptiste Daroussin do {                                                                                           \
354*c99fb5f9SBaptiste Daroussin   LDECLTYPE(head) _tmp;                                                                        \
355*c99fb5f9SBaptiste Daroussin   if ((head) == (del)) {                                                                       \
356*c99fb5f9SBaptiste Daroussin     (head)=(head)->next;                                                                       \
357*c99fb5f9SBaptiste Daroussin   } else {                                                                                     \
358*c99fb5f9SBaptiste Daroussin     _tmp = head;                                                                               \
359*c99fb5f9SBaptiste Daroussin     while (_tmp->next && (_tmp->next != (del))) {                                              \
360*c99fb5f9SBaptiste Daroussin       _tmp = _tmp->next;                                                                       \
361*c99fb5f9SBaptiste Daroussin     }                                                                                          \
362*c99fb5f9SBaptiste Daroussin     if (_tmp->next) {                                                                          \
363*c99fb5f9SBaptiste Daroussin       _tmp->next = ((del)->next);                                                              \
364*c99fb5f9SBaptiste Daroussin     }                                                                                          \
365*c99fb5f9SBaptiste Daroussin   }                                                                                            \
366*c99fb5f9SBaptiste Daroussin } while (0)
367*c99fb5f9SBaptiste Daroussin 
368*c99fb5f9SBaptiste Daroussin /* Here are VS2008 replacements for LL_APPEND and LL_DELETE */
369*c99fb5f9SBaptiste Daroussin #define LL_APPEND_VS2008(head,add)                                                             \
370*c99fb5f9SBaptiste Daroussin     LL_APPEND2_VS2008(head,add,next)
371*c99fb5f9SBaptiste Daroussin 
372*c99fb5f9SBaptiste Daroussin #define LL_APPEND2_VS2008(head,add,next)                                                       \
373*c99fb5f9SBaptiste Daroussin do {                                                                                           \
374*c99fb5f9SBaptiste Daroussin   if (head) {                                                                                  \
375*c99fb5f9SBaptiste Daroussin     (add)->next = head;     /* use add->next as a temp variable */                             \
376*c99fb5f9SBaptiste Daroussin     while ((add)->next->next) { (add)->next = (add)->next->next; }                             \
377*c99fb5f9SBaptiste Daroussin     (add)->next->next=(add);                                                                   \
378*c99fb5f9SBaptiste Daroussin   } else {                                                                                     \
379*c99fb5f9SBaptiste Daroussin     (head)=(add);                                                                              \
380*c99fb5f9SBaptiste Daroussin   }                                                                                            \
381*c99fb5f9SBaptiste Daroussin   (add)->next=NULL;                                                                            \
382*c99fb5f9SBaptiste Daroussin } while (0)
383*c99fb5f9SBaptiste Daroussin 
384*c99fb5f9SBaptiste Daroussin #define LL_DELETE_VS2008(head,del)                                                             \
385*c99fb5f9SBaptiste Daroussin     LL_DELETE2_VS2008(head,del,next)
386*c99fb5f9SBaptiste Daroussin 
387*c99fb5f9SBaptiste Daroussin #define LL_DELETE2_VS2008(head,del,next)                                                       \
388*c99fb5f9SBaptiste Daroussin do {                                                                                           \
389*c99fb5f9SBaptiste Daroussin   if ((head) == (del)) {                                                                       \
390*c99fb5f9SBaptiste Daroussin     (head)=(head)->next;                                                                       \
391*c99fb5f9SBaptiste Daroussin   } else {                                                                                     \
392*c99fb5f9SBaptiste Daroussin     char *_tmp = (char*)(head);                                                                \
393*c99fb5f9SBaptiste Daroussin     while ((head)->next && ((head)->next != (del))) {                                          \
394*c99fb5f9SBaptiste Daroussin       head = (head)->next;                                                                     \
395*c99fb5f9SBaptiste Daroussin     }                                                                                          \
396*c99fb5f9SBaptiste Daroussin     if ((head)->next) {                                                                        \
397*c99fb5f9SBaptiste Daroussin       (head)->next = ((del)->next);                                                            \
398*c99fb5f9SBaptiste Daroussin     }                                                                                          \
399*c99fb5f9SBaptiste Daroussin     {                                                                                          \
400*c99fb5f9SBaptiste Daroussin       char **_head_alias = (char**)&(head);                                                    \
401*c99fb5f9SBaptiste Daroussin       *_head_alias = _tmp;                                                                     \
402*c99fb5f9SBaptiste Daroussin     }                                                                                          \
403*c99fb5f9SBaptiste Daroussin   }                                                                                            \
404*c99fb5f9SBaptiste Daroussin } while (0)
405*c99fb5f9SBaptiste Daroussin #ifdef NO_DECLTYPE
406*c99fb5f9SBaptiste Daroussin #undef LL_APPEND
407*c99fb5f9SBaptiste Daroussin #define LL_APPEND LL_APPEND_VS2008
408*c99fb5f9SBaptiste Daroussin #undef LL_DELETE
409*c99fb5f9SBaptiste Daroussin #define LL_DELETE LL_DELETE_VS2008
410*c99fb5f9SBaptiste Daroussin #undef LL_DELETE2
411*c99fb5f9SBaptiste Daroussin #define LL_DELETE2 LL_DELETE2_VS2008
412*c99fb5f9SBaptiste Daroussin #undef LL_APPEND2
413*c99fb5f9SBaptiste Daroussin #define LL_APPEND2 LL_APPEND2_VS2008
414*c99fb5f9SBaptiste Daroussin #undef LL_CONCAT /* no LL_CONCAT_VS2008 */
415*c99fb5f9SBaptiste Daroussin #undef DL_CONCAT /* no DL_CONCAT_VS2008 */
416*c99fb5f9SBaptiste Daroussin #endif
417*c99fb5f9SBaptiste Daroussin /* end VS2008 replacements */
418*c99fb5f9SBaptiste Daroussin 
419*c99fb5f9SBaptiste Daroussin #define LL_COUNT(head,el,counter)                                                              \
420*c99fb5f9SBaptiste Daroussin     LL_COUNT2(head,el,counter,next)                                                            \
421*c99fb5f9SBaptiste Daroussin 
422*c99fb5f9SBaptiste Daroussin #define LL_COUNT2(head,el,counter,next)                                                        \
423*c99fb5f9SBaptiste Daroussin {                                                                                              \
424*c99fb5f9SBaptiste Daroussin     counter = 0;                                                                               \
425*c99fb5f9SBaptiste Daroussin     LL_FOREACH2(head,el,next){ ++counter; }                                                    \
426*c99fb5f9SBaptiste Daroussin }
427*c99fb5f9SBaptiste Daroussin 
428*c99fb5f9SBaptiste Daroussin #define LL_FOREACH(head,el)                                                                    \
429*c99fb5f9SBaptiste Daroussin     LL_FOREACH2(head,el,next)
430*c99fb5f9SBaptiste Daroussin 
431*c99fb5f9SBaptiste Daroussin #define LL_FOREACH2(head,el,next)                                                              \
432*c99fb5f9SBaptiste Daroussin     for(el=head;el;el=(el)->next)
433*c99fb5f9SBaptiste Daroussin 
434*c99fb5f9SBaptiste Daroussin #define LL_FOREACH_SAFE(head,el,tmp)                                                           \
435*c99fb5f9SBaptiste Daroussin     LL_FOREACH_SAFE2(head,el,tmp,next)
436*c99fb5f9SBaptiste Daroussin 
437*c99fb5f9SBaptiste Daroussin #define LL_FOREACH_SAFE2(head,el,tmp,next)                                                     \
438*c99fb5f9SBaptiste Daroussin   for((el)=(head);(el) && (tmp = (el)->next, 1); (el) = tmp)
439*c99fb5f9SBaptiste Daroussin 
440*c99fb5f9SBaptiste Daroussin #define LL_SEARCH_SCALAR(head,out,field,val)                                                   \
441*c99fb5f9SBaptiste Daroussin     LL_SEARCH_SCALAR2(head,out,field,val,next)
442*c99fb5f9SBaptiste Daroussin 
443*c99fb5f9SBaptiste Daroussin #define LL_SEARCH_SCALAR2(head,out,field,val,next)                                             \
444*c99fb5f9SBaptiste Daroussin do {                                                                                           \
445*c99fb5f9SBaptiste Daroussin     LL_FOREACH2(head,out,next) {                                                               \
446*c99fb5f9SBaptiste Daroussin       if ((out)->field == (val)) break;                                                        \
447*c99fb5f9SBaptiste Daroussin     }                                                                                          \
448*c99fb5f9SBaptiste Daroussin } while(0)
449*c99fb5f9SBaptiste Daroussin 
450*c99fb5f9SBaptiste Daroussin #define LL_SEARCH(head,out,elt,cmp)                                                            \
451*c99fb5f9SBaptiste Daroussin     LL_SEARCH2(head,out,elt,cmp,next)
452*c99fb5f9SBaptiste Daroussin 
453*c99fb5f9SBaptiste Daroussin #define LL_SEARCH2(head,out,elt,cmp,next)                                                      \
454*c99fb5f9SBaptiste Daroussin do {                                                                                           \
455*c99fb5f9SBaptiste Daroussin     LL_FOREACH2(head,out,next) {                                                               \
456*c99fb5f9SBaptiste Daroussin       if ((cmp(out,elt))==0) break;                                                            \
457*c99fb5f9SBaptiste Daroussin     }                                                                                          \
458*c99fb5f9SBaptiste Daroussin } while(0)
459*c99fb5f9SBaptiste Daroussin 
460*c99fb5f9SBaptiste Daroussin #define LL_REPLACE_ELEM(head, el, add)                                                         \
461*c99fb5f9SBaptiste Daroussin do {                                                                                           \
462*c99fb5f9SBaptiste Daroussin  LDECLTYPE(head) _tmp;                                                                         \
463*c99fb5f9SBaptiste Daroussin  assert(head != NULL);                                                                         \
464*c99fb5f9SBaptiste Daroussin  assert(el != NULL);                                                                           \
465*c99fb5f9SBaptiste Daroussin  assert(add != NULL);                                                                          \
466*c99fb5f9SBaptiste Daroussin  (add)->next = (el)->next;                                                                     \
467*c99fb5f9SBaptiste Daroussin  if ((head) == (el)) {                                                                         \
468*c99fb5f9SBaptiste Daroussin   (head) = (add);                                                                              \
469*c99fb5f9SBaptiste Daroussin  } else {                                                                                      \
470*c99fb5f9SBaptiste Daroussin   _tmp = head;                                                                                 \
471*c99fb5f9SBaptiste Daroussin   while (_tmp->next && (_tmp->next != (el))) {                                                 \
472*c99fb5f9SBaptiste Daroussin    _tmp = _tmp->next;                                                                          \
473*c99fb5f9SBaptiste Daroussin   }                                                                                            \
474*c99fb5f9SBaptiste Daroussin   if (_tmp->next) {                                                                            \
475*c99fb5f9SBaptiste Daroussin     _tmp->next = (add);                                                                        \
476*c99fb5f9SBaptiste Daroussin   }                                                                                            \
477*c99fb5f9SBaptiste Daroussin  }                                                                                             \
478*c99fb5f9SBaptiste Daroussin } while (0)
479*c99fb5f9SBaptiste Daroussin 
480*c99fb5f9SBaptiste Daroussin #define LL_PREPEND_ELEM(head, el, add)                                                         \
481*c99fb5f9SBaptiste Daroussin do {                                                                                           \
482*c99fb5f9SBaptiste Daroussin  LDECLTYPE(head) _tmp;                                                                         \
483*c99fb5f9SBaptiste Daroussin  assert(head != NULL);                                                                         \
484*c99fb5f9SBaptiste Daroussin  assert(el != NULL);                                                                           \
485*c99fb5f9SBaptiste Daroussin  assert(add != NULL);                                                                          \
486*c99fb5f9SBaptiste Daroussin  (add)->next = (el);                                                                           \
487*c99fb5f9SBaptiste Daroussin  if ((head) == (el)) {                                                                         \
488*c99fb5f9SBaptiste Daroussin   (head) = (add);                                                                              \
489*c99fb5f9SBaptiste Daroussin  } else {                                                                                      \
490*c99fb5f9SBaptiste Daroussin   _tmp = head;                                                                                 \
491*c99fb5f9SBaptiste Daroussin   while (_tmp->next && (_tmp->next != (el))) {                                                 \
492*c99fb5f9SBaptiste Daroussin    _tmp = _tmp->next;                                                                          \
493*c99fb5f9SBaptiste Daroussin   }                                                                                            \
494*c99fb5f9SBaptiste Daroussin   if (_tmp->next) {                                                                            \
495*c99fb5f9SBaptiste Daroussin     _tmp->next = (add);                                                                        \
496*c99fb5f9SBaptiste Daroussin   }                                                                                            \
497*c99fb5f9SBaptiste Daroussin  }                                                                                             \
498*c99fb5f9SBaptiste Daroussin } while (0)                                                                                    \
499*c99fb5f9SBaptiste Daroussin 
500*c99fb5f9SBaptiste Daroussin 
501*c99fb5f9SBaptiste Daroussin /******************************************************************************
502*c99fb5f9SBaptiste Daroussin  * doubly linked list macros (non-circular)                                   *
503*c99fb5f9SBaptiste Daroussin  *****************************************************************************/
504*c99fb5f9SBaptiste Daroussin #define DL_PREPEND(head,add)                                                                   \
505*c99fb5f9SBaptiste Daroussin     DL_PREPEND2(head,add,prev,next)
506*c99fb5f9SBaptiste Daroussin 
507*c99fb5f9SBaptiste Daroussin #define DL_PREPEND2(head,add,prev,next)                                                        \
508*c99fb5f9SBaptiste Daroussin do {                                                                                           \
509*c99fb5f9SBaptiste Daroussin  (add)->next = head;                                                                           \
510*c99fb5f9SBaptiste Daroussin  if (head) {                                                                                   \
511*c99fb5f9SBaptiste Daroussin    (add)->prev = (head)->prev;                                                                 \
512*c99fb5f9SBaptiste Daroussin    (head)->prev = (add);                                                                       \
513*c99fb5f9SBaptiste Daroussin  } else {                                                                                      \
514*c99fb5f9SBaptiste Daroussin    (add)->prev = (add);                                                                        \
515*c99fb5f9SBaptiste Daroussin  }                                                                                             \
516*c99fb5f9SBaptiste Daroussin  (head) = (add);                                                                               \
517*c99fb5f9SBaptiste Daroussin } while (0)
518*c99fb5f9SBaptiste Daroussin 
519*c99fb5f9SBaptiste Daroussin #define DL_APPEND(head,add)                                                                    \
520*c99fb5f9SBaptiste Daroussin     DL_APPEND2(head,add,prev,next)
521*c99fb5f9SBaptiste Daroussin 
522*c99fb5f9SBaptiste Daroussin #define DL_APPEND2(head,add,prev,next)                                                         \
523*c99fb5f9SBaptiste Daroussin do {                                                                                           \
524*c99fb5f9SBaptiste Daroussin   if (head) {                                                                                  \
525*c99fb5f9SBaptiste Daroussin       (add)->prev = (head)->prev;                                                              \
526*c99fb5f9SBaptiste Daroussin       (head)->prev->next = (add);                                                              \
527*c99fb5f9SBaptiste Daroussin       (head)->prev = (add);                                                                    \
528*c99fb5f9SBaptiste Daroussin       (add)->next = NULL;                                                                      \
529*c99fb5f9SBaptiste Daroussin   } else {                                                                                     \
530*c99fb5f9SBaptiste Daroussin       (head)=(add);                                                                            \
531*c99fb5f9SBaptiste Daroussin       (head)->prev = (head);                                                                   \
532*c99fb5f9SBaptiste Daroussin       (head)->next = NULL;                                                                     \
533*c99fb5f9SBaptiste Daroussin   }                                                                                            \
534*c99fb5f9SBaptiste Daroussin } while (0)
535*c99fb5f9SBaptiste Daroussin 
536*c99fb5f9SBaptiste Daroussin #define DL_CONCAT(head1,head2)                                                                 \
537*c99fb5f9SBaptiste Daroussin     DL_CONCAT2(head1,head2,prev,next)
538*c99fb5f9SBaptiste Daroussin 
539*c99fb5f9SBaptiste Daroussin #define DL_CONCAT2(head1,head2,prev,next)                                                      \
540*c99fb5f9SBaptiste Daroussin do {                                                                                           \
541*c99fb5f9SBaptiste Daroussin   LDECLTYPE(head1) _tmp;                                                                       \
542*c99fb5f9SBaptiste Daroussin   if (head2) {                                                                                 \
543*c99fb5f9SBaptiste Daroussin     if (head1) {                                                                               \
544*c99fb5f9SBaptiste Daroussin         _tmp = (head2)->prev;                                                                  \
545*c99fb5f9SBaptiste Daroussin         (head2)->prev = (head1)->prev;                                                         \
546*c99fb5f9SBaptiste Daroussin         (head1)->prev->next = (head2);                                                         \
547*c99fb5f9SBaptiste Daroussin         (head1)->prev = _tmp;                                                                  \
548*c99fb5f9SBaptiste Daroussin     } else {                                                                                   \
549*c99fb5f9SBaptiste Daroussin         (head1)=(head2);                                                                       \
550*c99fb5f9SBaptiste Daroussin     }                                                                                          \
551*c99fb5f9SBaptiste Daroussin   }                                                                                            \
552*c99fb5f9SBaptiste Daroussin } while (0)
553*c99fb5f9SBaptiste Daroussin 
554*c99fb5f9SBaptiste Daroussin #define DL_DELETE(head,del)                                                                    \
555*c99fb5f9SBaptiste Daroussin     DL_DELETE2(head,del,prev,next)
556*c99fb5f9SBaptiste Daroussin 
557*c99fb5f9SBaptiste Daroussin #define DL_DELETE2(head,del,prev,next)                                                         \
558*c99fb5f9SBaptiste Daroussin do {                                                                                           \
559*c99fb5f9SBaptiste Daroussin   assert((del)->prev != NULL);                                                                 \
560*c99fb5f9SBaptiste Daroussin   if ((del)->prev == (del)) {                                                                  \
561*c99fb5f9SBaptiste Daroussin       (head)=NULL;                                                                             \
562*c99fb5f9SBaptiste Daroussin   } else if ((del)==(head)) {                                                                  \
563*c99fb5f9SBaptiste Daroussin       (del)->next->prev = (del)->prev;                                                         \
564*c99fb5f9SBaptiste Daroussin       (head) = (del)->next;                                                                    \
565*c99fb5f9SBaptiste Daroussin   } else {                                                                                     \
566*c99fb5f9SBaptiste Daroussin       (del)->prev->next = (del)->next;                                                         \
567*c99fb5f9SBaptiste Daroussin       if ((del)->next) {                                                                       \
568*c99fb5f9SBaptiste Daroussin           (del)->next->prev = (del)->prev;                                                     \
569*c99fb5f9SBaptiste Daroussin       } else {                                                                                 \
570*c99fb5f9SBaptiste Daroussin           (head)->prev = (del)->prev;                                                          \
571*c99fb5f9SBaptiste Daroussin       }                                                                                        \
572*c99fb5f9SBaptiste Daroussin   }                                                                                            \
573*c99fb5f9SBaptiste Daroussin } while (0)
574*c99fb5f9SBaptiste Daroussin 
575*c99fb5f9SBaptiste Daroussin #define DL_COUNT(head,el,counter)                                                              \
576*c99fb5f9SBaptiste Daroussin     DL_COUNT2(head,el,counter,next)                                                            \
577*c99fb5f9SBaptiste Daroussin 
578*c99fb5f9SBaptiste Daroussin #define DL_COUNT2(head,el,counter,next)                                                        \
579*c99fb5f9SBaptiste Daroussin {                                                                                              \
580*c99fb5f9SBaptiste Daroussin     counter = 0;                                                                               \
581*c99fb5f9SBaptiste Daroussin     DL_FOREACH2(head,el,next){ ++counter; }                                                    \
582*c99fb5f9SBaptiste Daroussin }
583*c99fb5f9SBaptiste Daroussin 
584*c99fb5f9SBaptiste Daroussin #define DL_FOREACH(head,el)                                                                    \
585*c99fb5f9SBaptiste Daroussin     DL_FOREACH2(head,el,next)
586*c99fb5f9SBaptiste Daroussin 
587*c99fb5f9SBaptiste Daroussin #define DL_FOREACH2(head,el,next)                                                              \
588*c99fb5f9SBaptiste Daroussin     for(el=head;el;el=(el)->next)
589*c99fb5f9SBaptiste Daroussin 
590*c99fb5f9SBaptiste Daroussin /* this version is safe for deleting the elements during iteration */
591*c99fb5f9SBaptiste Daroussin #define DL_FOREACH_SAFE(head,el,tmp)                                                           \
592*c99fb5f9SBaptiste Daroussin     DL_FOREACH_SAFE2(head,el,tmp,next)
593*c99fb5f9SBaptiste Daroussin 
594*c99fb5f9SBaptiste Daroussin #define DL_FOREACH_SAFE2(head,el,tmp,next)                                                     \
595*c99fb5f9SBaptiste Daroussin   for((el)=(head);(el) && (tmp = (el)->next, 1); (el) = tmp)
596*c99fb5f9SBaptiste Daroussin 
597*c99fb5f9SBaptiste Daroussin /* these are identical to their singly-linked list counterparts */
598*c99fb5f9SBaptiste Daroussin #define DL_SEARCH_SCALAR LL_SEARCH_SCALAR
599*c99fb5f9SBaptiste Daroussin #define DL_SEARCH LL_SEARCH
600*c99fb5f9SBaptiste Daroussin #define DL_SEARCH_SCALAR2 LL_SEARCH_SCALAR2
601*c99fb5f9SBaptiste Daroussin #define DL_SEARCH2 LL_SEARCH2
602*c99fb5f9SBaptiste Daroussin 
603*c99fb5f9SBaptiste Daroussin #define DL_REPLACE_ELEM(head, el, add)                                                         \
604*c99fb5f9SBaptiste Daroussin do {                                                                                           \
605*c99fb5f9SBaptiste Daroussin  assert(head != NULL);                                                                         \
606*c99fb5f9SBaptiste Daroussin  assert(el != NULL);                                                                           \
607*c99fb5f9SBaptiste Daroussin  assert(add != NULL);                                                                          \
608*c99fb5f9SBaptiste Daroussin  if ((head) == (el)) {                                                                         \
609*c99fb5f9SBaptiste Daroussin   (head) = (add);                                                                              \
610*c99fb5f9SBaptiste Daroussin   (add)->next = (el)->next;                                                                    \
611*c99fb5f9SBaptiste Daroussin   if ((el)->next == NULL) {                                                                    \
612*c99fb5f9SBaptiste Daroussin    (add)->prev = (add);                                                                        \
613*c99fb5f9SBaptiste Daroussin   } else {                                                                                     \
614*c99fb5f9SBaptiste Daroussin    (add)->prev = (el)->prev;                                                                   \
615*c99fb5f9SBaptiste Daroussin    (add)->next->prev = (add);                                                                  \
616*c99fb5f9SBaptiste Daroussin   }                                                                                            \
617*c99fb5f9SBaptiste Daroussin  } else {                                                                                      \
618*c99fb5f9SBaptiste Daroussin   (add)->next = (el)->next;                                                                    \
619*c99fb5f9SBaptiste Daroussin   (add)->prev = (el)->prev;                                                                    \
620*c99fb5f9SBaptiste Daroussin   (add)->prev->next = (add);                                                                   \
621*c99fb5f9SBaptiste Daroussin   if ((el)->next == NULL) {                                                                    \
622*c99fb5f9SBaptiste Daroussin    (head)->prev = (add);                                                                       \
623*c99fb5f9SBaptiste Daroussin   } else {                                                                                     \
624*c99fb5f9SBaptiste Daroussin    (add)->next->prev = (add);                                                                  \
625*c99fb5f9SBaptiste Daroussin   }                                                                                            \
626*c99fb5f9SBaptiste Daroussin  }                                                                                             \
627*c99fb5f9SBaptiste Daroussin } while (0)
628*c99fb5f9SBaptiste Daroussin 
629*c99fb5f9SBaptiste Daroussin #define DL_PREPEND_ELEM(head, el, add)                                                         \
630*c99fb5f9SBaptiste Daroussin do {                                                                                           \
631*c99fb5f9SBaptiste Daroussin  assert(head != NULL);                                                                         \
632*c99fb5f9SBaptiste Daroussin  assert(el != NULL);                                                                           \
633*c99fb5f9SBaptiste Daroussin  assert(add != NULL);                                                                          \
634*c99fb5f9SBaptiste Daroussin  (add)->next = (el);                                                                           \
635*c99fb5f9SBaptiste Daroussin  (add)->prev = (el)->prev;                                                                     \
636*c99fb5f9SBaptiste Daroussin  (el)->prev = (add);                                                                           \
637*c99fb5f9SBaptiste Daroussin  if ((head) == (el)) {                                                                         \
638*c99fb5f9SBaptiste Daroussin   (head) = (add);                                                                              \
639*c99fb5f9SBaptiste Daroussin  } else {                                                                                      \
640*c99fb5f9SBaptiste Daroussin   (add)->prev->next = (add);                                                                   \
641*c99fb5f9SBaptiste Daroussin  }                                                                                             \
642*c99fb5f9SBaptiste Daroussin } while (0)                                                                                    \
643*c99fb5f9SBaptiste Daroussin 
644*c99fb5f9SBaptiste Daroussin 
645*c99fb5f9SBaptiste Daroussin /******************************************************************************
646*c99fb5f9SBaptiste Daroussin  * circular doubly linked list macros                                         *
647*c99fb5f9SBaptiste Daroussin  *****************************************************************************/
648*c99fb5f9SBaptiste Daroussin #define CDL_PREPEND(head,add)                                                                  \
649*c99fb5f9SBaptiste Daroussin     CDL_PREPEND2(head,add,prev,next)
650*c99fb5f9SBaptiste Daroussin 
651*c99fb5f9SBaptiste Daroussin #define CDL_PREPEND2(head,add,prev,next)                                                       \
652*c99fb5f9SBaptiste Daroussin do {                                                                                           \
653*c99fb5f9SBaptiste Daroussin  if (head) {                                                                                   \
654*c99fb5f9SBaptiste Daroussin    (add)->prev = (head)->prev;                                                                 \
655*c99fb5f9SBaptiste Daroussin    (add)->next = (head);                                                                       \
656*c99fb5f9SBaptiste Daroussin    (head)->prev = (add);                                                                       \
657*c99fb5f9SBaptiste Daroussin    (add)->prev->next = (add);                                                                  \
658*c99fb5f9SBaptiste Daroussin  } else {                                                                                      \
659*c99fb5f9SBaptiste Daroussin    (add)->prev = (add);                                                                        \
660*c99fb5f9SBaptiste Daroussin    (add)->next = (add);                                                                        \
661*c99fb5f9SBaptiste Daroussin  }                                                                                             \
662*c99fb5f9SBaptiste Daroussin (head)=(add);                                                                                  \
663*c99fb5f9SBaptiste Daroussin } while (0)
664*c99fb5f9SBaptiste Daroussin 
665*c99fb5f9SBaptiste Daroussin #define CDL_DELETE(head,del)                                                                   \
666*c99fb5f9SBaptiste Daroussin     CDL_DELETE2(head,del,prev,next)
667*c99fb5f9SBaptiste Daroussin 
668*c99fb5f9SBaptiste Daroussin #define CDL_DELETE2(head,del,prev,next)                                                        \
669*c99fb5f9SBaptiste Daroussin do {                                                                                           \
670*c99fb5f9SBaptiste Daroussin   if ( ((head)==(del)) && ((head)->next == (head))) {                                          \
671*c99fb5f9SBaptiste Daroussin       (head) = 0L;                                                                             \
672*c99fb5f9SBaptiste Daroussin   } else {                                                                                     \
673*c99fb5f9SBaptiste Daroussin      (del)->next->prev = (del)->prev;                                                          \
674*c99fb5f9SBaptiste Daroussin      (del)->prev->next = (del)->next;                                                          \
675*c99fb5f9SBaptiste Daroussin      if ((del) == (head)) (head)=(del)->next;                                                  \
676*c99fb5f9SBaptiste Daroussin   }                                                                                            \
677*c99fb5f9SBaptiste Daroussin } while (0)
678*c99fb5f9SBaptiste Daroussin 
679*c99fb5f9SBaptiste Daroussin #define CDL_COUNT(head,el,counter)                                                             \
680*c99fb5f9SBaptiste Daroussin     CDL_COUNT2(head,el,counter,next)                                                           \
681*c99fb5f9SBaptiste Daroussin 
682*c99fb5f9SBaptiste Daroussin #define CDL_COUNT2(head, el, counter,next)                                                     \
683*c99fb5f9SBaptiste Daroussin {                                                                                              \
684*c99fb5f9SBaptiste Daroussin     counter = 0;                                                                               \
685*c99fb5f9SBaptiste Daroussin     CDL_FOREACH2(head,el,next){ ++counter; }                                                   \
686*c99fb5f9SBaptiste Daroussin }
687*c99fb5f9SBaptiste Daroussin 
688*c99fb5f9SBaptiste Daroussin #define CDL_FOREACH(head,el)                                                                   \
689*c99fb5f9SBaptiste Daroussin     CDL_FOREACH2(head,el,next)
690*c99fb5f9SBaptiste Daroussin 
691*c99fb5f9SBaptiste Daroussin #define CDL_FOREACH2(head,el,next)                                                             \
692*c99fb5f9SBaptiste Daroussin     for(el=head;el;el=((el)->next==head ? 0L : (el)->next))
693*c99fb5f9SBaptiste Daroussin 
694*c99fb5f9SBaptiste Daroussin #define CDL_FOREACH_SAFE(head,el,tmp1,tmp2)                                                    \
695*c99fb5f9SBaptiste Daroussin     CDL_FOREACH_SAFE2(head,el,tmp1,tmp2,prev,next)
696*c99fb5f9SBaptiste Daroussin 
697*c99fb5f9SBaptiste Daroussin #define CDL_FOREACH_SAFE2(head,el,tmp1,tmp2,prev,next)                                         \
698*c99fb5f9SBaptiste Daroussin   for((el)=(head), ((tmp1)=(head)?((head)->prev):NULL);                                        \
699*c99fb5f9SBaptiste Daroussin       (el) && ((tmp2)=(el)->next, 1);                                                          \
700*c99fb5f9SBaptiste Daroussin       ((el) = (((el)==(tmp1)) ? 0L : (tmp2))))
701*c99fb5f9SBaptiste Daroussin 
702*c99fb5f9SBaptiste Daroussin #define CDL_SEARCH_SCALAR(head,out,field,val)                                                  \
703*c99fb5f9SBaptiste Daroussin     CDL_SEARCH_SCALAR2(head,out,field,val,next)
704*c99fb5f9SBaptiste Daroussin 
705*c99fb5f9SBaptiste Daroussin #define CDL_SEARCH_SCALAR2(head,out,field,val,next)                                            \
706*c99fb5f9SBaptiste Daroussin do {                                                                                           \
707*c99fb5f9SBaptiste Daroussin     CDL_FOREACH2(head,out,next) {                                                              \
708*c99fb5f9SBaptiste Daroussin       if ((out)->field == (val)) break;                                                        \
709*c99fb5f9SBaptiste Daroussin     }                                                                                          \
710*c99fb5f9SBaptiste Daroussin } while(0)
711*c99fb5f9SBaptiste Daroussin 
712*c99fb5f9SBaptiste Daroussin #define CDL_SEARCH(head,out,elt,cmp)                                                           \
713*c99fb5f9SBaptiste Daroussin     CDL_SEARCH2(head,out,elt,cmp,next)
714*c99fb5f9SBaptiste Daroussin 
715*c99fb5f9SBaptiste Daroussin #define CDL_SEARCH2(head,out,elt,cmp,next)                                                     \
716*c99fb5f9SBaptiste Daroussin do {                                                                                           \
717*c99fb5f9SBaptiste Daroussin     CDL_FOREACH2(head,out,next) {                                                              \
718*c99fb5f9SBaptiste Daroussin       if ((cmp(out,elt))==0) break;                                                            \
719*c99fb5f9SBaptiste Daroussin     }                                                                                          \
720*c99fb5f9SBaptiste Daroussin } while(0)
721*c99fb5f9SBaptiste Daroussin 
722*c99fb5f9SBaptiste Daroussin #define CDL_REPLACE_ELEM(head, el, add)                                                        \
723*c99fb5f9SBaptiste Daroussin do {                                                                                           \
724*c99fb5f9SBaptiste Daroussin  assert(head != NULL);                                                                         \
725*c99fb5f9SBaptiste Daroussin  assert(el != NULL);                                                                           \
726*c99fb5f9SBaptiste Daroussin  assert(add != NULL);                                                                          \
727*c99fb5f9SBaptiste Daroussin  if ((el)->next == (el)) {                                                                     \
728*c99fb5f9SBaptiste Daroussin   (add)->next = (add);                                                                         \
729*c99fb5f9SBaptiste Daroussin   (add)->prev = (add);                                                                         \
730*c99fb5f9SBaptiste Daroussin   (head) = (add);                                                                              \
731*c99fb5f9SBaptiste Daroussin  } else {                                                                                      \
732*c99fb5f9SBaptiste Daroussin   (add)->next = (el)->next;                                                                    \
733*c99fb5f9SBaptiste Daroussin   (add)->prev = (el)->prev;                                                                    \
734*c99fb5f9SBaptiste Daroussin   (add)->next->prev = (add);                                                                   \
735*c99fb5f9SBaptiste Daroussin   (add)->prev->next = (add);                                                                   \
736*c99fb5f9SBaptiste Daroussin   if ((head) == (el)) {                                                                        \
737*c99fb5f9SBaptiste Daroussin    (head) = (add);                                                                             \
738*c99fb5f9SBaptiste Daroussin   }                                                                                            \
739*c99fb5f9SBaptiste Daroussin  }                                                                                             \
740*c99fb5f9SBaptiste Daroussin } while (0)
741*c99fb5f9SBaptiste Daroussin 
742*c99fb5f9SBaptiste Daroussin #define CDL_PREPEND_ELEM(head, el, add)                                                        \
743*c99fb5f9SBaptiste Daroussin do {                                                                                           \
744*c99fb5f9SBaptiste Daroussin  assert(head != NULL);                                                                         \
745*c99fb5f9SBaptiste Daroussin  assert(el != NULL);                                                                           \
746*c99fb5f9SBaptiste Daroussin  assert(add != NULL);                                                                          \
747*c99fb5f9SBaptiste Daroussin  (add)->next = (el);                                                                           \
748*c99fb5f9SBaptiste Daroussin  (add)->prev = (el)->prev;                                                                     \
749*c99fb5f9SBaptiste Daroussin  (el)->prev = (add);                                                                           \
750*c99fb5f9SBaptiste Daroussin  (add)->prev->next = (add);                                                                    \
751*c99fb5f9SBaptiste Daroussin  if ((head) == (el)) {                                                                         \
752*c99fb5f9SBaptiste Daroussin   (head) = (add);                                                                              \
753*c99fb5f9SBaptiste Daroussin  }                                                                                             \
754*c99fb5f9SBaptiste Daroussin } while (0)                                                                                    \
755*c99fb5f9SBaptiste Daroussin 
756*c99fb5f9SBaptiste Daroussin #endif /* UTLIST_H */
757*c99fb5f9SBaptiste Daroussin 
758