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