Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/pkg
Path: blob/main/external/uthash/utlist.h
2065 views
1
/*
2
Copyright (c) 2007-2013, Troy D. Hanson http://troydhanson.github.com/uthash/
3
All rights reserved.
4
5
Redistribution and use in source and binary forms, with or without
6
modification, 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
11
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
12
IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
13
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
14
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
15
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
16
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
17
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
18
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
19
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
20
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
21
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
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) \
109
do { \
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) \
172
do { \
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) \
234
do { \
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) \
313
do { \
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) \
322
do { \
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) \
337
do { \
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) \
353
do { \
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) \
373
do { \
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) \
388
do { \
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) \
444
do { \
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) \
454
do { \
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) \
461
do { \
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) \
481
do { \
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) \
508
do { \
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) \
523
do { \
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) \
540
do { \
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) \
558
do { \
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) \
604
do { \
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) \
630
do { \
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) \
652
do { \
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) \
669
do { \
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) \
706
do { \
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) \
716
do { \
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) \
723
do { \
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) \
743
do { \
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
759