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