xref: /illumos-gate/usr/src/tools/smatch/src/ptrlist.c (revision c85f09cc)
11f5207b7SJohn Levon /*
21f5207b7SJohn Levon  * ptrlist.c
31f5207b7SJohn Levon  *
41f5207b7SJohn Levon  * (C) Copyright Linus Torvalds 2003-2005
51f5207b7SJohn Levon  */
6*c85f09ccSJohn Levon 
7*c85f09ccSJohn Levon ///
8*c85f09ccSJohn Levon // Pointer list manipulation
9*c85f09ccSJohn Levon // -------------------------
10*c85f09ccSJohn Levon 
111f5207b7SJohn Levon #include <stdlib.h>
121f5207b7SJohn Levon #include <string.h>
131f5207b7SJohn Levon #include <assert.h>
141f5207b7SJohn Levon 
151f5207b7SJohn Levon #include "ptrlist.h"
161f5207b7SJohn Levon #include "allocate.h"
171f5207b7SJohn Levon #include "compat.h"
181f5207b7SJohn Levon 
191f5207b7SJohn Levon __DECLARE_ALLOCATOR(struct ptr_list, ptrlist);
201f5207b7SJohn Levon __ALLOCATOR(struct ptr_list, "ptr list", ptrlist);
211f5207b7SJohn Levon __ALLOCATOR(struct ptr_list, "rl ptr list", rl_ptrlist);
221f5207b7SJohn Levon 
23*c85f09ccSJohn Levon ///
24*c85f09ccSJohn Levon // get the size of a ptrlist
25*c85f09ccSJohn Levon // @head: the head of the list
26*c85f09ccSJohn Levon // @return: the size of the list given by @head.
ptr_list_size(struct ptr_list * head)271f5207b7SJohn Levon int ptr_list_size(struct ptr_list *head)
281f5207b7SJohn Levon {
291f5207b7SJohn Levon 	int nr = 0;
301f5207b7SJohn Levon 
311f5207b7SJohn Levon 	if (head) {
321f5207b7SJohn Levon 		struct ptr_list *list = head;
331f5207b7SJohn Levon 		do {
341f5207b7SJohn Levon 			nr += list->nr - list->rm;
351f5207b7SJohn Levon 		} while ((list = list->next) != head);
361f5207b7SJohn Levon 	}
371f5207b7SJohn Levon 	return nr;
381f5207b7SJohn Levon }
391f5207b7SJohn Levon 
40*c85f09ccSJohn Levon ///
41*c85f09ccSJohn Levon // test if a list is empty
42*c85f09ccSJohn Levon // @head: the head of the list
43*c85f09ccSJohn Levon // @return: ``true`` if the list is empty, ``false`` otherwise.
ptr_list_empty(const struct ptr_list * head)44*c85f09ccSJohn Levon bool ptr_list_empty(const struct ptr_list *head)
45*c85f09ccSJohn Levon {
46*c85f09ccSJohn Levon 	const struct ptr_list *list = head;
47*c85f09ccSJohn Levon 
48*c85f09ccSJohn Levon 	if (!head)
49*c85f09ccSJohn Levon 		return true;
50*c85f09ccSJohn Levon 
51*c85f09ccSJohn Levon 	do {
52*c85f09ccSJohn Levon 		if (list->nr - list->rm)
53*c85f09ccSJohn Levon 			return false;
54*c85f09ccSJohn Levon 	} while ((list = list->next) != head);
55*c85f09ccSJohn Levon 
56*c85f09ccSJohn Levon 	return true;
57*c85f09ccSJohn Levon }
58*c85f09ccSJohn Levon 
59*c85f09ccSJohn Levon ///
60*c85f09ccSJohn Levon // test is a list contains more than one element
61*c85f09ccSJohn Levon // @head: the head of the list
62*c85f09ccSJohn Levon // @return: ``true`` if the list has more than 1 element, ``false`` otherwise.
ptr_list_multiple(const struct ptr_list * head)63*c85f09ccSJohn Levon bool ptr_list_multiple(const struct ptr_list *head)
64*c85f09ccSJohn Levon {
65*c85f09ccSJohn Levon 	const struct ptr_list *list = head;
66*c85f09ccSJohn Levon 	int nr = 0;
67*c85f09ccSJohn Levon 
68*c85f09ccSJohn Levon 	if (!head)
69*c85f09ccSJohn Levon 		return false;
70*c85f09ccSJohn Levon 
71*c85f09ccSJohn Levon 	do {
72*c85f09ccSJohn Levon 		nr += list->nr - list->rm;
73*c85f09ccSJohn Levon 		if (nr > 1)
74*c85f09ccSJohn Levon 			return true;
75*c85f09ccSJohn Levon 	} while ((list = list->next) != head);
76*c85f09ccSJohn Levon 
77*c85f09ccSJohn Levon 	return false;
78*c85f09ccSJohn Levon }
79*c85f09ccSJohn Levon 
80*c85f09ccSJohn Levon ///
81*c85f09ccSJohn Levon // get the first element of a ptrlist
82*c85f09ccSJohn Levon // @head: the head of the list
83*c85f09ccSJohn Levon // @return: the first element of the list or ``NULL`` if the list is empty
first_ptr_list(struct ptr_list * head)84*c85f09ccSJohn Levon void *first_ptr_list(struct ptr_list *head)
85*c85f09ccSJohn Levon {
86*c85f09ccSJohn Levon 	struct ptr_list *list = head;
87*c85f09ccSJohn Levon 
88*c85f09ccSJohn Levon 	if (!head)
89*c85f09ccSJohn Levon 		return NULL;
90*c85f09ccSJohn Levon 
91*c85f09ccSJohn Levon 	while (list->nr == 0) {
92*c85f09ccSJohn Levon 		list = list->next;
93*c85f09ccSJohn Levon 		if (list == head)
94*c85f09ccSJohn Levon 			return NULL;
95*c85f09ccSJohn Levon 	}
96*c85f09ccSJohn Levon 	return PTR_ENTRY_NOTAG(list, 0);
97*c85f09ccSJohn Levon }
98*c85f09ccSJohn Levon 
99*c85f09ccSJohn Levon ///
100*c85f09ccSJohn Levon // get the last element of a ptrlist
101*c85f09ccSJohn Levon // @head: the head of the list
102*c85f09ccSJohn Levon // @return: the last element of the list or ``NULL`` if the list is empty
last_ptr_list(struct ptr_list * head)103*c85f09ccSJohn Levon void *last_ptr_list(struct ptr_list *head)
104*c85f09ccSJohn Levon {
105*c85f09ccSJohn Levon 	struct ptr_list *list;
106*c85f09ccSJohn Levon 
107*c85f09ccSJohn Levon 	if (!head)
108*c85f09ccSJohn Levon 		return NULL;
109*c85f09ccSJohn Levon 	list = head->prev;
110*c85f09ccSJohn Levon 	while (list->nr == 0) {
111*c85f09ccSJohn Levon 		if (list == head)
112*c85f09ccSJohn Levon 			return NULL;
113*c85f09ccSJohn Levon 		list = list->prev;
114*c85f09ccSJohn Levon 	}
115*c85f09ccSJohn Levon 	return PTR_ENTRY_NOTAG(list, list->nr-1);
116*c85f09ccSJohn Levon }
117*c85f09ccSJohn Levon 
118*c85f09ccSJohn Levon ///
119*c85f09ccSJohn Levon // get the nth element of a ptrlist
120*c85f09ccSJohn Levon // @head: the head of the list
121*c85f09ccSJohn Levon // @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)122*c85f09ccSJohn Levon void *ptr_list_nth_entry(struct ptr_list *list, unsigned int idx)
123*c85f09ccSJohn Levon {
124*c85f09ccSJohn Levon 	struct ptr_list *head = list;
125*c85f09ccSJohn Levon 
126*c85f09ccSJohn Levon 	if (!head)
127*c85f09ccSJohn Levon 		return NULL;
128*c85f09ccSJohn Levon 
129*c85f09ccSJohn Levon 	do {
130*c85f09ccSJohn Levon 		unsigned int nr = list->nr;
131*c85f09ccSJohn Levon 
132*c85f09ccSJohn Levon 		if (idx < nr)
133*c85f09ccSJohn Levon 			return list->list[idx];
134*c85f09ccSJohn Levon 		else
135*c85f09ccSJohn Levon 			idx -= nr;
136*c85f09ccSJohn Levon 	} while ((list = list->next) != head);
137*c85f09ccSJohn Levon 	return NULL;
138*c85f09ccSJohn Levon }
139*c85f09ccSJohn Levon 
140*c85f09ccSJohn Levon ///
141*c85f09ccSJohn Levon // linearize the entries of a list
142*c85f09ccSJohn Levon //
143*c85f09ccSJohn Levon // @head: the list to be linearized
144*c85f09ccSJohn Levon // @arr: a ``void*`` array to fill with @head's entries
145*c85f09ccSJohn Levon // @max: the maximum number of entries to store into @arr
146*c85f09ccSJohn Levon // @return: the number of entries linearized.
147*c85f09ccSJohn Levon //
148*c85f09ccSJohn Levon // Linearize the entries of a list up to a total of @max,
149*c85f09ccSJohn Levon // and return the nr of entries linearized.
150*c85f09ccSJohn Levon //
151*c85f09ccSJohn Levon // The array to linearize into (@arr) should really
152*c85f09ccSJohn Levon // be ``void *x[]``, but we want to let people fill in any kind
153*c85f09ccSJohn Levon // of pointer array, so let's just call it ``void **``.
linearize_ptr_list(struct ptr_list * head,void ** arr,int max)1541f5207b7SJohn Levon int linearize_ptr_list(struct ptr_list *head, void **arr, int max)
1551f5207b7SJohn Levon {
1561f5207b7SJohn Levon 	int nr = 0;
1571f5207b7SJohn Levon 	if (head && max > 0) {
1581f5207b7SJohn Levon 		struct ptr_list *list = head;
1591f5207b7SJohn Levon 
1601f5207b7SJohn Levon 		do {
1611f5207b7SJohn Levon 			int i = list->nr;
1621f5207b7SJohn Levon 			if (i > max)
1631f5207b7SJohn Levon 				i = max;
1641f5207b7SJohn Levon 			memcpy(arr, list->list, i*sizeof(void *));
1651f5207b7SJohn Levon 			arr += i;
1661f5207b7SJohn Levon 			nr += i;
1671f5207b7SJohn Levon 			max -= i;
1681f5207b7SJohn Levon 			if (!max)
1691f5207b7SJohn Levon 				break;
1701f5207b7SJohn Levon 		} while ((list = list->next) != head);
1711f5207b7SJohn Levon 	}
1721f5207b7SJohn Levon 	return nr;
1731f5207b7SJohn Levon }
1741f5207b7SJohn Levon 
175*c85f09ccSJohn Levon ///
176*c85f09ccSJohn Levon // pack a ptrlist
177*c85f09ccSJohn Levon //
178*c85f09ccSJohn Levon // @listp: a pointer to the list to be packed.
179*c85f09ccSJohn Levon //
180*c85f09ccSJohn Levon // When we've walked the list and deleted entries,
181*c85f09ccSJohn Levon // we may need to re-pack it so that we don't have
182*c85f09ccSJohn Levon // any empty blocks left (empty blocks upset the
183*c85f09ccSJohn Levon // walking code).
pack_ptr_list(struct ptr_list ** listp)1841f5207b7SJohn Levon void pack_ptr_list(struct ptr_list **listp)
1851f5207b7SJohn Levon {
1861f5207b7SJohn Levon 	struct ptr_list *head = *listp;
1871f5207b7SJohn Levon 
1881f5207b7SJohn Levon 	if (head) {
1891f5207b7SJohn Levon 		struct ptr_list *entry = head;
1901f5207b7SJohn Levon 		do {
1911f5207b7SJohn Levon 			struct ptr_list *next;
1921f5207b7SJohn Levon restart:
1931f5207b7SJohn Levon 			next = entry->next;
1941f5207b7SJohn Levon 			if (!entry->nr) {
1951f5207b7SJohn Levon 				struct ptr_list *prev;
1961f5207b7SJohn Levon 				if (next == entry) {
1971f5207b7SJohn Levon 					__free_ptrlist(entry);
1981f5207b7SJohn Levon 					*listp = NULL;
1991f5207b7SJohn Levon 					return;
2001f5207b7SJohn Levon 				}
2011f5207b7SJohn Levon 				prev = entry->prev;
2021f5207b7SJohn Levon 				prev->next = next;
2031f5207b7SJohn Levon 				next->prev = prev;
2041f5207b7SJohn Levon 				__free_ptrlist(entry);
2051f5207b7SJohn Levon 				if (entry == head) {
2061f5207b7SJohn Levon 					*listp = next;
2071f5207b7SJohn Levon 					head = next;
2081f5207b7SJohn Levon 					entry = next;
2091f5207b7SJohn Levon 					goto restart;
2101f5207b7SJohn Levon 				}
2111f5207b7SJohn Levon 			}
2121f5207b7SJohn Levon 			entry = next;
2131f5207b7SJohn Levon 		} while (entry != head);
2141f5207b7SJohn Levon 	}
2151f5207b7SJohn Levon }
2161f5207b7SJohn Levon 
217*c85f09ccSJohn Levon ///
218*c85f09ccSJohn Levon // split a ptrlist block
219*c85f09ccSJohn Levon // @head: the ptrlist block to be splitted
220*c85f09ccSJohn Levon //
221*c85f09ccSJohn Levon // A new block is inserted just after @head and the entries
222*c85f09ccSJohn Levon // at the half end of @head are moved to this new block.
223*c85f09ccSJohn Levon // The goal being to create space inside @head for a new entry.
split_ptr_list_head(struct ptr_list * head)2241f5207b7SJohn Levon void split_ptr_list_head(struct ptr_list *head)
2251f5207b7SJohn Levon {
2261f5207b7SJohn Levon 	int old = head->nr, nr = old / 2;
2271f5207b7SJohn Levon 	struct ptr_list *newlist = __alloc_ptrlist(0);
2281f5207b7SJohn Levon 	struct ptr_list *next = head->next;
2291f5207b7SJohn Levon 
2301f5207b7SJohn Levon 	old -= nr;
2311f5207b7SJohn Levon 	head->nr = old;
2321f5207b7SJohn Levon 	newlist->next = next;
2331f5207b7SJohn Levon 	next->prev = newlist;
2341f5207b7SJohn Levon 	newlist->prev = head;
2351f5207b7SJohn Levon 	head->next = newlist;
2361f5207b7SJohn Levon 	newlist->nr = nr;
2371f5207b7SJohn Levon 	memcpy(newlist->list, head->list + old, nr * sizeof(void *));
2381f5207b7SJohn Levon 	memset(head->list + old, 0xf0, nr * sizeof(void *));
2391f5207b7SJohn Levon }
2401f5207b7SJohn Levon 
2411f5207b7SJohn Levon int rl_ptrlist_hack;
242*c85f09ccSJohn Levon ///
243*c85f09ccSJohn Levon // add an entry to a ptrlist
244*c85f09ccSJohn Levon // @listp: a pointer to the list
245*c85f09ccSJohn Levon // @ptr: the entry to add to the list
246*c85f09ccSJohn Levon // @return: the address where the new entry is stored.
247*c85f09ccSJohn Levon //
248*c85f09ccSJohn Levon // :note: code must not use this function and should use
249*c85f09ccSJohn Levon //	:func:`add_ptr_list` instead.
__add_ptr_list(struct ptr_list ** listp,void * ptr)250*c85f09ccSJohn Levon void **__add_ptr_list(struct ptr_list **listp, void *ptr)
2511f5207b7SJohn Levon {
2521f5207b7SJohn Levon 	struct ptr_list *list = *listp;
2531f5207b7SJohn Levon 	struct ptr_list *last = NULL; /* gcc complains needlessly */
2541f5207b7SJohn Levon 	void **ret;
2551f5207b7SJohn Levon 	int nr;
2561f5207b7SJohn Levon 
2571f5207b7SJohn Levon 	if (!list || (nr = (last = list->prev)->nr) >= LIST_NODE_NR) {
2581f5207b7SJohn Levon 		struct ptr_list *newlist;
2591f5207b7SJohn Levon 
2601f5207b7SJohn Levon 		if (rl_ptrlist_hack)
2611f5207b7SJohn Levon 			newlist = __alloc_rl_ptrlist(0);
2621f5207b7SJohn Levon 		else
2631f5207b7SJohn Levon 			newlist = __alloc_ptrlist(0);
2641f5207b7SJohn Levon 		if (!list) {
2651f5207b7SJohn Levon 			newlist->next = newlist;
2661f5207b7SJohn Levon 			newlist->prev = newlist;
2671f5207b7SJohn Levon 			*listp = newlist;
2681f5207b7SJohn Levon 		} else {
2691f5207b7SJohn Levon 			newlist->prev = last;
2701f5207b7SJohn Levon 			newlist->next = list;
2711f5207b7SJohn Levon 			list->prev = newlist;
2721f5207b7SJohn Levon 			last->next = newlist;
2731f5207b7SJohn Levon 		}
2741f5207b7SJohn Levon 		last = newlist;
2751f5207b7SJohn Levon 		nr = 0;
2761f5207b7SJohn Levon 	}
2771f5207b7SJohn Levon 	ret = last->list + nr;
2781f5207b7SJohn Levon 	*ret = ptr;
2791f5207b7SJohn Levon 	nr++;
2801f5207b7SJohn Levon 	last->nr = nr;
2811f5207b7SJohn Levon 	return ret;
2821f5207b7SJohn Levon }
2831f5207b7SJohn Levon 
284*c85f09ccSJohn Levon ///
285*c85f09ccSJohn Levon // add a tagged entry to a ptrlist
286*c85f09ccSJohn Levon // @listp: a pointer to the list
287*c85f09ccSJohn Levon // @ptr: the entry to add to the list
288*c85f09ccSJohn Levon // @tag: the tag to add to @ptr
289*c85f09ccSJohn Levon // @return: the address where the new entry is stored.
290*c85f09ccSJohn Levon //
291*c85f09ccSJohn Levon // :note: code must not use this function and should use
292*c85f09ccSJohn Levon //	:func:`add_ptr_list_tag` instead.
__add_ptr_list_tag(struct ptr_list ** listp,void * ptr,unsigned long tag)293*c85f09ccSJohn Levon void **__add_ptr_list_tag(struct ptr_list **listp, void *ptr, unsigned long tag)
294*c85f09ccSJohn Levon {
295*c85f09ccSJohn Levon 	/* The low two bits are reserved for tags */
296*c85f09ccSJohn Levon 	assert((3 & (unsigned long)ptr) == 0);
297*c85f09ccSJohn Levon 	assert((~3 & tag) == 0);
298*c85f09ccSJohn Levon 
299*c85f09ccSJohn Levon 	ptr = (void *)(tag | (unsigned long)ptr);
300*c85f09ccSJohn Levon 
301*c85f09ccSJohn Levon 	return __add_ptr_list(listp, ptr);
302*c85f09ccSJohn Levon }
303*c85f09ccSJohn Levon 
304*c85f09ccSJohn Levon ///
305*c85f09ccSJohn Levon // test if some entry is already present in a ptrlist
306*c85f09ccSJohn Levon // @list: the head of the list
307*c85f09ccSJohn Levon // @entry: the entry to test
308*c85f09ccSJohn Levon // @return: ``true`` if the entry is already present, ``false`` otherwise.
lookup_ptr_list_entry(const struct ptr_list * head,const void * entry)309*c85f09ccSJohn Levon bool lookup_ptr_list_entry(const struct ptr_list *head, const void *entry)
310*c85f09ccSJohn Levon {
311*c85f09ccSJohn Levon 	const struct ptr_list *list = head;
312*c85f09ccSJohn Levon 
313*c85f09ccSJohn Levon 	if (!head)
314*c85f09ccSJohn Levon 		return false;
315*c85f09ccSJohn Levon 	do {
316*c85f09ccSJohn Levon 		int nr = list->nr;
317*c85f09ccSJohn Levon 		int i;
318*c85f09ccSJohn Levon 		for (i = 0; i < nr; i++)
319*c85f09ccSJohn Levon 			if (list->list[i] == entry)
320*c85f09ccSJohn Levon 				return true;
321*c85f09ccSJohn Levon 	} while ((list = list->next) != head);
322*c85f09ccSJohn Levon 	return false;
323*c85f09ccSJohn Levon }
324*c85f09ccSJohn Levon 
325*c85f09ccSJohn Levon ///
326*c85f09ccSJohn Levon // delete an entry from a ptrlist
327*c85f09ccSJohn Levon // @list: a pointer to the list
328*c85f09ccSJohn Levon // @entry: the item to be deleted
329*c85f09ccSJohn Levon // @count: the minimum number of times @entry should be deleted or 0.
delete_ptr_list_entry(struct ptr_list ** list,void * entry,int count)3301f5207b7SJohn Levon int delete_ptr_list_entry(struct ptr_list **list, void *entry, int count)
3311f5207b7SJohn Levon {
3321f5207b7SJohn Levon 	void *ptr;
3331f5207b7SJohn Levon 
3341f5207b7SJohn Levon 	FOR_EACH_PTR(*list, ptr) {
3351f5207b7SJohn Levon 		if (ptr == entry) {
3361f5207b7SJohn Levon 			DELETE_CURRENT_PTR(ptr);
3371f5207b7SJohn Levon 			if (!--count)
3381f5207b7SJohn Levon 				goto out;
3391f5207b7SJohn Levon 		}
3401f5207b7SJohn Levon 	} END_FOR_EACH_PTR(ptr);
3411f5207b7SJohn Levon 	assert(count <= 0);
3421f5207b7SJohn Levon out:
3431f5207b7SJohn Levon 	pack_ptr_list(list);
3441f5207b7SJohn Levon 	return count;
3451f5207b7SJohn Levon }
3461f5207b7SJohn Levon 
347*c85f09ccSJohn Levon ///
348*c85f09ccSJohn Levon // replace an entry in a ptrlist
349*c85f09ccSJohn Levon // @list: a pointer to the list
350*c85f09ccSJohn Levon // @old_ptr: the entry to be replaced
351*c85f09ccSJohn Levon // @new_ptr: the new entry
352*c85f09ccSJohn Levon // @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)353*c85f09ccSJohn Levon int replace_ptr_list_entry(struct ptr_list **list, void *old_ptr,
354*c85f09ccSJohn Levon 	void *new_ptr, int count)
3551f5207b7SJohn Levon {
3561f5207b7SJohn Levon 	void *ptr;
3571f5207b7SJohn Levon 
3581f5207b7SJohn Levon 	FOR_EACH_PTR(*list, ptr) {
3591f5207b7SJohn Levon 		if (ptr==old_ptr) {
3601f5207b7SJohn Levon 			REPLACE_CURRENT_PTR(ptr, new_ptr);
3611f5207b7SJohn Levon 			if (!--count)
3621f5207b7SJohn Levon 				goto out;
3631f5207b7SJohn Levon 		}
3641f5207b7SJohn Levon 	}END_FOR_EACH_PTR(ptr);
3651f5207b7SJohn Levon 	assert(count <= 0);
3661f5207b7SJohn Levon out:
3671f5207b7SJohn Levon 	return count;
3681f5207b7SJohn Levon }
3691f5207b7SJohn Levon 
370*c85f09ccSJohn Levon ///
371*c85f09ccSJohn Levon // remove the last entry of a ptrlist
372*c85f09ccSJohn Levon // @head: a pointer to the list
373*c85f09ccSJohn Levon // @return: the last elemant of the list or NULL if the list is empty.
374*c85f09ccSJohn Levon //
375*c85f09ccSJohn Levon // :note: this doesn't repack the list
undo_ptr_list_last(struct ptr_list ** head)3761f5207b7SJohn Levon void * undo_ptr_list_last(struct ptr_list **head)
3771f5207b7SJohn Levon {
3781f5207b7SJohn Levon 	struct ptr_list *last, *first = *head;
3791f5207b7SJohn Levon 
3801f5207b7SJohn Levon 	if (!first)
3811f5207b7SJohn Levon 		return NULL;
3821f5207b7SJohn Levon 	last = first;
3831f5207b7SJohn Levon 	do {
3841f5207b7SJohn Levon 		last = last->prev;
3851f5207b7SJohn Levon 		if (last->nr) {
3861f5207b7SJohn Levon 			void *ptr;
3871f5207b7SJohn Levon 			int nr = --last->nr;
3881f5207b7SJohn Levon 			ptr = last->list[nr];
3891f5207b7SJohn Levon 			last->list[nr] = (void *)0xf1f1f1f1;
3901f5207b7SJohn Levon 			return ptr;
3911f5207b7SJohn Levon 		}
3921f5207b7SJohn Levon 	} while (last != first);
3931f5207b7SJohn Levon 	return NULL;
3941f5207b7SJohn Levon }
3951f5207b7SJohn Levon 
396*c85f09ccSJohn Levon ///
397*c85f09ccSJohn Levon // remove the last entry and repack the list
398*c85f09ccSJohn Levon // @head: a pointer to the list
399*c85f09ccSJohn Levon // @return: the last elemant of the list or NULL if the list is empty.
delete_ptr_list_last(struct ptr_list ** head)4001f5207b7SJohn Levon void * delete_ptr_list_last(struct ptr_list **head)
4011f5207b7SJohn Levon {
4021f5207b7SJohn Levon 	void *ptr = NULL;
4031f5207b7SJohn Levon 	struct ptr_list *last, *first = *head;
4041f5207b7SJohn Levon 
4051f5207b7SJohn Levon 	if (!first)
4061f5207b7SJohn Levon 		return NULL;
4071f5207b7SJohn Levon 	last = first->prev;
4081f5207b7SJohn Levon 	if (last->nr)
4091f5207b7SJohn Levon 		ptr = last->list[--last->nr];
4101f5207b7SJohn Levon 	if (last->nr <=0) {
4111f5207b7SJohn Levon 		first->prev = last->prev;
4121f5207b7SJohn Levon 		last->prev->next = first;
4131f5207b7SJohn Levon 		if (last == first)
4141f5207b7SJohn Levon 			*head = NULL;
4151f5207b7SJohn Levon 		__free_ptrlist(last);
4161f5207b7SJohn Levon 	}
4171f5207b7SJohn Levon 	return ptr;
4181f5207b7SJohn Levon }
4191f5207b7SJohn Levon 
420*c85f09ccSJohn Levon ///
421*c85f09ccSJohn Levon // concat two ptrlists
422*c85f09ccSJohn Levon // @a: the source list
423*c85f09ccSJohn Levon // @b: a pointer to the destination list.
424*c85f09ccSJohn Levon // The element of @a are added at the end of @b.
concat_ptr_list(struct ptr_list * a,struct ptr_list ** b)4251f5207b7SJohn Levon void concat_ptr_list(struct ptr_list *a, struct ptr_list **b)
4261f5207b7SJohn Levon {
4271f5207b7SJohn Levon 	void *entry;
4281f5207b7SJohn Levon 	FOR_EACH_PTR(a, entry) {
4291f5207b7SJohn Levon 		add_ptr_list(b, entry);
4301f5207b7SJohn Levon 	} END_FOR_EACH_PTR(entry);
4311f5207b7SJohn Levon }
4321f5207b7SJohn Levon 
433*c85f09ccSJohn Levon ///
434*c85f09ccSJohn Levon // copy the elements of a list at the end of another list.
435*c85f09ccSJohn Levon // @listp: a pointer to the destination list.
436*c85f09ccSJohn Levon // @src: the head of the source list.
copy_ptr_list(struct ptr_list ** listp,struct ptr_list * src)437*c85f09ccSJohn Levon void copy_ptr_list(struct ptr_list **listp, struct ptr_list *src)
438*c85f09ccSJohn Levon {
439*c85f09ccSJohn Levon 	struct ptr_list *head, *tail;
440*c85f09ccSJohn Levon 	struct ptr_list *cur = src;
441*c85f09ccSJohn Levon 	int idx;
442*c85f09ccSJohn Levon 
443*c85f09ccSJohn Levon 	if (!src)
444*c85f09ccSJohn Levon 		return;
445*c85f09ccSJohn Levon 	head = *listp;
446*c85f09ccSJohn Levon 	if (!head) {
447*c85f09ccSJohn Levon 		*listp = src;
448*c85f09ccSJohn Levon 		return;
449*c85f09ccSJohn Levon 	}
450*c85f09ccSJohn Levon 
451*c85f09ccSJohn Levon 	tail = head->prev;
452*c85f09ccSJohn Levon 	idx = tail->nr;
453*c85f09ccSJohn Levon 	do {
454*c85f09ccSJohn Levon 		struct ptr_list *next;
455*c85f09ccSJohn Levon 		int nr = cur->nr;
456*c85f09ccSJohn Levon 		int i;
457*c85f09ccSJohn Levon 		for (i = 0; i < nr;) {
458*c85f09ccSJohn Levon 			void *ptr = cur->list[i++];
459*c85f09ccSJohn Levon 			if (!ptr)
460*c85f09ccSJohn Levon 				continue;
461*c85f09ccSJohn Levon 			if (idx >= LIST_NODE_NR) {
462*c85f09ccSJohn Levon 				struct ptr_list *prev = tail;
463*c85f09ccSJohn Levon 				tail = __alloc_ptrlist(0);
464*c85f09ccSJohn Levon 				prev->next = tail;
465*c85f09ccSJohn Levon 				tail->prev = prev;
466*c85f09ccSJohn Levon 				prev->nr = idx;
467*c85f09ccSJohn Levon 				idx = 0;
468*c85f09ccSJohn Levon 			}
469*c85f09ccSJohn Levon 			tail->list[idx++] = ptr;
470*c85f09ccSJohn Levon 		}
471*c85f09ccSJohn Levon 
472*c85f09ccSJohn Levon 		next = cur->next;
473*c85f09ccSJohn Levon 		__free_ptrlist(cur);
474*c85f09ccSJohn Levon 		cur = next;
475*c85f09ccSJohn Levon 	} while (cur != src);
476*c85f09ccSJohn Levon 
477*c85f09ccSJohn Levon 	tail->nr = idx;
478*c85f09ccSJohn Levon 	head->prev = tail;
479*c85f09ccSJohn Levon 	tail->next = head;
480*c85f09ccSJohn Levon }
481*c85f09ccSJohn Levon 
482*c85f09ccSJohn Levon ///
483*c85f09ccSJohn Levon // free a ptrlist
484*c85f09ccSJohn Levon // @listp: a pointer to the list
485*c85f09ccSJohn Levon // Each blocks of the list are freed (but the entries
486*c85f09ccSJohn Levon // themselves are not freed).
487*c85f09ccSJohn Levon //
488*c85f09ccSJohn Levon // :note: code must not use this function and should use
489*c85f09ccSJohn Levon //	the macro :func:`free_ptr_list` instead.
__free_ptr_list(struct ptr_list ** listp)4901f5207b7SJohn Levon void __free_ptr_list(struct ptr_list **listp)
4911f5207b7SJohn Levon {
4921f5207b7SJohn Levon 	struct ptr_list *tmp, *list = *listp;
4931f5207b7SJohn Levon 
4941f5207b7SJohn Levon 	if (!list)
4951f5207b7SJohn Levon 		return;
4961f5207b7SJohn Levon 
4971f5207b7SJohn Levon 	list->prev->next = NULL;
4981f5207b7SJohn Levon 	while (list) {
4991f5207b7SJohn Levon 		tmp = list;
5001f5207b7SJohn Levon 		list = list->next;
5011f5207b7SJohn Levon 		__free_ptrlist(tmp);
5021f5207b7SJohn Levon 	}
5031f5207b7SJohn Levon 
5041f5207b7SJohn Levon 	*listp = NULL;
5051f5207b7SJohn Levon }
506