1 //metadoc List copyright Steve Dekorte 2002
2 //metadoc List license BSD revised
3 /*metadoc List description
4 List is an array of void pointers.
5 The List is not responsible for io_freeing its elements.
6 */
7 
8 #ifdef LIST_C
9 #define IO_IN_C_FILE
10 #endif
11 #include "Common_inline.h"
12 #include "PortableSorting.h"
13 #ifdef IO_DECLARE_INLINES
14 
15 #define LIST_FOREACH(list, index, value, code) \
16 { \
17 	const List *foreachList = list; \
18 	size_t index, foreachMax = foreachList->size; \
19 	\
20 	for (index = 0; index < foreachMax; index ++) \
21 	{ \
22 		void *value = foreachList->items[index]; \
23 		code; \
24 	} \
25 }
26 
27 #define LIST_SAFEFOREACH(list, index, value, code) \
28 { \
29 	const List *foreachList = list; \
30 	size_t index; \
31 	\
32 	for (index = 0; index < List_size(foreachList); index ++) \
33 	{ \
34 		void *value = List_at_(foreachList, index); \
35 		code; \
36 	} \
37 }
38 
39 #define LIST_REVERSEFOREACH(list, index, value, code) \
40 { \
41 	const List *foreachList = list; \
42 	size_t index = List_size(foreachList); \
43 	\
44 	while (index) \
45 	{ \
46 		void *value = List_at_(foreachList, (index --)); \
47 		code; \
48 	} \
49 }
50 
51 #define LIST_SAFEREVERSEFOREACH(list, index, value, code) \
52 { \
53 	const List *foreachList = list; \
54 	size_t index = List_size(foreachList); \
55 	\
56 	for (index = List_size(foreachList) - 1; index > 0; index --) \
57 	{ \
58 		void *value = List_at_(foreachList, index); \
59 		code; \
60 		if (index > List_size(foreachList) - 1) { index = List_size(foreachList) - 1; } \
61 	} \
62 }
63 
64 #define LIST_DO_(list, func) \
65 { \
66 	const List *foreachList = list; \
67 	size_t index, foreachMax = List_size(foreachList); \
68 	\
69 	for (index = 0; index < foreachMax; index ++) \
70 	{ \
71 		func(List_at_(foreachList, index)); \
72 	} \
73 }
74 
List_size(const List * self)75 IOINLINE size_t List_size(const List *self)
76 {
77 	return self->size;
78 }
79 
List_ifNeededSizeTo_(List * self,size_t newSize)80 IOINLINE void List_ifNeededSizeTo_(List *self, size_t newSize)
81 {
82 	if (newSize * sizeof(void *) >= self->memSize)
83 	{
84 		List_preallocateToSize_(self, newSize);
85 	}
86 }
87 
List_rawAt_(List * self,size_t index)88 IOINLINE void *List_rawAt_(List *self, size_t index)
89 {
90 	return self->items[index];
91 }
92 
93 
List_at_(const List * self,ssize_t index)94 IOINLINE void *List_at_(const List *self, ssize_t index)
95 {
96 
97     /* Negative indexing is also supported. */
98     if (index < 0)
99     {
100         index += self->size;
101     }
102 
103     if (index < self->size)
104     {
105         return self->items[index];
106     }
107 
108     return (void *)NULL;
109 }
110 
111 // --------------------------------------------
112 
List_indexOf_(List * self,void * item)113 IOINLINE size_t List_indexOf_(List *self, void *item)
114 {
115 	LIST_FOREACH(self, i, v, if(v == item) return i);
116 	return -1;
117 }
118 
List_contains_(List * self,void * item)119 IOINLINE int List_contains_(List *self, void *item)
120 {
121 	LIST_FOREACH(self, i, v, if(v == item) return 1);
122 	return 0;
123 }
124 
List_append_(List * self,void * item)125 IOINLINE void *List_append_(List *self, void *item)
126 {
127 	List_ifNeededSizeTo_(self, self->size + 1);
128 	self->items[self->size] = item;
129 	self->size ++;
130 	return item;
131 }
132 
List_appendSeq_(List * self,const List * otherList)133 IOINLINE void List_appendSeq_(List *self, const List *otherList)
134 {
135 	LIST_FOREACH(otherList, i, v, List_append_(self, v));
136 }
137 
List_compactIfNeeded(List * self)138 IOINLINE void List_compactIfNeeded(List *self)
139 {
140 	if(self->memSize > 1024 && self->size * sizeof(void *) * 4 < self->memSize)
141 	{
142 		List_compact(self);
143 	}
144 }
145 
List_removeIndex_(List * self,size_t index)146 IOINLINE void List_removeIndex_(List *self, size_t index)
147 {
148 	if (index < self->size)
149 	{
150 		if ( index != self->size - 1)
151 		{
152 			memmove(&self->items[index], &self->items[index + 1],
153 				   (self->size - 1 - index) * sizeof(void *));
154 		}
155 
156 		self->size --;
157 
158 		List_compactIfNeeded(self);
159 	}
160 }
161 
List_removeIndex_toIndex_(List * self,size_t index1,size_t index2)162 IOINLINE void List_removeIndex_toIndex_(List *self, size_t index1, size_t index2)
163 {
164 	size_t length;
165 
166 	if (index1 > self->size - 1)
167 	{
168 		index1 = self->size - 1;
169 	}
170 
171 	if (index2 > self->size - 1)
172 	{
173 		index2 = self->size - 1;
174 	}
175 
176 	length = index2 - index1;
177 
178 	if (length <= 0)
179 	{
180 		return;
181 	}
182 
183 	memmove(&self->items[index1], &self->items[index2],
184 		   (self->size - index2) * sizeof(void *));
185 
186 	self->size -= length;
187 
188 	List_compactIfNeeded(self);
189 }
190 
List_remove_(List * self,void * item)191 IOINLINE void List_remove_(List *self, void *item)
192 {
193 	size_t index;
194 
195 	for (index = 0; index < self->size; index ++)
196 	{
197 		if (self->items[index] == item)
198 		{
199 			List_removeIndex_(self, index);
200 		}
201 	}
202 }
203 
List_removeFirst_(List * self,void * item)204 IOINLINE int List_removeFirst_(List *self, void *item)
205 {
206 	size_t i, max = self->size;
207 
208 	for (i = 0; i < max; i ++)
209 	{
210 		if (self->items[i] == item)
211 		{
212 			List_removeIndex_(self, i);
213 			return 1;
214 		}
215 	}
216 
217 	return 0;
218 }
219 
List_removeLast_(List * self,void * item)220 IOINLINE void List_removeLast_(List *self, void *item)
221 {
222 	size_t index = self->size - 1;
223 
224 	for (index = self->size - 1; index > -1; index --)
225 	{
226 		if (self->items[index] == item)
227 		{
228 			List_removeIndex_(self, index);
229 			break;
230 		}
231 	}
232 }
233 
List_removeItems_(List * self,List * other)234 IOINLINE void List_removeItems_(List *self, List *other)
235 {
236 	LIST_FOREACH(other, i, v, List_remove_(self, v));
237 }
238 
List_at_insert_(List * self,size_t index,void * item)239 IOINLINE void List_at_insert_(List *self, size_t index, void *item)
240 {
241 	if (index > self->size - 1)
242 	{
243 		List_preallocateToSize_(self, index + 1);
244 	}
245 	else
246 	{
247 		List_ifNeededSizeTo_(self, self->size + 1);
248 	}
249 
250 	memmove(&self->items[index + 1], &self->items[index],
251 		   (self->size - index) * sizeof(void *));
252 
253 	self->items[index] = item;
254 	self->size ++;
255 }
256 
List_at_put_(List * self,size_t index,void * item)257 IOINLINE void List_at_put_(List *self, size_t index, void *item)
258 {
259 	List_ifNeededSizeTo_(self, index);
260 	self->items[index] = item;
261 
262 	if (index + 1 > self->size)
263 	{
264 		self->size = index + 1;
265 	}
266 }
267 
List_swap_with_(List * self,long index1,long index2)268 IOINLINE void List_swap_with_(List *self, long index1, long index2)
269 {
270 	if (index1 < 0 || index2 < 0)
271 	{
272 		return;
273 	}
274 
275 	if (index1 != index2)
276 	{
277 		void **items = self->items;
278 		register void *v1 = items[index1];
279 
280 		items[index1] = items[index2];
281 		items[index2] = v1;
282 	}
283 }
284 
List_reverseInPlace(List * self)285 IOINLINE void List_reverseInPlace(List *self)
286 {
287 	register void **i = self->items;
288 	register void **j = i + (self->size - 1);
289 	register void *iv;
290 
291 	while (j > i)
292 	{
293 		iv = *i;
294 		*i = *j;
295 		*j = iv;
296 		j --;
297 		i ++;
298 	}
299 }
300 
301 // stack --------------------------------------------------
302 
List_push_(List * self,void * item)303 IOINLINE void List_push_(List *self, void *item)
304 {
305 	List_ifNeededSizeTo_(self, self->size + 1);
306 	self->items[self->size] = item;
307 	self->size ++;
308 }
309 
List_pop(List * self)310 IOINLINE void *List_pop(List *self)
311 {
312 	void *item;
313 
314 	if (!self->size)
315 	{
316 		return (void *)NULL;
317 	}
318 
319 	self->size --;
320 	item = self->items[self->size];
321 	List_compactIfNeeded(self);
322 	return item;
323 }
324 
List_top(const List * self)325 IOINLINE void *List_top(const List *self)
326 {
327 	if (!self->size)
328 	{
329 		return (void *)NULL;
330 	}
331 
332 	return self->items[self->size - 1];
333 }
334 
335 /* --- perform -------------------------------------------------- */
336 
List_removeTrueFor_(List * self,ListCollectCallback * callback)337 IOINLINE int List_removeTrueFor_(List *self, ListCollectCallback* callback)
338 {
339 	size_t getIndex = 0;
340 	size_t putIndex = 0;
341 	size_t count = self->size;
342 	void **items = self->items;
343 
344 	while (getIndex < count)
345 	{
346 		void *item = items[getIndex];
347 
348 		if (item && !((*callback)(item)))
349 		{
350 			if (getIndex!=putIndex)
351 			{
352 				items[putIndex] = item;
353 			}
354 
355 			putIndex ++;
356 		}
357 
358 		getIndex ++;
359 	}
360 
361 	self->size = putIndex;
362 
363 	return (int)(getIndex - putIndex);
364 }
365 
List_qsort(List * self,ListSortCallback * callback)366 IOINLINE void List_qsort(List *self, ListSortCallback *callback)
367 {
368 	qsort(self->items, self->size, sizeof(void *), *callback);
369 }
370 
List_qsort_r(List * self,void * context,ListSortRCallback * callback)371 IOINLINE void List_qsort_r(List *self, void *context, ListSortRCallback *callback)
372 {
373 	portable_qsort_r(self->items, self->size, sizeof(void *), context, *callback);
374 }
375 
List_bsearch(List * self,const void * key,ListSortCallback * callback)376 IOINLINE void *List_bsearch(List *self, const void *key, ListSortCallback *callback)
377 {
378 	return bsearch(key, self->items, self->size, sizeof(void *), callback);
379 }
380 
List_first(const List * self)381 IOINLINE void *List_first(const List *self)
382 {
383 	return List_at_(self, 0);
384 }
385 
List_last(List * self)386 IOINLINE void *List_last(List *self)
387 {
388 	return List_at_(self, List_size(self) - 1);
389 }
390 
391 #undef IO_IN_C_FILE
392 #endif
393 
394