1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29 #include "cx/list.h"
30
31 #include <string.h>
32
33
34
35 static _Thread_local cx_compare_func cx_pl_cmpfunc_impl;
36
37 static int cx_pl_cmpfunc(
38 const void *l,
39 const void *r
40 ) {
41 void *
const *lptr = l;
42 void *
const *rptr = r;
43 const void *left = lptr ==
NULL ?
NULL : *lptr;
44 const void *right = rptr ==
NULL ?
NULL : *rptr;
45 return cx_pl_cmpfunc_impl(left, right);
46 }
47
48 static void cx_pl_hack_cmpfunc(
const struct cx_list_s *list) {
49
50 struct cx_collection_s *l = (
struct cx_collection_s*) &list->collection;
51 cx_pl_cmpfunc_impl = l->cmpfunc;
52 l->cmpfunc = cx_pl_cmpfunc;
53 }
54
55 static void cx_pl_unhack_cmpfunc(
const struct cx_list_s *list) {
56
57 struct cx_collection_s *l = (
struct cx_collection_s*) &list->collection;
58 l->cmpfunc = cx_pl_cmpfunc_impl;
59 }
60
61 static void cx_pl_destructor(
struct cx_list_s *list) {
62 list->climpl->destructor(list);
63 }
64
65 static int cx_pl_insert_element(
66 struct cx_list_s *list,
67 size_t index,
68 const void *element
69 ) {
70 return list->climpl->insert_element(list, index, &element);
71 }
72
73 static size_t cx_pl_insert_array(
74 struct cx_list_s *list,
75 size_t index,
76 const void *array,
77 size_t n
78 ) {
79 return list->climpl->insert_array(list, index, array, n);
80 }
81
82 static size_t cx_pl_insert_sorted(
83 struct cx_list_s *list,
84 const void *array,
85 size_t n
86 ) {
87 cx_pl_hack_cmpfunc(list);
88 size_t result = list->climpl->insert_sorted(list, array, n);
89 cx_pl_unhack_cmpfunc(list);
90 return result;
91 }
92
93 static int cx_pl_insert_iter(
94 struct cx_iterator_s *iter,
95 const void *elem,
96 int prepend
97 ) {
98 struct cx_list_s *list = iter->src_handle.m;
99 return list->climpl->insert_iter(iter, &elem, prepend);
100 }
101
102 static int cx_pl_remove(
103 struct cx_list_s *list,
104 size_t index
105 ) {
106 return list->climpl->remove(list, index);
107 }
108
109 static void cx_pl_clear(
struct cx_list_s *list) {
110 list->climpl->clear(list);
111 }
112
113 static int cx_pl_swap(
114 struct cx_list_s *list,
115 size_t i,
116 size_t j
117 ) {
118 return list->climpl->swap(list, i, j);
119 }
120
121 static void *cx_pl_at(
122 const struct cx_list_s *list,
123 size_t index
124 ) {
125 void **ptr = list->climpl->at(list, index);
126 return ptr ==
NULL ?
NULL : *ptr;
127 }
128
129 static ssize_t cx_pl_find_remove(
130 struct cx_list_s *list,
131 const void *elem,
132 bool remove
133 ) {
134 cx_pl_hack_cmpfunc(list);
135 ssize_t ret = list->climpl->find_remove(list, &elem, remove);
136 cx_pl_unhack_cmpfunc(list);
137 return ret;
138 }
139
140 static void cx_pl_sort(
struct cx_list_s *list) {
141 cx_pl_hack_cmpfunc(list);
142 list->climpl->sort(list);
143 cx_pl_unhack_cmpfunc(list);
144 }
145
146 static int cx_pl_compare(
147 const struct cx_list_s *list,
148 const struct cx_list_s *other
149 ) {
150 cx_pl_hack_cmpfunc(list);
151 int ret = list->climpl->compare(list, other);
152 cx_pl_unhack_cmpfunc(list);
153 return ret;
154 }
155
156 static void cx_pl_reverse(
struct cx_list_s *list) {
157 list->climpl->reverse(list);
158 }
159
160 static void *cx_pl_iter_current(
const void *it) {
161 const struct cx_iterator_s *iter = it;
162 void **ptr = iter->base.current_impl(it);
163 return ptr ==
NULL ?
NULL : *ptr;
164 }
165
166 static struct cx_iterator_s cx_pl_iterator(
167 const struct cx_list_s *list,
168 size_t index,
169 bool backwards
170 ) {
171 struct cx_iterator_s iter = list->climpl->iterator(list, index, backwards);
172 iter.base.current_impl = iter.base.current;
173 iter.base.current = cx_pl_iter_current;
174 return iter;
175 }
176
177 static cx_list_class cx_pointer_list_class = {
178 cx_pl_destructor,
179 cx_pl_insert_element,
180 cx_pl_insert_array,
181 cx_pl_insert_sorted,
182 cx_pl_insert_iter,
183 cx_pl_remove,
184 cx_pl_clear,
185 cx_pl_swap,
186 cx_pl_at,
187 cx_pl_find_remove,
188 cx_pl_sort,
189 cx_pl_compare,
190 cx_pl_reverse,
191 cx_pl_iterator,
192 };
193
194 void cxListStoreObjects(CxList *list) {
195 list->collection.store_pointer = false;
196 if (list->climpl !=
NULL) {
197 list->cl = list->climpl;
198 list->climpl =
NULL;
199 }
200 }
201
202 void cxListStorePointers(CxList *list) {
203 list->collection.elem_size =
sizeof(
void *);
204 list->collection.store_pointer = true;
205 list->climpl = list->cl;
206 list->cl = &cx_pointer_list_class;
207 }
208
209
210
211
212
213 static void cx_emptyl_noop(__attribute__((__unused__)) CxList *list) {
214
215 }
216
217 static void *cx_emptyl_at(
218 __attribute__((__unused__))
const struct cx_list_s *list,
219 __attribute__((__unused__))
size_t index
220 ) {
221 return NULL;
222 }
223
224 static ssize_t cx_emptyl_find_remove(
225 __attribute__((__unused__))
struct cx_list_s *list,
226 __attribute__((__unused__))
const void *elem,
227 __attribute__((__unused__)) bool remove
228 ) {
229 return -
1;
230 }
231
232 static bool cx_emptyl_iter_valid(__attribute__((__unused__))
const void *iter) {
233 return false;
234 }
235
236 static CxIterator cx_emptyl_iterator(
237 const struct cx_list_s *list,
238 size_t index,
239 __attribute__((__unused__)) bool backwards
240 ) {
241 CxIterator iter = {
0};
242 iter.src_handle.c = list;
243 iter.index = index;
244 iter.base.valid = cx_emptyl_iter_valid;
245 return iter;
246 }
247
248 static cx_list_class cx_empty_list_class = {
249 cx_emptyl_noop,
250 NULL,
251 NULL,
252 NULL,
253 NULL,
254 NULL,
255 cx_emptyl_noop,
256 NULL,
257 cx_emptyl_at,
258 cx_emptyl_find_remove,
259 cx_emptyl_noop,
260 NULL,
261 cx_emptyl_noop,
262 cx_emptyl_iterator,
263 };
264
265 CxList cx_empty_list = {
266 {
267 NULL,
268 NULL,
269 0,
270 0,
271 NULL,
272 NULL,
273 NULL,
274 false
275 },
276 &cx_empty_list_class,
277 NULL
278 };
279
280 CxList *
const cxEmptyList = &cx_empty_list;
281
282
283
284 #define invoke_list_func(name, list, ...) \
285 ((list)->climpl ==
NULL ? (list)->cl->name : (list)->climpl->name) \
286 (list,
__VA_ARGS__)
287
288 size_t cx_list_default_insert_array(
289 struct cx_list_s *list,
290 size_t index,
291 const void *data,
292 size_t n
293 ) {
294 size_t elem_size = list->collection.elem_size;
295 const char *src = data;
296 size_t i =
0;
297 for (; i < n; i++) {
298 if (
0 != invoke_list_func(insert_element,
299 list, index + i, src + (i * elem_size))) {
300 return i;
301 }
302 }
303 return i;
304 }
305
306 size_t cx_list_default_insert_sorted(
307 struct cx_list_s *list,
308 const void *sorted_data,
309 size_t n
310 ) {
311
312 if (n ==
0)
return 0;
313
314 size_t elem_size = list->collection.elem_size;
315 cx_compare_func cmp = list->collection.cmpfunc;
316 const char *src = sorted_data;
317
318
319 size_t di =
0, si =
0, inserted =
0;
320
321
322 for (; di < list->collection.size; di++) {
323 const void *list_elm = invoke_list_func(at, list, di);
324
325
326
327 if (cmp(list_elm, src) <=
0) {
328 continue;
329 }
330
331
332 size_t ins =
1;
333 const char *next = src;
334 while (++si < n) {
335 next += elem_size;
336
337 if (cmp(list_elm, next) <=
0) {
338 break;
339 }
340
341 ins++;
342 }
343
344
345 if (ins ==
1) {
346 if (
0 != invoke_list_func(insert_element,
347 list, di, src))
348 return inserted;
349 }
else {
350 size_t r = invoke_list_func(insert_array, list, di, src, ins);
351 if (r < ins)
return inserted + r;
352 }
353 inserted += ins;
354 di += ins;
355
356
357 if (inserted == n)
return inserted;
358 src = next;
359 }
360
361
362 if (si < n) {
363 inserted += invoke_list_func(insert_array, list, di, src, n - si);
364 }
365
366 return inserted;
367 }
368
369 void cx_list_default_sort(
struct cx_list_s *list) {
370 size_t elem_size = list->collection.elem_size;
371 size_t list_size = list->collection.size;
372 void *tmp = malloc(elem_size * list_size);
373 if (tmp ==
NULL) abort();
374
375
376 char *loc = tmp;
377 for (
size_t i =
0; i < list_size; i++) {
378 void *src = invoke_list_func(at, list, i);
379 memcpy(loc, src, elem_size);
380 loc += elem_size;
381 }
382
383
384 qsort(tmp, list_size, elem_size,
385 list->collection.cmpfunc);
386
387
388 loc = tmp;
389 for (
size_t i =
0; i < list_size; i++) {
390 void *dest = invoke_list_func(at, list, i);
391 memcpy(dest, loc, elem_size);
392 loc += elem_size;
393 }
394
395 free(tmp);
396 }
397
398 int cx_list_default_swap(
struct cx_list_s *list,
size_t i,
size_t j) {
399 if (i == j)
return 0;
400 if (i >= list->collection.size)
return 1;
401 if (j >= list->collection.size)
return 1;
402
403 size_t elem_size = list->collection.elem_size;
404
405 void *tmp = malloc(elem_size);
406 if (tmp ==
NULL)
return 1;
407
408 void *ip = invoke_list_func(at, list, i);
409 void *jp = invoke_list_func(at, list, j);
410
411 memcpy(tmp, ip, elem_size);
412 memcpy(ip, jp, elem_size);
413 memcpy(jp, tmp, elem_size);
414
415 free(tmp);
416
417 return 0;
418 }
419
420 void cxListDestroy(CxList *list) {
421 list->cl->destructor(list);
422 }
423
424 int cxListCompare(
425 const CxList *list,
426 const CxList *other
427 ) {
428 bool cannot_optimize = false;
429
430
431 cannot_optimize |= list->collection.store_pointer ^ other->collection.store_pointer;
432
433
434 cannot_optimize |= (list->climpl ==
NULL) ^ (other->climpl ==
NULL);
435
436
437 if (!cannot_optimize) {
438 cx_compare_func list_cmp = (cx_compare_func) (list->climpl !=
NULL ?
439 list->climpl->compare : list->cl->compare);
440 cx_compare_func other_cmp = (cx_compare_func) (other->climpl !=
NULL ?
441 other->climpl->compare : other->cl->compare);
442 cannot_optimize |= list_cmp != other_cmp;
443 cannot_optimize |= list_cmp ==
NULL;
444 }
445
446 if (cannot_optimize) {
447
448 if (list->collection.size == other->collection.size) {
449 CxIterator left = list->cl->iterator(list,
0, false);
450 CxIterator right = other->cl->iterator(other,
0, false);
451 for (
size_t i =
0; i < list->collection.size; i++) {
452 void *leftValue = cxIteratorCurrent(left);
453 void *rightValue = cxIteratorCurrent(right);
454 int d = list->collection.cmpfunc(leftValue, rightValue);
455 if (d !=
0) {
456 return d;
457 }
458 cxIteratorNext(left);
459 cxIteratorNext(right);
460 }
461 return 0;
462 }
else {
463 return list->collection.size < other->collection.size ? -
1 :
1;
464 }
465 }
else {
466
467 return list->cl->compare(list, other);
468 }
469 }
470
471 CxIterator cxListMutIteratorAt(
472 CxList *list,
473 size_t index
474 ) {
475 CxIterator it = list->cl->iterator(list, index, false);
476 it.base.mutating = true;
477 return it;
478 }
479
480 CxIterator cxListMutBackwardsIteratorAt(
481 CxList *list,
482 size_t index
483 ) {
484 CxIterator it = list->cl->iterator(list, index, true);
485 it.base.mutating = true;
486 return it;
487 }
488