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