1 /*
2 * ptrlist.c
3 *
4 * (C) Copyright Linus Torvalds 2003-2005
5 */
6
7 ///
8 // Pointer list manipulation
9 // -------------------------
10 //
11 // The data structure handled here is designed to hold pointers
12 // but two special cases need to be avoided or need special care:
13 // * NULL is used by {PREPARE,NEXT}_PTR_LIST() to indicate the end-of-list.
14 // Thus, NULL can't be stored in lists using this API but is fine to
15 // use with FOR_EACH_PTR() and its variants.
16 // * VOID is used to replace a removed pseudo 'usage'. Since phi-nodes
17 // (OP_PHI) use a list to store their operands, a VOID in a phi-node
18 // list must be ignored since it represents a removed operand. As
19 // consequence, VOIDs must never be used as phi-node operand.
20 // This is fine since phi-nodes make no sense with void values
21 // but VOID is also used for invalid types and in case of errors.
22
23 #include <stdlib.h>
24 #include <string.h>
25 #include <assert.h>
26
27 #include "ptrlist.h"
28 #include "allocate.h"
29 #include "compat.h"
30
31 __DECLARE_ALLOCATOR(struct ptr_list, ptrlist);
32 __ALLOCATOR(struct ptr_list, "ptr list", ptrlist);
33
34 ///
35 // get the size of a ptrlist
36 // @head: the head of the list
37 // @return: the size of the list given by @head.
ptr_list_size(struct ptr_list * head)38 int ptr_list_size(struct ptr_list *head)
39 {
40 int nr = 0;
41
42 if (head) {
43 struct ptr_list *list = head;
44 do {
45 nr += list->nr - list->rm;
46 } while ((list = list->next) != head);
47 }
48 return nr;
49 }
50
51 ///
52 // test if a list is empty
53 // @head: the head of the list
54 // @return: ``true`` if the list is empty, ``false`` otherwise.
ptr_list_empty(const struct ptr_list * head)55 bool ptr_list_empty(const struct ptr_list *head)
56 {
57 const struct ptr_list *list = head;
58
59 if (!head)
60 return true;
61
62 do {
63 if (list->nr - list->rm)
64 return false;
65 } while ((list = list->next) != head);
66
67 return true;
68 }
69
70 ///
71 // test is a list contains more than one element
72 // @head: the head of the list
73 // @return: ``true`` if the list has more than 1 element, ``false`` otherwise.
ptr_list_multiple(const struct ptr_list * head)74 bool ptr_list_multiple(const struct ptr_list *head)
75 {
76 const struct ptr_list *list = head;
77 int nr = 0;
78
79 if (!head)
80 return false;
81
82 do {
83 nr += list->nr - list->rm;
84 if (nr > 1)
85 return true;
86 } while ((list = list->next) != head);
87
88 return false;
89 }
90
91 ///
92 // get the first element of a ptrlist
93 // @head: the head of the list
94 // @return: the first element of the list or ``NULL`` if the list is empty
first_ptr_list(struct ptr_list * head)95 void *first_ptr_list(struct ptr_list *head)
96 {
97 struct ptr_list *list = head;
98
99 if (!head)
100 return NULL;
101
102 while (list->nr == 0) {
103 list = list->next;
104 if (list == head)
105 return NULL;
106 }
107 return PTR_ENTRY_NOTAG(list, 0);
108 }
109
110 ///
111 // get the last element of a ptrlist
112 // @head: the head of the list
113 // @return: the last element of the list or ``NULL`` if the list is empty
last_ptr_list(struct ptr_list * head)114 void *last_ptr_list(struct ptr_list *head)
115 {
116 struct ptr_list *list;
117
118 if (!head)
119 return NULL;
120 list = head->prev;
121 while (list->nr == 0) {
122 if (list == head)
123 return NULL;
124 list = list->prev;
125 }
126 return PTR_ENTRY_NOTAG(list, list->nr-1);
127 }
128
129 ///
130 // get the nth element of a ptrlist
131 // @head: the head of the list
132 // @return: the nth element of the list or ``NULL`` if the list is too short.
ptr_list_nth_entry(struct ptr_list * list,unsigned int idx)133 void *ptr_list_nth_entry(struct ptr_list *list, unsigned int idx)
134 {
135 struct ptr_list *head = list;
136
137 if (!head)
138 return NULL;
139
140 do {
141 unsigned int nr = list->nr;
142
143 if (idx < nr)
144 return list->list[idx];
145 else
146 idx -= nr;
147 } while ((list = list->next) != head);
148 return NULL;
149 }
150
151 ///
152 // linearize the entries of a list
153 //
154 // @head: the list to be linearized
155 // @arr: a ``void*`` array to fill with @head's entries
156 // @max: the maximum number of entries to store into @arr
157 // @return: the number of entries in the list.
158 //
159 // Linearize the entries of a list up to a total of @max,
160 // and return the number of entries in the list.
161 //
162 // The array to linearize into (@arr) should really
163 // be ``void *x[]``, but we want to let people fill in any kind
164 // of pointer array, so let's just call it ``void **``.
linearize_ptr_list(struct ptr_list * head,void ** arr,int max)165 int linearize_ptr_list(struct ptr_list *head, void **arr, int max)
166 {
167 int nr = 0;
168 if (head && max > 0) {
169 struct ptr_list *list = head;
170
171 do {
172 int i = list->nr;
173 nr += i;
174 if (max == 0)
175 continue;
176 if (i > max)
177 i = max;
178 memcpy(arr, list->list, i*sizeof(void *));
179 arr += i;
180 max -= i;
181 } while ((list = list->next) != head);
182 }
183 return nr;
184 }
185
186 ///
187 // pack a ptrlist
188 //
189 // @listp: a pointer to the list to be packed.
190 //
191 // When we've walked the list and deleted entries,
192 // we may need to re-pack it so that we don't have
193 // any empty blocks left (empty blocks upset the
194 // walking code).
pack_ptr_list(struct ptr_list ** listp)195 void pack_ptr_list(struct ptr_list **listp)
196 {
197 struct ptr_list *head = *listp;
198
199 if (head) {
200 struct ptr_list *entry = head;
201 do {
202 struct ptr_list *next;
203 restart:
204 next = entry->next;
205 if (!entry->nr) {
206 struct ptr_list *prev;
207 if (next == entry) {
208 __free_ptrlist(entry);
209 *listp = NULL;
210 return;
211 }
212 prev = entry->prev;
213 prev->next = next;
214 next->prev = prev;
215 __free_ptrlist(entry);
216 if (entry == head) {
217 *listp = next;
218 head = next;
219 entry = next;
220 goto restart;
221 }
222 }
223 entry = next;
224 } while (entry != head);
225 }
226 }
227
228 ///
229 // split a ptrlist block
230 // @head: the ptrlist block to be split
231 //
232 // A new block is inserted just after @head and the entries
233 // at the half end of @head are moved to this new block.
234 // The goal being to create space inside @head for a new entry.
split_ptr_list_head(struct ptr_list * head)235 void split_ptr_list_head(struct ptr_list *head)
236 {
237 int old = head->nr, nr = old / 2;
238 struct ptr_list *newlist = __alloc_ptrlist(0);
239 struct ptr_list *next = head->next;
240
241 old -= nr;
242 head->nr = old;
243 newlist->next = next;
244 next->prev = newlist;
245 newlist->prev = head;
246 head->next = newlist;
247 newlist->nr = nr;
248 memcpy(newlist->list, head->list + old, nr * sizeof(void *));
249 memset(head->list + old, 0xf0, nr * sizeof(void *));
250 }
251
252 ///
253 // add an entry to a ptrlist
254 // @listp: a pointer to the list
255 // @ptr: the entry to add to the list
256 // @return: the address where the new entry is stored.
257 //
258 // :note: code must not use this function and should use
259 // :func:`add_ptr_list` instead.
__add_ptr_list(struct ptr_list ** listp,void * ptr)260 void **__add_ptr_list(struct ptr_list **listp, void *ptr)
261 {
262 struct ptr_list *list = *listp;
263 struct ptr_list *last = NULL; /* gcc complains needlessly */
264 void **ret;
265 int nr;
266
267 if (!list || (nr = (last = list->prev)->nr) >= LIST_NODE_NR) {
268 struct ptr_list *newlist = __alloc_ptrlist(0);
269 if (!list) {
270 newlist->next = newlist;
271 newlist->prev = newlist;
272 *listp = newlist;
273 } else {
274 newlist->prev = last;
275 newlist->next = list;
276 list->prev = newlist;
277 last->next = newlist;
278 }
279 last = newlist;
280 nr = 0;
281 }
282 ret = last->list + nr;
283 *ret = ptr;
284 nr++;
285 last->nr = nr;
286 return ret;
287 }
288
289 ///
290 // add a tagged entry to a ptrlist
291 // @listp: a pointer to the list
292 // @ptr: the entry to add to the list
293 // @tag: the tag to add to @ptr
294 // @return: the address where the new entry is stored.
295 //
296 // :note: code must not use this function and should use
297 // :func:`add_ptr_list_tag` instead.
__add_ptr_list_tag(struct ptr_list ** listp,void * ptr,unsigned long tag)298 void **__add_ptr_list_tag(struct ptr_list **listp, void *ptr, unsigned long tag)
299 {
300 /* The low two bits are reserved for tags */
301 assert((3 & (unsigned long)ptr) == 0);
302 assert((~3 & tag) == 0);
303
304 ptr = (void *)(tag | (unsigned long)ptr);
305
306 return __add_ptr_list(listp, ptr);
307 }
308
309 ///
310 // test if some entry is already present in a ptrlist
311 // @list: the head of the list
312 // @entry: the entry to test
313 // @return: ``true`` if the entry is already present, ``false`` otherwise.
lookup_ptr_list_entry(const struct ptr_list * head,const void * entry)314 bool lookup_ptr_list_entry(const struct ptr_list *head, const void *entry)
315 {
316 const struct ptr_list *list = head;
317
318 if (!head)
319 return false;
320 do {
321 int nr = list->nr;
322 int i;
323 for (i = 0; i < nr; i++)
324 if (list->list[i] == entry)
325 return true;
326 } while ((list = list->next) != head);
327 return false;
328 }
329
330 ///
331 // delete an entry from a ptrlist
332 // @list: a pointer to the list
333 // @entry: the item to be deleted
334 // @count: the minimum number of times @entry should be deleted or 0.
delete_ptr_list_entry(struct ptr_list ** list,void * entry,int count)335 int delete_ptr_list_entry(struct ptr_list **list, void *entry, int count)
336 {
337 void *ptr;
338
339 FOR_EACH_PTR(*list, ptr) {
340 if (ptr == entry) {
341 DELETE_CURRENT_PTR(ptr);
342 if (!--count)
343 goto out;
344 }
345 } END_FOR_EACH_PTR(ptr);
346 assert(count <= 0);
347 out:
348 pack_ptr_list(list);
349 return count;
350 }
351
352 ///
353 // replace an entry in a ptrlist
354 // @list: a pointer to the list
355 // @old_ptr: the entry to be replaced
356 // @new_ptr: the new entry
357 // @count: the minimum number of times @entry should be deleted or 0.
replace_ptr_list_entry(struct ptr_list ** list,void * old_ptr,void * new_ptr,int count)358 int replace_ptr_list_entry(struct ptr_list **list, void *old_ptr,
359 void *new_ptr, int count)
360 {
361 void *ptr;
362
363 FOR_EACH_PTR(*list, ptr) {
364 if (ptr==old_ptr) {
365 REPLACE_CURRENT_PTR(ptr, new_ptr);
366 if (!--count)
367 goto out;
368 }
369 }END_FOR_EACH_PTR(ptr);
370 assert(count <= 0);
371 out:
372 return count;
373 }
374
375 ///
376 // remove the last entry of a ptrlist
377 // @head: a pointer to the list
378 // @return: the last element of the list or NULL if the list is empty.
379 //
380 // :note: this doesn't repack the list
undo_ptr_list_last(struct ptr_list ** head)381 void * undo_ptr_list_last(struct ptr_list **head)
382 {
383 struct ptr_list *last, *first = *head;
384
385 if (!first)
386 return NULL;
387 last = first;
388 do {
389 last = last->prev;
390 if (last->nr) {
391 void *ptr;
392 int nr = --last->nr;
393 ptr = last->list[nr];
394 last->list[nr] = (void *)0xf1f1f1f1;
395 return ptr;
396 }
397 } while (last != first);
398 return NULL;
399 }
400
401 ///
402 // remove the last entry and repack the list
403 // @head: a pointer to the list
404 // @return: the last element of the list or NULL if the list is empty.
delete_ptr_list_last(struct ptr_list ** head)405 void * delete_ptr_list_last(struct ptr_list **head)
406 {
407 void *ptr = NULL;
408 struct ptr_list *last, *first = *head;
409
410 if (!first)
411 return NULL;
412 last = first->prev;
413 if (last->nr)
414 ptr = last->list[--last->nr];
415 if (last->nr <=0) {
416 first->prev = last->prev;
417 last->prev->next = first;
418 if (last == first)
419 *head = NULL;
420 __free_ptrlist(last);
421 }
422 return ptr;
423 }
424
425 ///
426 // concat two ptrlists
427 // @a: the source list
428 // @b: a pointer to the destination list.
429 // The element of @a are added at the end of @b.
concat_ptr_list(struct ptr_list * a,struct ptr_list ** b)430 void concat_ptr_list(struct ptr_list *a, struct ptr_list **b)
431 {
432 void *entry;
433 FOR_EACH_PTR(a, entry) {
434 add_ptr_list(b, entry);
435 } END_FOR_EACH_PTR(entry);
436 }
437
438 ///
439 // copy the elements of a list at the end of another list.
440 // @listp: a pointer to the destination list.
441 // @src: the head of the source list.
copy_ptr_list(struct ptr_list ** listp,struct ptr_list * src)442 void copy_ptr_list(struct ptr_list **listp, struct ptr_list *src)
443 {
444 struct ptr_list *head, *tail;
445 struct ptr_list *cur = src;
446 int idx;
447
448 if (!src)
449 return;
450 head = *listp;
451 if (!head) {
452 *listp = src;
453 return;
454 }
455
456 tail = head->prev;
457 idx = tail->nr;
458 do {
459 struct ptr_list *next;
460 int nr = cur->nr;
461 int i;
462 for (i = 0; i < nr;) {
463 void *ptr = cur->list[i++];
464 if (!ptr)
465 continue;
466 if (idx >= LIST_NODE_NR) {
467 struct ptr_list *prev = tail;
468 tail = __alloc_ptrlist(0);
469 prev->next = tail;
470 tail->prev = prev;
471 prev->nr = idx;
472 idx = 0;
473 }
474 tail->list[idx++] = ptr;
475 }
476
477 next = cur->next;
478 __free_ptrlist(cur);
479 cur = next;
480 } while (cur != src);
481
482 tail->nr = idx;
483 head->prev = tail;
484 tail->next = head;
485 }
486
487 ///
488 // free a ptrlist
489 // @listp: a pointer to the list
490 // Each blocks of the list are freed (but the entries
491 // themselves are not freed).
492 //
493 // :note: code must not use this function and should use
494 // the macro :func:`free_ptr_list` instead.
__free_ptr_list(struct ptr_list ** listp)495 void __free_ptr_list(struct ptr_list **listp)
496 {
497 struct ptr_list *tmp, *list = *listp;
498
499 if (!list)
500 return;
501
502 list->prev->next = NULL;
503 while (list) {
504 tmp = list;
505 list = list->next;
506 __free_ptrlist(tmp);
507 }
508
509 *listp = NULL;
510 }
511