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