1 /** 2 * Interface to the C linked list type. 3 * 4 * List is a complete package of functions to deal with singly linked 5 * lists of pointers or integers. 6 * Features: 7 * 1. Uses mem package. 8 * 2. Has loop-back tests. 9 * 3. Each item in the list can have multiple predecessors, enabling 10 * different lists to 'share' a common tail. 11 * 12 * Copyright: Copyright (C) 1986-1990 by Northwest Software 13 * Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved 14 * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) 15 * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) 16 * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/backend/dlist.d, backend/dlist.d) 17 */ 18 19 module dmd.backend.dlist; 20 21 import core.stdc.stdarg; 22 import core.stdc.stdio; 23 import core.stdc.stdlib; 24 import core.stdc.string; 25 26 extern (C++): 27 28 nothrow: 29 @safe: 30 @nogc 31 { 32 33 /* **************** TYPEDEFS AND DEFINES ****************** */ 34 35 struct LIST 36 { 37 /* Do not access items in this struct directly, use the */ 38 /* functions designed for that purpose. */ 39 LIST* next; /* next element in list */ 40 int count; /* when 0, element may be deleted */ 41 union 42 { void* ptr; /* data pointer */ 43 int data; 44 } 45 } 46 47 alias list_t = LIST*; /* pointer to a list entry */ 48 49 /* FPNULL is a null function pointer designed to be an argument to 50 * list_free(). 51 */ 52 53 alias list_free_fp = void function(void*) @nogc nothrow; 54 55 enum FPNULL = cast(list_free_fp)null; 56 57 /* **************** PUBLIC VARIABLES ********************* */ 58 59 __gshared 60 { 61 int list_inited; // != 0 if list package is initialized 62 list_t list_freelist; 63 int nlist; 64 } 65 66 /* **************** PUBLIC FUNCTIONS ********************* */ 67 68 /******************************** 69 * Create link to existing list, that is, share the list with 70 * somebody else. 71 * 72 * Returns: 73 * pointer to that list entry. 74 */ 75 76 list_t list_link(list_t list) 77 { 78 if (list) 79 ++list.count; 80 return list; 81 } 82 83 /******************************** 84 * Returns: 85 * pointer to next entry in list. 86 */ 87 88 list_t list_next(list_t list) { return list.next; } 89 90 /******************************** 91 * Returns: 92 * ptr from list entry. 93 */ 94 95 @trusted 96 inout(void)* list_ptr(inout list_t list) { return list.ptr; } 97 98 /******************************** 99 * Returns: 100 * integer item from list entry. 101 */ 102 103 int list_data(list_t list) { return list.data; } 104 105 /******************************** 106 * Append integer item to list. 107 */ 108 109 void list_appenddata(list_t* plist, int d) 110 { 111 list_append(plist, null).data = d; 112 } 113 114 /******************************** 115 * Prepend integer item to list. 116 */ 117 118 void list_prependdata(list_t *plist,int d) 119 { 120 list_prepend(plist, null).data = d; 121 } 122 123 /********************** 124 * Initialize list package. 125 * Output: 126 * list_inited = 1 127 */ 128 129 @trusted 130 void list_init() 131 { 132 if (list_inited == 0) 133 { 134 nlist = 0; 135 list_inited++; 136 } 137 } 138 139 /******************* 140 * Terminate list package. 141 * Output: 142 * list_inited = 0 143 */ 144 145 @trusted 146 void list_term() 147 { 148 if (list_inited) 149 { 150 debug printf("Max # of lists = %d\n",nlist); 151 while (list_freelist) 152 { 153 list_t list = list_next(list_freelist); 154 list_delete(list_freelist); 155 list_freelist = list; 156 nlist--; 157 } 158 debug if (nlist) 159 printf("nlist = %d\n",nlist); 160 assert(nlist == 0); 161 list_inited = 0; 162 } 163 } 164 165 166 @trusted 167 list_t list_alloc() 168 { 169 list_t list; 170 171 if (list_freelist) 172 { 173 list = list_freelist; 174 list_freelist = list_next(list); 175 //mem_setnewfileline(list,file,line); 176 } 177 else 178 { 179 nlist++; 180 list = list_new(); 181 } 182 return list; 183 } 184 185 list_t list_alloc(const(char)* file, int line) 186 { 187 return list_alloc(); 188 } 189 190 191 @trusted 192 list_t list_new() { return cast(list_t)malloc(LIST.sizeof); } 193 194 @trusted 195 void list_delete(list_t list) { free(list); } 196 197 /******************** 198 * Free list. 199 * Params: 200 * plist = Pointer to list to free 201 * freeptr = Pointer to freeing function for the data pointer 202 * (use FPNULL if none) 203 * Output: 204 * *plist is null 205 */ 206 207 @trusted 208 void list_free(list_t* plist, list_free_fp freeptr) 209 { 210 list_t list = *plist; 211 *plist = null; // block any circular reference bugs 212 while (list && --list.count == 0) 213 { 214 list_t listnext = list_next(list); 215 if (freeptr) 216 (*freeptr)(list_ptr(list)); 217 debug memset(list, 0, (*list).sizeof); 218 list.next = list_freelist; 219 list_freelist = list; 220 list = listnext; 221 } 222 } 223 224 void list_free(list_t *l) 225 { 226 list_free(l, FPNULL); 227 } 228 229 /*************************** 230 * Remove ptr from the list pointed to by *plist. 231 * Output: 232 * *plist is updated to be the start of the new list 233 * Returns: 234 * null if *plist is null 235 * otherwise ptr 236 */ 237 238 @trusted 239 void* list_subtract(list_t* plist, void* ptr) 240 { 241 list_t list; 242 243 while ((list = *plist) != null) 244 { 245 if (list_ptr(list) == ptr) 246 { 247 if (--list.count == 0) 248 { 249 *plist = list_next(list); 250 list.next = list_freelist; 251 list_freelist = list; 252 } 253 return ptr; 254 } 255 else 256 plist = &list.next; 257 } 258 return null; // it wasn't in the list 259 } 260 261 /*************************** 262 * Remove first element in list pointed to by *plist. 263 * Returns: 264 * First element, null if *plist is null 265 */ 266 267 void* list_pop(list_t* plist) 268 { 269 return list_subtract(plist, list_ptr(*plist)); 270 } 271 272 /************************* 273 * Append ptr to *plist. 274 * Returns: 275 * pointer to list item created. 276 * null if out of memory 277 */ 278 279 @trusted 280 list_t list_append(list_t* plist, void* ptr) 281 { 282 while (*plist) 283 plist = &(*plist).next; // find end of list 284 285 list_t list = list_alloc(); 286 if (list) 287 { 288 *plist = list; 289 list.next = null; 290 list.ptr = ptr; 291 list.count = 1; 292 } 293 return list; 294 } 295 296 list_t list_append_debug(list_t* plist, void* ptr, const(char)* file, int line) 297 { 298 return list_append(plist, ptr); 299 } 300 301 /************************* 302 * Prepend ptr to *plist. 303 * Returns: 304 * pointer to list item created (which is also the start of the list). 305 * null if out of memory 306 */ 307 308 @trusted 309 list_t list_prepend(list_t *plist, void *ptr) 310 { 311 list_t list = list_alloc(); 312 if (list) 313 { 314 list.next = *plist; 315 list.ptr = ptr; 316 list.count = 1; 317 *plist = list; 318 } 319 return list; 320 } 321 322 /************************* 323 * Count up and return number of items in list. 324 * Returns: 325 * # of entries in list 326 */ 327 328 int list_nitems(list_t list) 329 { 330 int n = 0; 331 foreach (l; ListRange(list)) 332 { 333 ++n; 334 } 335 return n; 336 } 337 338 /************************* 339 * Returns: 340 * nth list entry in list. 341 */ 342 343 list_t list_nth(list_t list, int n) 344 { 345 for (int i = 0; i < n; i++) 346 { 347 assert(list); 348 list = list_next(list); 349 } 350 return list; 351 } 352 353 /*********************** 354 * Returns: 355 * last list entry in list. 356 */ 357 358 list_t list_last(list_t list) 359 { 360 if (list) 361 while (list_next(list)) 362 list = list_next(list); 363 return list; 364 } 365 366 /******************************** 367 * Returns: 368 * pointer to previous item in list. 369 */ 370 371 list_t list_prev(list_t start, list_t list) 372 { 373 if (start) 374 { 375 if (start == list) 376 start = null; 377 else 378 while (list_next(start) != list) 379 { 380 start = list_next(start); 381 assert(start); 382 } 383 } 384 return start; 385 } 386 387 /*********************** 388 * Copy a list and return it. 389 */ 390 391 @trusted 392 list_t list_copy(list_t list) 393 { 394 list_t c = null; 395 for (; list; list = list_next(list)) 396 list_append(&c,list_ptr(list)); 397 return c; 398 } 399 400 /************************ 401 * Compare two lists. 402 * Returns: 403 * If they have the same ptrs, return 1 else 0. 404 */ 405 406 int list_equal(list_t list1, list_t list2) 407 { 408 while (list1 && list2) 409 { 410 if (list_ptr(list1) != list_ptr(list2)) 411 break; 412 list1 = list_next(list1); 413 list2 = list_next(list2); 414 } 415 return list1 == list2; 416 } 417 418 /************************ 419 * Compare two lists using the comparison function fp. 420 * The comparison function is the same as used for qsort(). 421 * Returns: 422 * If they compare equal, return 0 else value returned by fp. 423 */ 424 425 @trusted 426 int list_cmp(list_t list1, list_t list2, int function(void*, void*) @nogc nothrow fp) 427 { 428 int result = 0; 429 430 while (1) 431 { 432 if (!list1) 433 { if (list2) 434 result = -1; /* list1 < list2 */ 435 break; 436 } 437 if (!list2) 438 { result = 1; /* list1 > list2 */ 439 break; 440 } 441 result = (*fp)(list_ptr(list1),list_ptr(list2)); 442 if (result) 443 break; 444 list1 = list_next(list1); 445 list2 = list_next(list2); 446 } 447 return result; 448 } 449 450 /************************* 451 * Search for ptr in list. 452 * Returns: 453 * If found, return list entry that it is, else null. 454 */ 455 456 @trusted 457 list_t list_inlist(list_t list, void* ptr) 458 { 459 foreach (l; ListRange(list)) 460 if (l.ptr == ptr) 461 return l; 462 return null; 463 } 464 465 /************************* 466 * Concatenate two lists (l2 appended to l1). 467 * Output: 468 * *pl1 updated to be start of concatenated list. 469 * Returns: 470 * *pl1 471 */ 472 473 list_t list_cat(list_t *pl1, list_t l2) 474 { 475 list_t *pl; 476 for (pl = pl1; *pl; pl = &(*pl).next) 477 { } 478 *pl = l2; 479 return *pl1; 480 } 481 482 /*************************************** 483 * Apply a function fp to each member of a list. 484 */ 485 486 @trusted 487 void list_apply(list_t* plist, void function(void*) @nogc nothrow fp) 488 { 489 if (fp) 490 foreach (l; ListRange(*plist)) 491 { 492 (*fp)(list_ptr(l)); 493 } 494 } 495 496 /******************************************** 497 * Reverse a list in place. 498 */ 499 500 list_t list_reverse(list_t l) 501 { 502 list_t r = null; 503 while (l) 504 { 505 list_t ln = list_next(l); 506 l.next = r; 507 r = l; 508 l = ln; 509 } 510 return r; 511 } 512 513 514 /********************************************** 515 * Copy list of pointers into an array of pointers. 516 */ 517 518 @trusted 519 void list_copyinto(list_t l, void *pa) 520 { 521 void **ppa = cast(void **)pa; 522 for (; l; l = l.next) 523 { 524 *ppa = l.ptr; 525 ++ppa; 526 } 527 } 528 529 /********************************************** 530 * Insert item into list at nth position. 531 */ 532 533 @trusted 534 list_t list_insert(list_t *pl,void *ptr,int n) 535 { 536 list_t list; 537 538 while (n) 539 { 540 pl = &(*pl).next; 541 n--; 542 } 543 list = list_alloc(); 544 if (list) 545 { 546 list.next = *pl; 547 *pl = list; 548 list.ptr = ptr; 549 list.count = 1; 550 } 551 return list; 552 } 553 554 /******************************** 555 * Range for Lists. 556 */ 557 struct ListRange 558 { 559 pure nothrow @nogc @safe: 560 561 this(list_t li) 562 { 563 this.li = li; 564 } 565 566 list_t front() return scope { return li; } 567 void popFront() { li = li.next; } 568 bool empty() const { return !li; } 569 570 private: 571 list_t li; 572 } 573 574 } 575 576 /* The following function should be nothrow @nogc, too, but on 577 * some platforms core.stdc.stdarg is not fully nothrow @nogc. 578 */ 579 580 /************************* 581 * Build a list out of the null-terminated argument list. 582 * Returns: 583 * generated list 584 */ 585 586 @trusted 587 list_t list_build(void *p,...) 588 { 589 va_list ap; 590 591 list_t alist = null; 592 list_t *pe = &alist; 593 for (va_start(ap,p); p; p = va_arg!(void*)(ap)) 594 { 595 list_t list = list_alloc(); 596 if (list) 597 { 598 list.next = null; 599 list.ptr = p; 600 list.count = 1; 601 *pe = list; 602 pe = &list.next; 603 } 604 } 605 va_end(ap); 606 return alist; 607 }