Toggle navigation
Documentation
The friendly Operating System for the Internet of Things
utlist.h
Go to the documentation of this file.
1
/*
2
Copyright (c) 2007-2014, 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
#pragma once
25
40
#define UTLIST_VERSION 1.9.9
41
#include <stddef.h>
42
43
#include <
assert.h
>
44
45
#ifdef __cplusplus
46
extern
"C"
{
47
#endif
48
49
/*
50
* This file contains macros to manipulate singly and doubly-linked lists.
51
*
52
* 1. LL_ macros: singly-linked lists.
53
* 2. DL_ macros: doubly-linked lists.
54
* 3. CDL_ macros: circular doubly-linked lists.
55
*
56
* To use singly-linked lists, your structure must have a "next" pointer.
57
* To use doubly-linked lists, your structure must "prev" and "next" pointers.
58
* Either way, the pointer to the head of the list must be initialized to NULL.
59
*
60
* ----------------.EXAMPLE -------------------------
61
* struct item {
62
* int id;
63
* struct item *prev, *next;
64
* }
65
*
66
* struct item *list = NULL:
67
*
68
* int main() {
69
* struct item *item;
70
* ... allocate and populate item ...
71
* DL_APPEND(list, item);
72
* }
73
* --------------------------------------------------
74
*
75
* For doubly-linked lists, the append and delete macros are O(1)
76
* For singly-linked lists, append and delete are O(n) but prepend is O(1)
77
* The sort macro is O(n log(n)) for all types of single/double/circular lists.
78
*/
79
93
#ifdef _MSC_VER
/* MS compiler */
94
#if _MSC_VER >= 1600 && defined(__cplusplus)
/* VS2010 or newer in C++ mode */
95
#define LDECLTYPE(x) decltype(x)
96
#else
/* VS2008 or older (or VS2010 in C mode) */
97
#define NO_DECLTYPE
98
#define LDECLTYPE(x) char*
99
#endif
100
#elif defined(__ICCARM__)
101
#define NO_DECLTYPE
102
#define LDECLTYPE(x) char*
103
#else
/* GNU, Sun and other compilers */
104
#define LDECLTYPE(x) __typeof(x)
105
#endif
106
107
#ifdef NO_DECLTYPE
108
#define _SV(elt,list) _tmp = (char*)(list); {char **_alias = (char**)&(list); *_alias = (elt); }
109
#define _NEXT(elt,list,next) ((char*)((list)->next))
110
#define _NEXTASGN(elt,list,to,next) { char **_alias = (char**)&((list)->next); *_alias=(char*)(to); }
111
/* #define _PREV(elt,list,prev) ((char*)((list)->prev)) */
112
#define _PREVASGN(elt,list,to,prev) { char **_alias = (char**)&((list)->prev); *_alias=(char*)(to); }
113
#define _RS(list) { char **_alias = (char**)&(list); *_alias=_tmp; }
114
#define _CASTASGN(a,b) { char **_alias = (char**)&(a); *_alias=(char*)(b); }
115
#else
116
#define _SV(elt,list)
117
#define _NEXT(elt,list,next) ((elt)->next)
118
#define _NEXTASGN(elt,list,to,next) ((elt)->next)=(to)
119
/* #define _PREV(elt,list,prev) ((elt)->prev) */
120
#define _PREVASGN(elt,list,to,prev) ((elt)->prev)=(to)
121
#define _RS(list)
122
#define _CASTASGN(a,b) (a)=(b)
123
#endif
133
#define LL_SORT(list, cmp) \
134
LL_SORT2(list, cmp, next)
135
136
#define LL_SORT2(list, cmp, next) \
137
do { \
138
LDECLTYPE(list) _ls_p; \
139
LDECLTYPE(list) _ls_q; \
140
LDECLTYPE(list) _ls_e; \
141
LDECLTYPE(list) _ls_tail; \
142
int _ls_insize, _ls_nmerges, _ls_psize, _ls_qsize, _ls_i, _ls_looping; \
143
if (list) { \
144
_ls_insize = 1; \
145
_ls_looping = 1; \
146
while (_ls_looping) { \
147
_CASTASGN(_ls_p,list); \
148
list = NULL; \
149
_ls_tail = NULL; \
150
_ls_nmerges = 0; \
151
while (_ls_p) { \
152
_ls_nmerges++; \
153
_ls_q = _ls_p; \
154
_ls_psize = 0; \
155
for (_ls_i = 0; _ls_i < _ls_insize; _ls_i++) { \
156
_ls_psize++; \
157
_SV(_ls_q,list); _ls_q = _NEXT(_ls_q,list,next); _RS(list); \
158
if (!_ls_q) break; \
159
} \
160
_ls_qsize = _ls_insize; \
161
while (_ls_psize > 0 || (_ls_qsize > 0 && _ls_q)) { \
162
if (_ls_psize == 0) { \
163
_ls_e = _ls_q; _SV(_ls_q,list); _ls_q = \
164
_NEXT(_ls_q,list,next); _RS(list); _ls_qsize--; \
165
} else if (_ls_qsize == 0 || !_ls_q) { \
166
_ls_e = _ls_p; _SV(_ls_p,list); _ls_p = \
167
_NEXT(_ls_p,list,next); _RS(list); _ls_psize--; \
168
} else if (cmp(_ls_p,_ls_q) <= 0) { \
169
_ls_e = _ls_p; _SV(_ls_p,list); _ls_p = \
170
_NEXT(_ls_p,list,next); _RS(list); _ls_psize--; \
171
} else { \
172
_ls_e = _ls_q; _SV(_ls_q,list); _ls_q = \
173
_NEXT(_ls_q,list,next); _RS(list); _ls_qsize--; \
174
} \
175
if (_ls_tail) { \
176
_SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,_ls_e,next); _RS(list); \
177
} else { \
178
_CASTASGN(list,_ls_e); \
179
} \
180
_ls_tail = _ls_e; \
181
} \
182
_ls_p = _ls_q; \
183
} \
184
if (_ls_tail) { \
185
_SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,NULL,next); _RS(list); \
186
} \
187
if (_ls_nmerges <= 1) { \
188
_ls_looping=0; \
189
} \
190
_ls_insize *= 2; \
191
} \
192
} \
193
} while (0)
194
195
#define DL_SORT(list, cmp) \
196
DL_SORT2(list, cmp, prev, next)
197
198
#define DL_SORT2(list, cmp, prev, next) \
199
do { \
200
LDECLTYPE(list) _ls_p; \
201
LDECLTYPE(list) _ls_q; \
202
LDECLTYPE(list) _ls_e; \
203
LDECLTYPE(list) _ls_tail; \
204
int _ls_insize, _ls_nmerges, _ls_psize, _ls_qsize, _ls_i, _ls_looping; \
205
if (list) { \
206
_ls_insize = 1; \
207
_ls_looping = 1; \
208
while (_ls_looping) { \
209
_CASTASGN(_ls_p,list); \
210
list = NULL; \
211
_ls_tail = NULL; \
212
_ls_nmerges = 0; \
213
while (_ls_p) { \
214
_ls_nmerges++; \
215
_ls_q = _ls_p; \
216
_ls_psize = 0; \
217
for (_ls_i = 0; _ls_i < _ls_insize; _ls_i++) { \
218
_ls_psize++; \
219
_SV(_ls_q,list); _ls_q = _NEXT(_ls_q,list,next); _RS(list); \
220
if (!_ls_q) break; \
221
} \
222
_ls_qsize = _ls_insize; \
223
while (_ls_psize > 0 || (_ls_qsize > 0 && _ls_q)) { \
224
if (_ls_psize == 0) { \
225
_ls_e = _ls_q; _SV(_ls_q,list); _ls_q = \
226
_NEXT(_ls_q,list,next); _RS(list); _ls_qsize--; \
227
} else if (_ls_qsize == 0 || !_ls_q) { \
228
_ls_e = _ls_p; _SV(_ls_p,list); _ls_p = \
229
_NEXT(_ls_p,list,next); _RS(list); _ls_psize--; \
230
} else if (cmp(_ls_p,_ls_q) <= 0) { \
231
_ls_e = _ls_p; _SV(_ls_p,list); _ls_p = \
232
_NEXT(_ls_p,list,next); _RS(list); _ls_psize--; \
233
} else { \
234
_ls_e = _ls_q; _SV(_ls_q,list); _ls_q = \
235
_NEXT(_ls_q,list,next); _RS(list); _ls_qsize--; \
236
} \
237
if (_ls_tail) { \
238
_SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,_ls_e,next); _RS(list); \
239
} else { \
240
_CASTASGN(list,_ls_e); \
241
} \
242
_SV(_ls_e,list); _PREVASGN(_ls_e,list,_ls_tail,prev); _RS(list); \
243
_ls_tail = _ls_e; \
244
} \
245
_ls_p = _ls_q; \
246
} \
247
_CASTASGN(list->prev, _ls_tail); \
248
_SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,NULL,next); _RS(list); \
249
if (_ls_nmerges <= 1) { \
250
_ls_looping=0; \
251
} \
252
_ls_insize *= 2; \
253
} \
254
} \
255
} while (0)
256
257
#define CDL_SORT(list, cmp) \
258
CDL_SORT2(list, cmp, prev, next)
259
260
#define CDL_SORT2(list, cmp, prev, next) \
261
do { \
262
LDECLTYPE(list) _ls_p; \
263
LDECLTYPE(list) _ls_q; \
264
LDECLTYPE(list) _ls_e; \
265
LDECLTYPE(list) _ls_tail; \
266
LDECLTYPE(list) _ls_oldhead; \
267
LDECLTYPE(list) _tmp; \
268
int _ls_insize, _ls_nmerges, _ls_psize, _ls_qsize, _ls_i, _ls_looping; \
269
if (list) { \
270
_ls_insize = 1; \
271
_ls_looping = 1; \
272
while (_ls_looping) { \
273
_CASTASGN(_ls_p,list); \
274
_CASTASGN(_ls_oldhead,list); \
275
list = NULL; \
276
_ls_tail = NULL; \
277
_ls_nmerges = 0; \
278
while (_ls_p) { \
279
_ls_nmerges++; \
280
_ls_q = _ls_p; \
281
_ls_psize = 0; \
282
for (_ls_i = 0; _ls_i < _ls_insize; _ls_i++) { \
283
_ls_psize++; \
284
_SV(_ls_q,list); \
285
if (_NEXT(_ls_q,list,next) == _ls_oldhead) { \
286
_ls_q = NULL; \
287
} else { \
288
_ls_q = _NEXT(_ls_q,list,next); \
289
} \
290
_RS(list); \
291
if (!_ls_q) break; \
292
} \
293
_ls_qsize = _ls_insize; \
294
while (_ls_psize > 0 || (_ls_qsize > 0 && _ls_q)) { \
295
if (_ls_psize == 0) { \
296
_ls_e = _ls_q; _SV(_ls_q,list); _ls_q = \
297
_NEXT(_ls_q,list,next); _RS(list); _ls_qsize--; \
298
if (_ls_q == _ls_oldhead) { _ls_q = NULL; } \
299
} else if (_ls_qsize == 0 || !_ls_q) { \
300
_ls_e = _ls_p; _SV(_ls_p,list); _ls_p = \
301
_NEXT(_ls_p,list,next); _RS(list); _ls_psize--; \
302
if (_ls_p == _ls_oldhead) { _ls_p = NULL; } \
303
} else if (cmp(_ls_p,_ls_q) <= 0) { \
304
_ls_e = _ls_p; _SV(_ls_p,list); _ls_p = \
305
_NEXT(_ls_p,list,next); _RS(list); _ls_psize--; \
306
if (_ls_p == _ls_oldhead) { _ls_p = NULL; } \
307
} else { \
308
_ls_e = _ls_q; _SV(_ls_q,list); _ls_q = \
309
_NEXT(_ls_q,list,next); _RS(list); _ls_qsize--; \
310
if (_ls_q == _ls_oldhead) { _ls_q = NULL; } \
311
} \
312
if (_ls_tail) { \
313
_SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,_ls_e,next); _RS(list); \
314
} else { \
315
_CASTASGN(list,_ls_e); \
316
} \
317
_SV(_ls_e,list); _PREVASGN(_ls_e,list,_ls_tail,prev); _RS(list); \
318
_ls_tail = _ls_e; \
319
} \
320
_ls_p = _ls_q; \
321
} \
322
_CASTASGN(list->prev,_ls_tail); \
323
_CASTASGN(_tmp,list); \
324
_SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,_tmp,next); _RS(list); \
325
if (_ls_nmerges <= 1) { \
326
_ls_looping=0; \
327
} \
328
_ls_insize *= 2; \
329
} \
330
} \
331
} while (0)
339
#define LL_PREPEND(head,add) \
340
LL_PREPEND2(head,add,next)
341
343
#define LL_PREPEND2(head,add,next) \
344
do { \
345
(add)->next = head; \
346
head = add; \
347
} while (0)
348
350
#define LL_CONCAT(head1,head2) \
351
LL_CONCAT2(head1,head2,next)
352
354
#define LL_CONCAT2(head1,head2,next) \
355
do { \
356
LDECLTYPE(head1) _tmp; \
357
if (head1) { \
358
_tmp = head1; \
359
while (_tmp->next) { _tmp = _tmp->next; } \
360
_tmp->next=(head2); \
361
} else { \
362
(head1)=(head2); \
363
} \
364
} while (0)
365
367
#define LL_APPEND(head,add) \
368
LL_APPEND2(head,add,next)
369
371
#define LL_APPEND2(head,add,next) \
372
do { \
373
LDECLTYPE(head) _tmp; \
374
(add)->next=NULL; \
375
if (head) { \
376
_tmp = head; \
377
while (_tmp->next) { _tmp = _tmp->next; } \
378
_tmp->next=(add); \
379
} else { \
380
(head)=(add); \
381
} \
382
} while (0)
383
385
#define LL_DELETE(head,del) \
386
LL_DELETE2(head,del,next)
387
389
#define LL_DELETE2(head,del,next) \
390
do { \
391
LDECLTYPE(head) _tmp; \
392
if ((head) == (del)) { \
393
(head)=(head)->next; \
394
} else { \
395
_tmp = head; \
396
while (_tmp->next && (_tmp->next != (del))) { \
397
_tmp = _tmp->next; \
398
} \
399
if (_tmp->next) { \
400
_tmp->next = ((del)->next); \
401
} \
402
} \
403
} while (0)
404
405
/* Here are VS2008 replacements for LL_APPEND and LL_DELETE */
406
#define LL_APPEND_VS2008(head,add) \
407
LL_APPEND2_VS2008(head,add,next)
408
409
#define LL_APPEND2_VS2008(head,add,next) \
410
do { \
411
if (head) { \
412
(add)->next = head;
/* use add->next as a temp variable */
\
413
while ((add)->next->next) { (add)->next = (add)->next->next; } \
414
(add)->next->next=(add); \
415
} else { \
416
(head)=(add); \
417
} \
418
(add)->next=NULL; \
419
} while (0)
420
421
#define LL_DELETE_VS2008(head,del) \
422
LL_DELETE2_VS2008(head,del,next)
423
424
#define LL_DELETE2_VS2008(head,del,next) \
425
do { \
426
if ((head) == (del)) { \
427
(head)=(head)->next; \
428
} else { \
429
char *_tmp = (char*)(head); \
430
while ((head)->next && ((head)->next != (del))) { \
431
head = (head)->next; \
432
} \
433
if ((head)->next) { \
434
(head)->next = ((del)->next); \
435
} \
436
{ \
437
char **_head_alias = (char**)&(head); \
438
*_head_alias = _tmp; \
439
} \
440
} \
441
} while (0)
442
#ifdef NO_DECLTYPE
443
#undef LL_APPEND
444
#define LL_APPEND LL_APPEND_VS2008
445
#undef LL_DELETE
446
#define LL_DELETE LL_DELETE_VS2008
447
#undef LL_DELETE2
448
#define LL_DELETE2 LL_DELETE2_VS2008
449
#undef LL_APPEND2
450
#define LL_APPEND2 LL_APPEND2_VS2008
451
#undef LL_CONCAT
/* no LL_CONCAT_VS2008 */
452
#undef DL_CONCAT
/* no DL_CONCAT_VS2008 */
453
#endif
454
/* end VS2008 replacements */
455
457
#define LL_COUNT(head,el,counter) \
458
LL_COUNT2(head,el,counter,next) \
459
461
#define LL_COUNT2(head,el,counter,next) \
462
{ \
463
counter = 0; \
464
LL_FOREACH2(head,el,next){ ++counter; } \
465
}
466
468
#define LL_FOREACH(head,el) \
469
LL_FOREACH2(head,el,next)
470
472
#define LL_FOREACH2(head,el,next) \
473
for(el=head;el;el=(el)->next)
474
479
#define LL_FOREACH_SAFE(head,el,tmp) \
480
LL_FOREACH_SAFE2(head,el,tmp,next)
481
483
#define LL_FOREACH_SAFE2(head,el,tmp,next) \
484
for((el)=(head);(el) && (tmp = (el)->next, 1); (el) = tmp)
485
487
#define LL_SEARCH_SCALAR(head,out,field,val) \
488
LL_SEARCH_SCALAR2(head,out,field,val,next)
489
491
#define LL_SEARCH_SCALAR2(head,out,field,val,next) \
492
do { \
493
LL_FOREACH2(head,out,next) { \
494
if ((out)->field == (val)) break; \
495
} \
496
} while(0)
497
499
#define LL_SEARCH(head,out,elt,cmp) \
500
LL_SEARCH2(head,out,elt,cmp,next)
501
503
#define LL_SEARCH2(head,out,elt,cmp,next) \
504
do { \
505
LL_FOREACH2(head,out,next) { \
506
if ((cmp(out,elt))==0) break; \
507
} \
508
} while(0)
509
511
#define LL_REPLACE_ELEM(head, el, add) \
512
do { \
513
LDECLTYPE(head) _tmp; \
514
assert(head != NULL); \
515
assert(el != NULL); \
516
assert(add != NULL); \
517
(add)->next = (el)->next; \
518
if ((head) == (el)) { \
519
(head) = (add); \
520
} else { \
521
_tmp = head; \
522
while (_tmp->next && (_tmp->next != (el))) { \
523
_tmp = _tmp->next; \
524
} \
525
if (_tmp->next) { \
526
_tmp->next = (add); \
527
} \
528
} \
529
} while (0)
530
532
#define LL_PREPEND_ELEM(head, el, add) \
533
do { \
534
LDECLTYPE(head) _tmp; \
535
assert(head != NULL); \
536
assert(el != NULL); \
537
assert(add != NULL); \
538
(add)->next = (el); \
539
if ((head) == (el)) { \
540
(head) = (add); \
541
} else { \
542
_tmp = head; \
543
while (_tmp->next && (_tmp->next != (el))) { \
544
_tmp = _tmp->next; \
545
} \
546
if (_tmp->next) { \
547
_tmp->next = (add); \
548
} \
549
} \
550
} while (0)
558
#define DL_PREPEND(head,add) \
559
DL_PREPEND2(head,add,prev,next)
560
562
#define DL_PREPEND2(head,add,prev,next) \
563
do { \
564
(add)->next = head; \
565
if (head) { \
566
(add)->prev = (head)->prev; \
567
(head)->prev = (add); \
568
} else { \
569
(add)->prev = (add); \
570
} \
571
(head) = (add); \
572
} while (0)
573
575
#define DL_APPEND(head,add) \
576
DL_APPEND2(head,add,prev,next)
577
579
#define DL_APPEND2(head,add,prev,next) \
580
do { \
581
if (head) { \
582
(add)->prev = (head)->prev; \
583
(head)->prev->next = (add); \
584
(head)->prev = (add); \
585
(add)->next = NULL; \
586
} else { \
587
(head)=(add); \
588
(head)->prev = (head); \
589
(head)->next = NULL; \
590
} \
591
} while (0)
592
594
#define DL_CONCAT(head1,head2) \
595
DL_CONCAT2(head1,head2,prev,next)
596
598
#define DL_CONCAT2(head1,head2,prev,next) \
599
do { \
600
LDECLTYPE(head1) _tmp; \
601
if (head2) { \
602
if (head1) { \
603
_tmp = (head2)->prev; \
604
(head2)->prev = (head1)->prev; \
605
(head1)->prev->next = (head2); \
606
(head1)->prev = _tmp; \
607
} else { \
608
(head1)=(head2); \
609
} \
610
} \
611
} while (0)
612
614
#define DL_DELETE(head,del) \
615
DL_DELETE2(head,del,prev,next)
616
618
#define DL_DELETE2(head,del,prev,next) \
619
do { \
620
assert((del)->prev != NULL); \
621
if ((del)->prev == (del)) { \
622
(head)=NULL; \
623
} else if ((del)==(head)) { \
624
(del)->next->prev = (del)->prev; \
625
(head) = (del)->next; \
626
} else { \
627
(del)->prev->next = (del)->next; \
628
if ((del)->next) { \
629
(del)->next->prev = (del)->prev; \
630
} else { \
631
(head)->prev = (del)->prev; \
632
} \
633
} \
634
} while (0)
635
637
#define DL_COUNT(head,el,counter) \
638
DL_COUNT2(head,el,counter,next) \
639
641
#define DL_COUNT2(head,el,counter,next) \
642
{ \
643
counter = 0; \
644
DL_FOREACH2(head,el,next){ ++counter; } \
645
}
646
648
#define DL_FOREACH(head,el) \
649
DL_FOREACH2(head,el,next)
650
652
#define DL_FOREACH2(head,el,next) \
653
for(el=head;el;el=(el)->next)
654
659
#define DL_FOREACH_SAFE(head,el,tmp) \
660
DL_FOREACH_SAFE2(head,el,tmp,next)
661
663
#define DL_FOREACH_SAFE2(head,el,tmp,next) \
664
for((el)=(head);(el) && (tmp = (el)->next, 1); (el) = tmp)
665
670
#define DL_SEARCH_SCALAR LL_SEARCH_SCALAR
671
676
#define DL_SEARCH_SCALAR2 LL_SEARCH_SCALAR2
677
682
#define DL_SEARCH LL_SEARCH
683
688
#define DL_SEARCH2 LL_SEARCH2
689
691
#define DL_REPLACE_ELEM(head, el, add) \
692
do { \
693
assert(head != NULL); \
694
assert(el != NULL); \
695
assert(add != NULL); \
696
if ((head) == (el)) { \
697
(head) = (add); \
698
(add)->next = (el)->next; \
699
if ((el)->next == NULL) { \
700
(add)->prev = (add); \
701
} else { \
702
(add)->prev = (el)->prev; \
703
(add)->next->prev = (add); \
704
} \
705
} else { \
706
(add)->next = (el)->next; \
707
(add)->prev = (el)->prev; \
708
(add)->prev->next = (add); \
709
if ((el)->next == NULL) { \
710
(head)->prev = (add); \
711
} else { \
712
(add)->next->prev = (add); \
713
} \
714
} \
715
} while (0)
716
718
#define DL_PREPEND_ELEM(head, el, add) \
719
do { \
720
assert(head != NULL); \
721
assert(el != NULL); \
722
assert(add != NULL); \
723
(add)->next = (el); \
724
(add)->prev = (el)->prev; \
725
(el)->prev = (add); \
726
if ((head) == (el)) { \
727
(head) = (add); \
728
} else { \
729
(add)->prev->next = (add); \
730
} \
731
} while (0)
739
#define CDL_PREPEND(head,add) \
740
CDL_PREPEND2(head,add,prev,next)
741
743
#define CDL_PREPEND2(head,add,prev,next) \
744
do { \
745
if (head) { \
746
(add)->prev = (head)->prev; \
747
(add)->next = (head); \
748
(head)->prev = (add); \
749
(add)->prev->next = (add); \
750
} else { \
751
(add)->prev = (add); \
752
(add)->next = (add); \
753
} \
754
(head)=(add); \
755
} while (0)
756
758
#define CDL_DELETE(head,del) \
759
CDL_DELETE2(head,del,prev,next)
760
762
#define CDL_DELETE2(head,del,prev,next) \
763
do { \
764
if ( ((head)==(del)) && ((head)->next == (head))) { \
765
(head) = 0L; \
766
} else { \
767
(del)->next->prev = (del)->prev; \
768
(del)->prev->next = (del)->next; \
769
if ((del) == (head)) (head)=(del)->next; \
770
} \
771
} while (0)
772
774
#define CDL_COUNT(head,el,counter) \
775
CDL_COUNT2(head,el,counter,next) \
776
778
#define CDL_COUNT2(head, el, counter,next) \
779
{ \
780
counter = 0; \
781
CDL_FOREACH2(head,el,next){ ++counter; } \
782
}
783
785
#define CDL_FOREACH(head,el) \
786
CDL_FOREACH2(head,el,next)
787
789
#define CDL_FOREACH2(head,el,next) \
790
for(el=head;el;el=((el)->next==head ? 0L : (el)->next))
791
796
#define CDL_FOREACH_SAFE(head,el,tmp1,tmp2) \
797
CDL_FOREACH_SAFE2(head,el,tmp1,tmp2,prev,next)
798
800
#define CDL_FOREACH_SAFE2(head,el,tmp1,tmp2,prev,next) \
801
for((el)=(head), ((tmp1)=(head)?((head)->prev):NULL); \
802
(el) && ((tmp2)=(el)->next, 1); \
803
((el) = (((el)==(tmp1)) ? 0L : (tmp2))))
804
806
#define CDL_SEARCH_SCALAR(head,out,field,val) \
807
CDL_SEARCH_SCALAR2(head,out,field,val,next)
808
810
#define CDL_SEARCH_SCALAR2(head,out,field,val,next) \
811
do { \
812
CDL_FOREACH2(head,out,next) { \
813
if ((out)->field == (val)) break; \
814
} \
815
} while(0)
816
818
#define CDL_SEARCH(head,out,elt,cmp) \
819
CDL_SEARCH2(head,out,elt,cmp,next)
820
822
#define CDL_SEARCH2(head,out,elt,cmp,next) \
823
do { \
824
CDL_FOREACH2(head,out,next) { \
825
if ((cmp(out,elt))==0) break; \
826
} \
827
} while(0)
828
830
#define CDL_REPLACE_ELEM(head, el, add) \
831
do { \
832
assert(head != NULL); \
833
assert(el != NULL); \
834
assert(add != NULL); \
835
if ((el)->next == (el)) { \
836
(add)->next = (add); \
837
(add)->prev = (add); \
838
(head) = (add); \
839
} else { \
840
(add)->next = (el)->next; \
841
(add)->prev = (el)->prev; \
842
(add)->next->prev = (add); \
843
(add)->prev->next = (add); \
844
if ((head) == (el)) { \
845
(head) = (add); \
846
} \
847
} \
848
} while (0)
849
851
#define CDL_PREPEND_ELEM(head, el, add) \
852
do { \
853
assert(head != NULL); \
854
assert(el != NULL); \
855
assert(add != NULL); \
856
(add)->next = (el); \
857
(add)->prev = (el)->prev; \
858
(el)->prev = (add); \
859
(add)->prev->next = (add); \
860
if ((head) == (el)) { \
861
(head) = (add); \
862
} \
863
} while (0)
866
#ifdef __cplusplus
867
}
868
#endif
869
assert.h
POSIX.1-2008 compliant version of the assert macro.
Generated on Mon Jun 30 2025 14:58:02 by
1.9.1