param_key: remove some bogus warning messages
[smatch.git] / ptrlist.c
bloba6db773765709d716014427b4d96b45df7bd247f
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);
33 __ALLOCATOR(struct ptr_list, "rl ptr list", rl_ptrlist);
35 ///
36 // get the size of a ptrlist
37 // @head: the head of the list
38 // @return: the size of the list given by @head.
39 int ptr_list_size(struct ptr_list *head)
41 int nr = 0;
43 if (head) {
44 struct ptr_list *list = head;
45 do {
46 nr += list->nr - list->rm;
47 } while ((list = list->next) != head);
49 return nr;
52 ///
53 // test if a list is empty
54 // @head: the head of the list
55 // @return: ``true`` if the list is empty, ``false`` otherwise.
56 bool ptr_list_empty(const struct ptr_list *head)
58 const struct ptr_list *list = head;
60 if (!head)
61 return true;
63 do {
64 if (list->nr - list->rm)
65 return false;
66 } while ((list = list->next) != head);
68 return true;
71 ///
72 // test is a list contains more than one element
73 // @head: the head of the list
74 // @return: ``true`` if the list has more than 1 element, ``false`` otherwise.
75 bool ptr_list_multiple(const struct ptr_list *head)
77 const struct ptr_list *list = head;
78 int nr = 0;
80 if (!head)
81 return false;
83 do {
84 nr += list->nr - list->rm;
85 if (nr > 1)
86 return true;
87 } while ((list = list->next) != head);
89 return false;
92 ///
93 // get the first element of a ptrlist
94 // @head: the head of the list
95 // @return: the first element of the list or ``NULL`` if the list is empty
96 void *first_ptr_list(struct ptr_list *head)
98 struct ptr_list *list = head;
100 if (!head)
101 return NULL;
103 while (list->nr == 0) {
104 list = list->next;
105 if (list == head)
106 return NULL;
108 return PTR_ENTRY_NOTAG(list, 0);
112 // get the last element of a ptrlist
113 // @head: the head of the list
114 // @return: the last element of the list or ``NULL`` if the list is empty
115 void *last_ptr_list(struct ptr_list *head)
117 struct ptr_list *list;
119 if (!head)
120 return NULL;
121 list = head->prev;
122 while (list->nr == 0) {
123 if (list == head)
124 return NULL;
125 list = list->prev;
127 return PTR_ENTRY_NOTAG(list, list->nr-1);
131 // get the nth element of a ptrlist
132 // @head: the head of the list
133 // @return: the nth element of the list or ``NULL`` if the list is too short.
134 void *ptr_list_nth_entry(struct ptr_list *list, unsigned int idx)
136 struct ptr_list *head = list;
138 if (!head)
139 return NULL;
141 do {
142 unsigned int nr = list->nr;
144 if (idx < nr)
145 return list->list[idx];
146 else
147 idx -= nr;
148 } while ((list = list->next) != head);
149 return NULL;
153 // linearize the entries of a list
155 // @head: the list to be linearized
156 // @arr: a ``void*`` array to fill with @head's entries
157 // @max: the maximum number of entries to store into @arr
158 // @return: the number of entries in the list.
160 // Linearize the entries of a list up to a total of @max,
161 // and return the number of entries in the list.
163 // The array to linearize into (@arr) should really
164 // be ``void *x[]``, but we want to let people fill in any kind
165 // of pointer array, so let's just call it ``void **``.
166 int linearize_ptr_list(struct ptr_list *head, void **arr, int max)
168 int nr = 0;
169 if (head && max > 0) {
170 struct ptr_list *list = head;
172 do {
173 int i = list->nr;
174 nr += i;
175 if (max == 0)
176 continue;
177 if (i > max)
178 i = max;
179 memcpy(arr, list->list, i*sizeof(void *));
180 arr += i;
181 max -= i;
182 } while ((list = list->next) != head);
184 return nr;
188 // pack a ptrlist
190 // @listp: a pointer to the list to be packed.
192 // When we've walked the list and deleted entries,
193 // we may need to re-pack it so that we don't have
194 // any empty blocks left (empty blocks upset the
195 // walking code).
196 void pack_ptr_list(struct ptr_list **listp)
198 struct ptr_list *head = *listp;
200 if (head) {
201 struct ptr_list *entry = head;
202 do {
203 struct ptr_list *next;
204 restart:
205 next = entry->next;
206 if (!entry->nr) {
207 struct ptr_list *prev;
208 if (next == entry) {
209 __free_ptrlist(entry);
210 *listp = NULL;
211 return;
213 prev = entry->prev;
214 prev->next = next;
215 next->prev = prev;
216 __free_ptrlist(entry);
217 if (entry == head) {
218 *listp = next;
219 head = next;
220 entry = next;
221 goto restart;
224 entry = next;
225 } while (entry != head);
230 // split a ptrlist block
231 // @head: the ptrlist block to be split
233 // A new block is inserted just after @head and the entries
234 // at the half end of @head are moved to this new block.
235 // The goal being to create space inside @head for a new entry.
236 void split_ptr_list_head(struct ptr_list *head)
238 int old = head->nr, nr = old / 2;
239 struct ptr_list *newlist = __alloc_ptrlist(0);
240 struct ptr_list *next = head->next;
242 old -= nr;
243 head->nr = old;
244 newlist->next = next;
245 next->prev = newlist;
246 newlist->prev = head;
247 head->next = newlist;
248 newlist->nr = nr;
249 memcpy(newlist->list, head->list + old, nr * sizeof(void *));
250 memset(head->list + old, 0xf0, nr * sizeof(void *));
253 int rl_ptrlist_hack;
255 // add an entry to a ptrlist
256 // @listp: a pointer to the list
257 // @ptr: the entry to add to the list
258 // @return: the address where the new entry is stored.
260 // :note: code must not use this function and should use
261 // :func:`add_ptr_list` instead.
262 void **__add_ptr_list(struct ptr_list **listp, void *ptr)
264 struct ptr_list *list = *listp;
265 struct ptr_list *last = NULL; /* gcc complains needlessly */
266 void **ret;
267 int nr;
269 if (!list || (nr = (last = list->prev)->nr) >= LIST_NODE_NR) {
270 struct ptr_list *newlist;
272 if (rl_ptrlist_hack)
273 newlist = __alloc_rl_ptrlist(0);
274 else
275 newlist = __alloc_ptrlist(0);
276 if (!list) {
277 newlist->next = newlist;
278 newlist->prev = newlist;
279 *listp = newlist;
280 } else {
281 newlist->prev = last;
282 newlist->next = list;
283 list->prev = newlist;
284 last->next = newlist;
286 last = newlist;
287 nr = 0;
289 ret = last->list + nr;
290 *ret = ptr;
291 nr++;
292 last->nr = nr;
293 return ret;
297 // add a tagged entry to a ptrlist
298 // @listp: a pointer to the list
299 // @ptr: the entry to add to the list
300 // @tag: the tag to add to @ptr
301 // @return: the address where the new entry is stored.
303 // :note: code must not use this function and should use
304 // :func:`add_ptr_list_tag` instead.
305 void **__add_ptr_list_tag(struct ptr_list **listp, void *ptr, unsigned long tag)
307 /* The low two bits are reserved for tags */
308 assert((3 & (unsigned long)ptr) == 0);
309 assert((~3 & tag) == 0);
311 ptr = (void *)(tag | (unsigned long)ptr);
313 return __add_ptr_list(listp, ptr);
317 // test if some entry is already present in a ptrlist
318 // @list: the head of the list
319 // @entry: the entry to test
320 // @return: ``true`` if the entry is already present, ``false`` otherwise.
321 bool lookup_ptr_list_entry(const struct ptr_list *head, const void *entry)
323 const struct ptr_list *list = head;
325 if (!head)
326 return false;
327 do {
328 int nr = list->nr;
329 int i;
330 for (i = 0; i < nr; i++)
331 if (list->list[i] == entry)
332 return true;
333 } while ((list = list->next) != head);
334 return false;
338 // delete an entry from a ptrlist
339 // @list: a pointer to the list
340 // @entry: the item to be deleted
341 // @count: the minimum number of times @entry should be deleted or 0.
342 int delete_ptr_list_entry(struct ptr_list **list, void *entry, int count)
344 void *ptr;
346 FOR_EACH_PTR(*list, ptr) {
347 if (ptr == entry) {
348 DELETE_CURRENT_PTR(ptr);
349 if (!--count)
350 goto out;
352 } END_FOR_EACH_PTR(ptr);
353 assert(count <= 0);
354 out:
355 pack_ptr_list(list);
356 return count;
360 // replace an entry in a ptrlist
361 // @list: a pointer to the list
362 // @old_ptr: the entry to be replaced
363 // @new_ptr: the new entry
364 // @count: the minimum number of times @entry should be deleted or 0.
365 int replace_ptr_list_entry(struct ptr_list **list, void *old_ptr,
366 void *new_ptr, int count)
368 void *ptr;
370 FOR_EACH_PTR(*list, ptr) {
371 if (ptr==old_ptr) {
372 REPLACE_CURRENT_PTR(ptr, new_ptr);
373 if (!--count)
374 goto out;
376 }END_FOR_EACH_PTR(ptr);
377 assert(count <= 0);
378 out:
379 return count;
383 // remove the last entry of a ptrlist
384 // @head: a pointer to the list
385 // @return: the last element of the list or NULL if the list is empty.
387 // :note: this doesn't repack the list
388 void * undo_ptr_list_last(struct ptr_list **head)
390 struct ptr_list *last, *first = *head;
392 if (!first)
393 return NULL;
394 last = first;
395 do {
396 last = last->prev;
397 if (last->nr) {
398 void *ptr;
399 int nr = --last->nr;
400 ptr = last->list[nr];
401 last->list[nr] = (void *)0xf1f1f1f1;
402 return ptr;
404 } while (last != first);
405 return NULL;
409 // remove the last entry and repack the list
410 // @head: a pointer to the list
411 // @return: the last element of the list or NULL if the list is empty.
412 void * delete_ptr_list_last(struct ptr_list **head)
414 void *ptr = NULL;
415 struct ptr_list *last, *first = *head;
417 if (!first)
418 return NULL;
419 last = first->prev;
420 if (last->nr)
421 ptr = last->list[--last->nr];
422 if (last->nr <=0) {
423 first->prev = last->prev;
424 last->prev->next = first;
425 if (last == first)
426 *head = NULL;
427 __free_ptrlist(last);
429 return ptr;
433 // concat two ptrlists
434 // @a: the source list
435 // @b: a pointer to the destination list.
436 // The element of @a are added at the end of @b.
437 void concat_ptr_list(struct ptr_list *a, struct ptr_list **b)
439 void *entry;
440 FOR_EACH_PTR(a, entry) {
441 add_ptr_list(b, entry);
442 } END_FOR_EACH_PTR(entry);
446 // copy the elements of a list at the end of another list.
447 // @listp: a pointer to the destination list.
448 // @src: the head of the source list.
449 void copy_ptr_list(struct ptr_list **listp, struct ptr_list *src)
451 struct ptr_list *head, *tail;
452 struct ptr_list *cur = src;
453 int idx;
455 if (!src)
456 return;
457 head = *listp;
458 if (!head) {
459 *listp = src;
460 return;
463 tail = head->prev;
464 idx = tail->nr;
465 do {
466 struct ptr_list *next;
467 int nr = cur->nr;
468 int i;
469 for (i = 0; i < nr;) {
470 void *ptr = cur->list[i++];
471 if (!ptr)
472 continue;
473 if (idx >= LIST_NODE_NR) {
474 struct ptr_list *prev = tail;
475 tail = __alloc_ptrlist(0);
476 prev->next = tail;
477 tail->prev = prev;
478 prev->nr = idx;
479 idx = 0;
481 tail->list[idx++] = ptr;
484 next = cur->next;
485 __free_ptrlist(cur);
486 cur = next;
487 } while (cur != src);
489 tail->nr = idx;
490 head->prev = tail;
491 tail->next = head;
495 // free a ptrlist
496 // @listp: a pointer to the list
497 // Each blocks of the list are freed (but the entries
498 // themselves are not freed).
500 // :note: code must not use this function and should use
501 // the macro :func:`free_ptr_list` instead.
502 void __free_ptr_list(struct ptr_list **listp)
504 struct ptr_list *tmp, *list = *listp;
506 if (!list)
507 return;
509 list->prev->next = NULL;
510 while (list) {
511 tmp = list;
512 list = list->next;
513 __free_ptrlist(tmp);
516 *listp = NULL;