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