Merge branch 'handle-cleanup-attr'
[smatch.git] / ptrlist.c
blobc5766002e7ef823debbbd90e18f29055830f5f52
1 /*
2 * ptrlist.c
4 * (C) Copyright Linus Torvalds 2003-2005
5 */
7 ///
8 // Pointer list manipulation
9 // -------------------------
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.
23 #include <stdlib.h>
24 #include <string.h>
25 #include <assert.h>
27 #include "ptrlist.h"
28 #include "allocate.h"
29 #include "compat.h"
31 __DECLARE_ALLOCATOR(struct ptr_list, ptrlist);
32 __ALLOCATOR(struct ptr_list, "ptr list", ptrlist);
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.
38 int ptr_list_size(struct ptr_list *head)
40 int nr = 0;
42 if (head) {
43 struct ptr_list *list = head;
44 do {
45 nr += list->nr - list->rm;
46 } while ((list = list->next) != head);
48 return nr;
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.
55 bool ptr_list_empty(const struct ptr_list *head)
57 const struct ptr_list *list = head;
59 if (!head)
60 return true;
62 do {
63 if (list->nr - list->rm)
64 return false;
65 } while ((list = list->next) != head);
67 return true;
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.
74 bool ptr_list_multiple(const struct ptr_list *head)
76 const struct ptr_list *list = head;
77 int nr = 0;
79 if (!head)
80 return false;
82 do {
83 nr += list->nr - list->rm;
84 if (nr > 1)
85 return true;
86 } while ((list = list->next) != head);
88 return false;
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
95 void *first_ptr_list(struct ptr_list *head)
97 struct ptr_list *list = head;
99 if (!head)
100 return NULL;
102 while (list->nr == 0) {
103 list = list->next;
104 if (list == head)
105 return NULL;
107 return PTR_ENTRY_NOTAG(list, 0);
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
114 void *last_ptr_list(struct ptr_list *head)
116 struct ptr_list *list;
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;
126 return PTR_ENTRY_NOTAG(list, list->nr-1);
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.
133 void *ptr_list_nth_entry(struct ptr_list *list, unsigned int idx)
135 struct ptr_list *head = list;
137 if (!head)
138 return NULL;
140 do {
141 unsigned int nr = list->nr;
143 if (idx < nr)
144 return list->list[idx];
145 else
146 idx -= nr;
147 } while ((list = list->next) != head);
148 return NULL;
152 // linearize the entries of a list
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.
159 // Linearize the entries of a list up to a total of @max,
160 // and return the number of entries in the list.
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 **``.
165 int linearize_ptr_list(struct ptr_list *head, void **arr, int max)
167 int nr = 0;
168 if (head && max > 0) {
169 struct ptr_list *list = head;
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);
183 return nr;
187 // pack a ptrlist
189 // @listp: a pointer to the list to be packed.
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).
195 void pack_ptr_list(struct ptr_list **listp)
197 struct ptr_list *head = *listp;
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;
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;
223 entry = next;
224 } while (entry != head);
229 // split a ptrlist block
230 // @head: the ptrlist block to be split
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.
235 void split_ptr_list_head(struct ptr_list *head)
237 int old = head->nr, nr = old / 2;
238 struct ptr_list *newlist = __alloc_ptrlist(0);
239 struct ptr_list *next = head->next;
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 *));
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.
258 // :note: code must not use this function and should use
259 // :func:`add_ptr_list` instead.
260 void **__add_ptr_list(struct ptr_list **listp, void *ptr)
262 struct ptr_list *list = *listp;
263 struct ptr_list *last = NULL; /* gcc complains needlessly */
264 void **ret;
265 int nr;
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;
279 last = newlist;
280 nr = 0;
282 ret = last->list + nr;
283 *ret = ptr;
284 nr++;
285 last->nr = nr;
286 return ret;
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.
296 // :note: code must not use this function and should use
297 // :func:`add_ptr_list_tag` instead.
298 void **__add_ptr_list_tag(struct ptr_list **listp, void *ptr, unsigned long tag)
300 /* The low two bits are reserved for tags */
301 assert((3 & (unsigned long)ptr) == 0);
302 assert((~3 & tag) == 0);
304 ptr = (void *)(tag | (unsigned long)ptr);
306 return __add_ptr_list(listp, ptr);
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.
314 bool lookup_ptr_list_entry(const struct ptr_list *head, const void *entry)
316 const struct ptr_list *list = head;
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;
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.
335 int delete_ptr_list_entry(struct ptr_list **list, void *entry, int count)
337 void *ptr;
339 FOR_EACH_PTR(*list, ptr) {
340 if (ptr == entry) {
341 DELETE_CURRENT_PTR(ptr);
342 if (!--count)
343 goto out;
345 } END_FOR_EACH_PTR(ptr);
346 assert(count <= 0);
347 out:
348 pack_ptr_list(list);
349 return count;
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.
358 int replace_ptr_list_entry(struct ptr_list **list, void *old_ptr,
359 void *new_ptr, int count)
361 void *ptr;
363 FOR_EACH_PTR(*list, ptr) {
364 if (ptr==old_ptr) {
365 REPLACE_CURRENT_PTR(ptr, new_ptr);
366 if (!--count)
367 goto out;
369 }END_FOR_EACH_PTR(ptr);
370 assert(count <= 0);
371 out:
372 return count;
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.
380 // :note: this doesn't repack the list
381 void * undo_ptr_list_last(struct ptr_list **head)
383 struct ptr_list *last, *first = *head;
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;
397 } while (last != first);
398 return NULL;
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.
405 void * delete_ptr_list_last(struct ptr_list **head)
407 void *ptr = NULL;
408 struct ptr_list *last, *first = *head;
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);
422 return ptr;
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.
430 void concat_ptr_list(struct ptr_list *a, struct ptr_list **b)
432 void *entry;
433 FOR_EACH_PTR(a, entry) {
434 add_ptr_list(b, entry);
435 } END_FOR_EACH_PTR(entry);
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.
442 void copy_ptr_list(struct ptr_list **listp, struct ptr_list *src)
444 struct ptr_list *head, *tail;
445 struct ptr_list *cur = src;
446 int idx;
448 if (!src)
449 return;
450 head = *listp;
451 if (!head) {
452 *listp = src;
453 return;
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;
474 tail->list[idx++] = ptr;
477 next = cur->next;
478 __free_ptrlist(cur);
479 cur = next;
480 } while (cur != src);
482 tail->nr = idx;
483 head->prev = tail;
484 tail->next = head;
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).
493 // :note: code must not use this function and should use
494 // the macro :func:`free_ptr_list` instead.
495 void __free_ptr_list(struct ptr_list **listp)
497 struct ptr_list *tmp, *list = *listp;
499 if (!list)
500 return;
502 list->prev->next = NULL;
503 while (list) {
504 tmp = list;
505 list = list->next;
506 __free_ptrlist(tmp);
509 *listp = NULL;