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 
27 nothrow:
28 @safe:
29 @nogc:
30 
31 struct LIST
32 {
33         /* Do not access items in this struct directly, use the         */
34         /* functions designed for that purpose.                         */
35         LIST* next;             /* next element in list                 */
36         int count;              /* when 0, element may be deleted       */
37         union
38         {       void* ptr;      /* data pointer                         */
39                 int data;
40         }
41 }
42 
43 alias list_t = LIST*;             /* pointer to a list entry              */
44 
45 /* FPNULL is a null function pointer designed to be an argument to
46  * list_free().
47  */
48 
49 alias list_free_fp = void function(void*) @nogc nothrow;
50 
51 enum FPNULL = cast(list_free_fp)null;
52 
53 private __gshared list_t list_freelist;
54 
55 /* **************** PUBLIC FUNCTIONS ********************* */
56 
57 /********************************
58  * Returns:
59  *    pointer to next entry in list.
60  */
61 
62 list_t list_next(list_t list) { return list.next; }
63 
64 /********************************
65  * Returns:
66  *    ptr from list entry.
67  */
68 
69 @trusted
70 inout(void)* list_ptr(inout list_t list) { return list.ptr; }
71 
72 /********************************
73  * Returns:
74  *    integer item from list entry.
75  */
76 
77 int list_data(list_t list) { return list.data; }
78 
79 /********************************
80  * Prepend integer item to list.
81  */
82 
83 void list_prependdata(list_t *plist,int d)
84 {
85     list_prepend(plist, null).data = d;
86 }
87 
88 @trusted
89 list_t list_alloc()
90 {
91     list_t list;
92 
93     if (list_freelist)
94     {
95         list = list_freelist;
96         list_freelist = list_next(list);
97         //mem_setnewfileline(list,file,line);
98     }
99     else
100     {
101         list = list_new();
102     }
103     return list;
104 }
105 
106 @trusted
107 list_t list_new() { return cast(list_t)malloc(LIST.sizeof); }
108 
109 @trusted
110 void list_delete(list_t list) { free(list); }
111 
112 /********************
113  * Free list.
114  * Params:
115  *      plist =         Pointer to list to free
116  *      freeptr =       Pointer to freeing function for the data pointer
117  *                      (use FPNULL if none)
118  * Output:
119  *      *plist is null
120  */
121 
122 @trusted
123 void list_free(list_t* plist, list_free_fp freeptr)
124 {
125     list_t list = *plist;
126     *plist = null;             // block any circular reference bugs
127     while (list && --list.count == 0)
128     {
129         list_t listnext = list_next(list);
130         if (freeptr)
131             (*freeptr)(list_ptr(list));
132         debug memset(list, 0, (*list).sizeof);
133         list.next = list_freelist;
134         list_freelist = list;
135         list = listnext;
136     }
137 }
138 
139 void list_free(list_t *l)
140 {
141      list_free(l, FPNULL);
142 }
143 
144 /***************************
145  * Remove ptr from the list pointed to by *plist.
146  * Output:
147  *      *plist is updated to be the start of the new list
148  * Returns:
149  *      null if *plist is null
150  *      otherwise ptr
151  */
152 
153 @trusted
154 void* list_subtract(list_t* plist, void* ptr)
155 {
156     list_t list;
157 
158     while ((list = *plist) != null)
159     {
160         if (list_ptr(list) == ptr)
161         {
162             if (--list.count == 0)
163             {
164                 *plist = list_next(list);
165                 list.next = list_freelist;
166                 list_freelist = list;
167             }
168             return ptr;
169         }
170         else
171             plist = &list.next;
172     }
173     return null;            // it wasn't in the list
174 }
175 
176 /***************************
177  * Remove first element in list pointed to by *plist.
178  * Returns:
179  *      First element, null if *plist is null
180  */
181 
182 void* list_pop(list_t* plist)
183 {
184     return list_subtract(plist, list_ptr(*plist));
185 }
186 
187 /*************************
188  * Append ptr to *plist.
189  * Returns:
190  *      pointer to list item created.
191  *      null if out of memory
192  */
193 
194 @trusted
195 list_t list_append(list_t* plist, void* ptr)
196 {
197     while (*plist)
198         plist = &(*plist).next;   // find end of list
199 
200     list_t list = list_alloc();
201     if (list)
202     {
203         *plist = list;
204         list.next = null;
205         list.ptr = ptr;
206         list.count = 1;
207     }
208     return list;
209 }
210 
211 /*************************
212  * Prepend ptr to *plist.
213  * Returns:
214  *      pointer to list item created (which is also the start of the list).
215  *      null if out of memory
216  */
217 
218 @trusted
219 list_t list_prepend(list_t *plist, void *ptr)
220 {
221     list_t list = list_alloc();
222     if (list)
223     {
224         list.next = *plist;
225         list.ptr = ptr;
226         list.count = 1;
227         *plist = list;
228     }
229     return list;
230 }
231 
232 /*************************
233  * Count up and return number of items in list.
234  * Returns:
235  *      # of entries in list
236  */
237 
238 int list_nitems(list_t list)
239 {
240     int n = 0;
241     foreach (l; ListRange(list))
242     {
243         ++n;
244     }
245     return n;
246 }
247 
248 /*************************
249  * Returns:
250  *    nth list entry in list.
251  */
252 
253 list_t list_nth(list_t list, int n)
254 {
255     for (int i = 0; i < n; i++)
256     {
257         assert(list);
258         list = list_next(list);
259     }
260     return list;
261 }
262 
263 /************************
264  * Compare two lists.
265  * Returns:
266  *      If they have the same ptrs, return 1 else 0.
267  */
268 
269 int list_equal(list_t list1, list_t list2)
270 {
271     while (list1 && list2)
272     {
273         if (list_ptr(list1) != list_ptr(list2))
274             break;
275         list1 = list_next(list1);
276         list2 = list_next(list2);
277     }
278     return list1 == list2;
279 }
280 
281 /*************************
282  * Search for ptr in list.
283  * Returns:
284  *    If found, return list entry that it is, else null.
285  */
286 
287 @trusted
288 list_t list_inlist(list_t list, void* ptr)
289 {
290     foreach (l; ListRange(list))
291         if (l.ptr == ptr)
292             return l;
293     return null;
294 }
295 
296 /***************************************
297  * Apply a function fp to each member of a list.
298  */
299 
300 @trusted
301 void list_apply(list_t* plist, void function(void*) @nogc nothrow fp)
302 {
303     if (fp)
304         foreach (l; ListRange(*plist))
305         {
306             (*fp)(list_ptr(l));
307         }
308 }
309 
310 /********************************************
311  * Reverse a list in place.
312  */
313 
314 list_t list_reverse(list_t l)
315 {
316     list_t r = null;
317     while (l)
318     {
319         list_t ln = list_next(l);
320         l.next = r;
321         r = l;
322         l = ln;
323     }
324     return r;
325 }
326 
327 /********************************
328  * Range for Lists.
329  */
330 struct ListRange
331 {
332   pure nothrow @nogc:
333 
334     this(list_t li)
335     {
336         this.li = li;
337     }
338 
339     list_t front() return scope { return li; }
340     void popFront() { li = li.next; }
341     bool empty() const { return !li; }
342 
343   private:
344     list_t li;
345 }