| 29 #include "cx/list.h" |
29 #include "cx/list.h" |
| 30 |
30 |
| 31 #include <string.h> |
31 #include <string.h> |
| 32 #include <assert.h> |
32 #include <assert.h> |
| 33 |
33 |
| |
34 // we don't want to include the full array_list.h. |
| |
35 // therefore, we only forward declare the one function we want to use |
| |
36 CX_EXPORT void cx_array_qsort_c(void *array, size_t nmemb, size_t size, |
| |
37 cx_compare_func2 fn, void *context); |
| |
38 |
| |
39 |
| 34 int cx_list_compare_wrapper(const void *l, const void *r, void *c) { |
40 int cx_list_compare_wrapper(const void *l, const void *r, void *c) { |
| 35 CxList *list = c; |
41 CxList *list = c; |
| 36 const void *left; |
42 const void *left; |
| 37 const void *right; |
43 const void *right; |
| 38 if (cxCollectionStoresPointers(list)) { |
44 if (cxCollectionStoresPointers(list)) { |
| 55 |
61 |
| 56 #define cx_list_compare_wrapper(l, r, c) cx_list_compare_wrapper(l, r, (void*)c) |
62 #define cx_list_compare_wrapper(l, r, c) cx_list_compare_wrapper(l, r, (void*)c) |
| 57 |
63 |
| 58 // <editor-fold desc="empty list implementation"> |
64 // <editor-fold desc="empty list implementation"> |
| 59 |
65 |
| 60 static void cx_emptyl_noop(cx_attr_unused CxList *list) { |
66 static void cx_emptyl_noop(CX_UNUSED CxList *list) { |
| 61 // this is a noop, but MUST be implemented |
67 // this is a noop, but MUST be implemented |
| 62 } |
68 } |
| 63 |
69 |
| 64 static void *cx_emptyl_at( |
70 static void *cx_emptyl_at( |
| 65 cx_attr_unused const struct cx_list_s *list, |
71 CX_UNUSED const struct cx_list_s *list, |
| 66 cx_attr_unused size_t index |
72 CX_UNUSED size_t index |
| 67 ) { |
73 ) { |
| 68 return NULL; |
74 return NULL; |
| 69 } |
75 } |
| 70 |
76 |
| 71 static size_t cx_emptyl_find_remove( |
77 static size_t cx_emptyl_find_remove( |
| 72 cx_attr_unused struct cx_list_s *list, |
78 CX_UNUSED struct cx_list_s *list, |
| 73 cx_attr_unused const void *elem, |
79 CX_UNUSED const void *elem, |
| 74 cx_attr_unused bool remove |
80 CX_UNUSED bool remove |
| 75 ) { |
81 ) { |
| 76 return 0; |
82 return 0; |
| 77 } |
83 } |
| 78 |
84 |
| 79 static bool cx_emptyl_iter_valid(cx_attr_unused const void *iter) { |
85 static bool cx_emptyl_iter_valid(CX_UNUSED const void *iter) { |
| 80 return false; |
86 return false; |
| 81 } |
87 } |
| 82 |
88 |
| 83 static CxIterator cx_emptyl_iterator( |
89 static CxIterator cx_emptyl_iterator( |
| 84 const struct cx_list_s *list, |
90 const struct cx_list_s *list, |
| 85 size_t index, |
91 size_t index, |
| 86 cx_attr_unused bool backwards |
92 CX_UNUSED bool backwards |
| 87 ) { |
93 ) { |
| 88 CxIterator iter = {0}; |
94 CxIterator iter = {0}; |
| 89 iter.src_handle = (void*) list; |
95 iter.src_handle = (void*) list; |
| 90 iter.index = index; |
96 iter.index = index; |
| 91 iter.base.valid = cx_emptyl_iter_valid; |
97 iter.base.valid = cx_emptyl_iter_valid; |
| 139 size_t n |
145 size_t n |
| 140 ) { |
146 ) { |
| 141 const char *src = data; |
147 const char *src = data; |
| 142 size_t i = 0; |
148 size_t i = 0; |
| 143 for (; i < n; i++) { |
149 for (; i < n; i++) { |
| 144 if (NULL == list->cl->insert_element(list, index + i, src) |
150 if (NULL == list->cl->insert_element(list, index + i, src)) { |
| 145 ) { |
|
| 146 return i; // LCOV_EXCL_LINE |
151 return i; // LCOV_EXCL_LINE |
| 147 } |
152 } |
| 148 if (src != NULL) { |
153 if (src != NULL) { |
| 149 src += list->collection.elem_size; |
154 src += list->collection.elem_size; |
| 150 } |
155 } |
| 281 size_t n |
286 size_t n |
| 282 ) { |
287 ) { |
| 283 return cx_list_default_insert_sorted_impl(list, sorted_data, n, false); |
288 return cx_list_default_insert_sorted_impl(list, sorted_data, n, false); |
| 284 } |
289 } |
| 285 |
290 |
| 286 // TODO: remove this hack once we have a solution for qsort() / qsort_s() |
|
| 287 static _Thread_local CxList *cx_hack_for_qsort_list; |
|
| 288 static int cx_hack_cmp_for_qsort(const void *l, const void *r) { |
|
| 289 return cx_list_compare_wrapper(l, r, cx_hack_for_qsort_list); |
|
| 290 } |
|
| 291 |
|
| 292 void cx_list_default_sort(struct cx_list_s *list) { |
291 void cx_list_default_sort(struct cx_list_s *list) { |
| 293 size_t elem_size = list->collection.elem_size; |
292 size_t elem_size = list->collection.elem_size; |
| 294 size_t list_size = list->collection.size; |
293 size_t list_size = list->collection.size; |
| 295 void *tmp = cxMallocDefault(elem_size * list_size); |
294 void *tmp = cxMallocDefault(elem_size * list_size); |
| 296 if (tmp == NULL) abort(); // LCOV_EXCL_LINE |
295 if (tmp == NULL) abort(); // LCOV_EXCL_LINE |
| 302 memcpy(loc, src, elem_size); |
301 memcpy(loc, src, elem_size); |
| 303 loc += elem_size; |
302 loc += elem_size; |
| 304 } |
303 } |
| 305 |
304 |
| 306 // qsort |
305 // qsort |
| 307 // TODO: qsort_s() is not as nice as we thought |
306 cx_array_qsort_c(tmp, list_size, elem_size, cx_list_compare_wrapper, list); |
| 308 cx_hack_for_qsort_list = list; |
|
| 309 qsort(tmp, list_size, elem_size, cx_hack_cmp_for_qsort); |
|
| 310 |
307 |
| 311 // copy elements back |
308 // copy elements back |
| 312 loc = tmp; |
309 loc = tmp; |
| 313 for (size_t i = 0; i < list_size; i++) { |
310 for (size_t i = 0; i < list_size; i++) { |
| 314 void *dest = list->cl->at(list, i); |
311 void *dest = list->cl->at(list, i); |
| 337 memcpy(jp, tmp, elem_size); |
334 memcpy(jp, tmp, elem_size); |
| 338 |
335 |
| 339 cxFreeDefault(tmp); |
336 cxFreeDefault(tmp); |
| 340 |
337 |
| 341 return 0; |
338 return 0; |
| |
339 } |
| |
340 |
| |
341 static int cx_list_cmpfunc2_safe_memcmp(const void *a, const void *b, void *c) { |
| |
342 // it is not safe to store a pointer to the size in the list |
| |
343 // because the entire list structure might get reallocated |
| |
344 size_t elem_size = (size_t)(uintptr_t)c; |
| |
345 return memcmp(a, b, elem_size); |
| 342 } |
346 } |
| 343 |
347 |
| 344 void cx_list_init( |
348 void cx_list_init( |
| 345 struct cx_list_s *list, |
349 struct cx_list_s *list, |
| 346 struct cx_list_class_s *cl, |
350 struct cx_list_class_s *cl, |
| 352 list->collection.size = 0; |
356 list->collection.size = 0; |
| 353 list->collection.sorted = false; // should be set by the implementation |
357 list->collection.sorted = false; // should be set by the implementation |
| 354 if (elem_size > 0) { |
358 if (elem_size > 0) { |
| 355 list->collection.elem_size = elem_size; |
359 list->collection.elem_size = elem_size; |
| 356 list->collection.simple_cmp = NULL; |
360 list->collection.simple_cmp = NULL; |
| 357 list->collection.advanced_cmp = cx_acmp_memcmp; |
361 list->collection.advanced_cmp = cx_list_cmpfunc2_safe_memcmp; |
| 358 list->collection.cmp_data = &list->collection.elem_size; |
362 list->collection.cmp_data = (void*)(uintptr_t)list->collection.elem_size; |
| 359 list->collection.store_pointer = false; |
363 list->collection.store_pointer = false; |
| 360 } else { |
364 } else { |
| 361 list->collection.elem_size = sizeof(void *); |
365 list->collection.elem_size = sizeof(void *); |
| 362 list->collection.simple_cmp = cx_cmp_ptr; |
366 list->collection.simple_cmp = cx_cmp_ptr; |
| 363 list->collection.advanced_cmp = NULL; |
367 list->collection.advanced_cmp = NULL; |