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 }