| 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 // <editor-fold desc="Store Pointers Functionality"> |
34 // we don't want to include the full array_list.h. |
| 35 |
35 // therefore, we only forward declare the one function we want to use |
| 36 static _Thread_local cx_compare_func cx_pl_cmpfunc_impl; |
36 CX_EXPORT void cx_array_qsort_c(void *array, size_t nmemb, size_t size, |
| 37 |
37 cx_compare_func2 fn, void *context); |
| 38 static int cx_pl_cmpfunc( |
38 |
| 39 const void *l, |
39 |
| 40 const void *r |
40 int cx_list_compare_wrapper(const void *l, const void *r, void *c) { |
| 41 ) { |
41 CxList *list = c; |
| 42 // l and r are guaranteed to be non-NULL pointing to the list's memory |
42 const void *left; |
| 43 void *const *lptr = l; |
43 const void *right; |
| 44 void *const *rptr = r; |
44 if (cxCollectionStoresPointers(list)) { |
| 45 const void *left = *lptr; |
45 left = *(void**)l; |
| 46 const void *right = *rptr; |
46 right = *(void**)r; |
| 47 if (left == NULL) { |
47 // for historic reasons, we are handling the NULL case here |
| 48 // NULL is smaller than any value except NULL |
48 // because every UCX compare function does not support NULL arguments |
| 49 return right == NULL ? 0 : -1; |
49 if (left == NULL) { |
| 50 } else if (right == NULL) { |
50 if (right == NULL) return 0; |
| 51 // any value is larger than NULL |
51 return -1; |
| 52 return 1; |
52 } else if (right == NULL) { |
| 53 } |
53 return 1; |
| 54 return cx_pl_cmpfunc_impl(left, right); |
54 } |
| 55 } |
55 } else { |
| 56 |
56 left = l; |
| 57 static void cx_pl_hack_cmpfunc(const struct cx_list_s *list) { |
57 right = r; |
| 58 // cast away const - this is the hacky thing |
58 } |
| 59 struct cx_collection_s *l = (struct cx_collection_s*) &list->collection; |
59 return cx_invoke_compare_func(list, left, right); |
| 60 cx_pl_cmpfunc_impl = l->cmpfunc; |
60 } |
| 61 l->cmpfunc = cx_pl_cmpfunc; |
61 |
| 62 } |
62 #define cx_list_compare_wrapper(l, r, c) cx_list_compare_wrapper(l, r, (void*)c) |
| 63 |
|
| 64 static void cx_pl_unhack_cmpfunc(const struct cx_list_s *list) { |
|
| 65 // cast away const - this is the hacky thing |
|
| 66 struct cx_collection_s *l = (struct cx_collection_s*) &list->collection; |
|
| 67 l->cmpfunc = cx_pl_cmpfunc_impl; |
|
| 68 } |
|
| 69 |
|
| 70 static void cx_pl_destructor(struct cx_list_s *list) { |
|
| 71 list->climpl->deallocate(list); |
|
| 72 } |
|
| 73 |
|
| 74 static void *cx_pl_insert_element( |
|
| 75 struct cx_list_s *list, |
|
| 76 size_t index, |
|
| 77 const void *element |
|
| 78 ) { |
|
| 79 return list->climpl->insert_element(list, index, &element); |
|
| 80 } |
|
| 81 |
|
| 82 static size_t cx_pl_insert_array( |
|
| 83 struct cx_list_s *list, |
|
| 84 size_t index, |
|
| 85 const void *array, |
|
| 86 size_t n |
|
| 87 ) { |
|
| 88 return list->climpl->insert_array(list, index, array, n); |
|
| 89 } |
|
| 90 |
|
| 91 static size_t cx_pl_insert_sorted( |
|
| 92 struct cx_list_s *list, |
|
| 93 const void *array, |
|
| 94 size_t n |
|
| 95 ) { |
|
| 96 cx_pl_hack_cmpfunc(list); |
|
| 97 size_t result = list->climpl->insert_sorted(list, array, n); |
|
| 98 cx_pl_unhack_cmpfunc(list); |
|
| 99 return result; |
|
| 100 } |
|
| 101 |
|
| 102 static size_t cx_pl_insert_unique( |
|
| 103 struct cx_list_s *list, |
|
| 104 const void *array, |
|
| 105 size_t n |
|
| 106 ) { |
|
| 107 cx_pl_hack_cmpfunc(list); |
|
| 108 size_t result = list->climpl->insert_unique(list, array, n); |
|
| 109 cx_pl_unhack_cmpfunc(list); |
|
| 110 return result; |
|
| 111 } |
|
| 112 |
|
| 113 static int cx_pl_insert_iter( |
|
| 114 struct cx_iterator_s *iter, |
|
| 115 const void *elem, |
|
| 116 int prepend |
|
| 117 ) { |
|
| 118 struct cx_list_s *list = iter->src_handle; |
|
| 119 return list->climpl->insert_iter(iter, &elem, prepend); |
|
| 120 } |
|
| 121 |
|
| 122 static size_t cx_pl_remove( |
|
| 123 struct cx_list_s *list, |
|
| 124 size_t index, |
|
| 125 size_t num, |
|
| 126 void *targetbuf |
|
| 127 ) { |
|
| 128 return list->climpl->remove(list, index, num, targetbuf); |
|
| 129 } |
|
| 130 |
|
| 131 static void cx_pl_clear(struct cx_list_s *list) { |
|
| 132 list->climpl->clear(list); |
|
| 133 } |
|
| 134 |
|
| 135 static int cx_pl_swap( |
|
| 136 struct cx_list_s *list, |
|
| 137 size_t i, |
|
| 138 size_t j |
|
| 139 ) { |
|
| 140 return list->climpl->swap(list, i, j); |
|
| 141 } |
|
| 142 |
|
| 143 static void *cx_pl_at( |
|
| 144 const struct cx_list_s *list, |
|
| 145 size_t index |
|
| 146 ) { |
|
| 147 void **ptr = list->climpl->at(list, index); |
|
| 148 return ptr == NULL ? NULL : *ptr; |
|
| 149 } |
|
| 150 |
|
| 151 static size_t cx_pl_find_remove( |
|
| 152 struct cx_list_s *list, |
|
| 153 const void *elem, |
|
| 154 bool remove |
|
| 155 ) { |
|
| 156 cx_pl_hack_cmpfunc(list); |
|
| 157 size_t ret = list->climpl->find_remove(list, &elem, remove); |
|
| 158 cx_pl_unhack_cmpfunc(list); |
|
| 159 return ret; |
|
| 160 } |
|
| 161 |
|
| 162 static void cx_pl_sort(struct cx_list_s *list) { |
|
| 163 cx_pl_hack_cmpfunc(list); |
|
| 164 list->climpl->sort(list); |
|
| 165 cx_pl_unhack_cmpfunc(list); |
|
| 166 } |
|
| 167 |
|
| 168 static int cx_pl_compare( |
|
| 169 const struct cx_list_s *list, |
|
| 170 const struct cx_list_s *other |
|
| 171 ) { |
|
| 172 cx_pl_hack_cmpfunc(list); |
|
| 173 int ret = list->climpl->compare(list, other); |
|
| 174 cx_pl_unhack_cmpfunc(list); |
|
| 175 return ret; |
|
| 176 } |
|
| 177 |
|
| 178 static void cx_pl_reverse(struct cx_list_s *list) { |
|
| 179 list->climpl->reverse(list); |
|
| 180 } |
|
| 181 |
|
| 182 static void *cx_pl_iter_current(const void *it) { |
|
| 183 const struct cx_iterator_s *iter = it; |
|
| 184 void **ptr = iter->base.current_impl(it); |
|
| 185 return ptr == NULL ? NULL : *ptr; |
|
| 186 } |
|
| 187 |
|
| 188 static int cx_pl_change_capacity(struct cx_list_s *list, size_t cap) { |
|
| 189 if (list->climpl->change_capacity == NULL) { |
|
| 190 return 0; |
|
| 191 } else { |
|
| 192 return list->climpl->change_capacity(list, cap); |
|
| 193 } |
|
| 194 } |
|
| 195 |
|
| 196 static struct cx_iterator_s cx_pl_iterator( |
|
| 197 const struct cx_list_s *list, |
|
| 198 size_t index, |
|
| 199 bool backwards |
|
| 200 ) { |
|
| 201 struct cx_iterator_s iter = list->climpl->iterator(list, index, backwards); |
|
| 202 iter.base.current_impl = iter.base.current; |
|
| 203 iter.base.current = cx_pl_iter_current; |
|
| 204 return iter; |
|
| 205 } |
|
| 206 |
|
| 207 static cx_list_class cx_pointer_list_class = { |
|
| 208 cx_pl_destructor, |
|
| 209 cx_pl_insert_element, |
|
| 210 cx_pl_insert_array, |
|
| 211 cx_pl_insert_sorted, |
|
| 212 cx_pl_insert_unique, |
|
| 213 cx_pl_insert_iter, |
|
| 214 cx_pl_remove, |
|
| 215 cx_pl_clear, |
|
| 216 cx_pl_swap, |
|
| 217 cx_pl_at, |
|
| 218 cx_pl_find_remove, |
|
| 219 cx_pl_sort, |
|
| 220 cx_pl_compare, |
|
| 221 cx_pl_reverse, |
|
| 222 cx_pl_change_capacity, |
|
| 223 cx_pl_iterator, |
|
| 224 }; |
|
| 225 // </editor-fold> |
|
| 226 |
63 |
| 227 // <editor-fold desc="empty list implementation"> |
64 // <editor-fold desc="empty list implementation"> |
| 228 |
65 |
| 229 static void cx_emptyl_noop(cx_attr_unused CxList *list) { |
66 static void cx_emptyl_noop(cx_attr_unused CxList *list) { |
| 230 // this is a noop, but MUST be implemented |
67 // this is a noop, but MUST be implemented |
| 333 ) { |
166 ) { |
| 334 // corner case |
167 // corner case |
| 335 if (n == 0) return 0; |
168 if (n == 0) return 0; |
| 336 |
169 |
| 337 size_t elem_size = list->collection.elem_size; |
170 size_t elem_size = list->collection.elem_size; |
| 338 cx_compare_func cmp = list->collection.cmpfunc; |
|
| 339 const char *src = sorted_data; |
171 const char *src = sorted_data; |
| 340 |
172 |
| 341 // track indices and number of inserted items |
173 // track indices and number of inserted items |
| 342 size_t di = 0, si = 0, processed = 0; |
174 size_t di = 0, si = 0, processed = 0; |
| 343 |
175 |
| 344 // search the list for insertion points |
176 // search the list for insertion points |
| 345 while (di < list->collection.size) { |
177 while (di < list->collection.size) { |
| 346 const void *list_elm = invoke_list_func(at, list, di); |
178 const void *list_elm = list->cl->at(list, di); |
| 347 |
179 |
| 348 // compare the current list element with the first source element |
180 // compare the current list element with the first source element |
| 349 // if less, skip the list elements |
181 // if less, skip the list elements |
| 350 // if equal, skip the list elements and optionally the source elements |
182 // if equal, skip the list elements and optionally the source elements |
| 351 { |
183 { |
| 352 int d = cmp(list_elm, src); |
184 int d = cx_list_compare_wrapper(list_elm, src, list); |
| 353 if (d <= 0) { |
185 if (d <= 0) { |
| 354 if (!allow_duplicates && d == 0) { |
186 if (!allow_duplicates && d == 0) { |
| 355 src += elem_size; |
187 src += elem_size; |
| 356 si++; |
188 si++; |
| 357 processed++; // we also count duplicates for the return value |
189 processed++; // we also count duplicates for the return value |
| 358 while (si < n && cmp(list_elm, src) == 0) { |
190 while (si < n && cx_list_compare_wrapper(list_elm, src, list) == 0) { |
| 359 src += elem_size; |
191 src += elem_size; |
| 360 si++; |
192 si++; |
| 361 processed++; |
193 processed++; |
| 362 } |
194 } |
| 363 if (processed == n) { |
195 if (processed == n) { |
| 464 if (tmp == NULL) abort(); // LCOV_EXCL_LINE |
296 if (tmp == NULL) abort(); // LCOV_EXCL_LINE |
| 465 |
297 |
| 466 // copy elements from source array |
298 // copy elements from source array |
| 467 char *loc = tmp; |
299 char *loc = tmp; |
| 468 for (size_t i = 0; i < list_size; i++) { |
300 for (size_t i = 0; i < list_size; i++) { |
| 469 void *src = invoke_list_func(at, list, i); |
301 void *src = list->cl->at(list, i); |
| 470 memcpy(loc, src, elem_size); |
302 memcpy(loc, src, elem_size); |
| 471 loc += elem_size; |
303 loc += elem_size; |
| 472 } |
304 } |
| 473 |
305 |
| 474 // qsort |
306 // qsort |
| 475 qsort(tmp, list_size, elem_size, |
307 cx_array_qsort_c(tmp, list_size, elem_size, cx_list_compare_wrapper, list); |
| 476 list->collection.cmpfunc); |
|
| 477 |
308 |
| 478 // copy elements back |
309 // copy elements back |
| 479 loc = tmp; |
310 loc = tmp; |
| 480 for (size_t i = 0; i < list_size; i++) { |
311 for (size_t i = 0; i < list_size; i++) { |
| 481 void *dest = invoke_list_func(at, list, i); |
312 void *dest = list->cl->at(list, i); |
| 482 memcpy(dest, loc, elem_size); |
313 memcpy(dest, loc, elem_size); |
| 483 loc += elem_size; |
314 loc += elem_size; |
| 484 } |
315 } |
| 485 |
316 |
| 486 cxFreeDefault(tmp); |
317 cxFreeDefault(tmp); |
| 510 |
341 |
| 511 void cx_list_init( |
342 void cx_list_init( |
| 512 struct cx_list_s *list, |
343 struct cx_list_s *list, |
| 513 struct cx_list_class_s *cl, |
344 struct cx_list_class_s *cl, |
| 514 const struct cx_allocator_s *allocator, |
345 const struct cx_allocator_s *allocator, |
| 515 cx_compare_func comparator, |
|
| 516 size_t elem_size |
346 size_t elem_size |
| 517 ) { |
347 ) { |
| 518 list->cl = cl; |
348 list->cl = cl; |
| 519 list->collection.allocator = allocator; |
349 list->collection.allocator = allocator; |
| 520 list->collection.cmpfunc = comparator; |
350 list->collection.size = 0; |
| |
351 list->collection.sorted = false; // should be set by the implementation |
| 521 if (elem_size > 0) { |
352 if (elem_size > 0) { |
| 522 list->collection.elem_size = elem_size; |
353 list->collection.elem_size = elem_size; |
| |
354 list->collection.simple_cmp = NULL; |
| |
355 list->collection.advanced_cmp = cx_ccmp_memcmp; |
| |
356 list->collection.cmp_data = &list->collection.elem_size; |
| |
357 list->collection.store_pointer = false; |
| 523 } else { |
358 } else { |
| 524 list->collection.elem_size = sizeof(void *); |
359 list->collection.elem_size = sizeof(void *); |
| 525 if (list->collection.cmpfunc == NULL) { |
360 list->collection.simple_cmp = cx_cmp_ptr; |
| 526 list->collection.cmpfunc = cx_cmp_ptr; |
361 list->collection.advanced_cmp = NULL; |
| 527 } |
362 list->collection.cmp_data = NULL; |
| 528 list->collection.store_pointer = true; |
363 list->collection.store_pointer = true; |
| 529 list->climpl = list->cl; |
|
| 530 list->cl = &cx_pointer_list_class; |
|
| 531 } |
364 } |
| 532 } |
365 } |
| 533 |
366 |
| 534 int cxListCompare( |
367 int cxListCompare( |
| 535 const CxList *list, |
368 const CxList *list, |
| 536 const CxList *other |
369 const CxList *other |
| 537 ) { |
370 ) { |
| |
371 // check if we cannot use the list internal function |
| 538 bool cannot_optimize = false; |
372 bool cannot_optimize = false; |
| 539 |
373 |
| 540 // if one is storing pointers but the other is not |
374 // if one is storing pointers but the other is not |
| 541 cannot_optimize |= list->collection.store_pointer ^ other->collection.store_pointer; |
375 cannot_optimize |= list->collection.store_pointer ^ other->collection.store_pointer; |
| 542 |
376 |
| 543 // if one class is wrapped but the other is not |
377 // check if the lists are incompatible or this list does not implement compare |
| 544 cannot_optimize |= (list->climpl == NULL) ^ (other->climpl == NULL); |
378 cx_compare_func list_cmp = (cx_compare_func) list->cl->compare; |
| 545 |
379 cx_compare_func other_cmp = (cx_compare_func) other->cl->compare; |
| 546 // if the compare functions do not match or both are NULL |
380 cannot_optimize |= list_cmp != other_cmp; |
| 547 if (!cannot_optimize) { |
381 cannot_optimize |= list_cmp == NULL; |
| 548 cx_compare_func list_cmp = (cx_compare_func) (list->climpl != NULL ? |
|
| 549 list->climpl->compare : list->cl->compare); |
|
| 550 cx_compare_func other_cmp = (cx_compare_func) (other->climpl != NULL ? |
|
| 551 other->climpl->compare : other->cl->compare); |
|
| 552 cannot_optimize |= list_cmp != other_cmp; |
|
| 553 cannot_optimize |= list_cmp == NULL; |
|
| 554 } |
|
| 555 |
382 |
| 556 if (cannot_optimize) { |
383 if (cannot_optimize) { |
| 557 // lists are definitely different - cannot use internal compare function |
384 // lists are definitely different - cannot use internal compare function |
| 558 if (list->collection.size == other->collection.size) { |
385 if (list->collection.size == other->collection.size) { |
| 559 CxIterator left = list->cl->iterator(list, 0, false); |
386 CxIterator left = cxListIterator(list); |
| 560 CxIterator right = other->cl->iterator(other, 0, false); |
387 CxIterator right = cxListIterator(other); |
| 561 for (size_t i = 0; i < list->collection.size; i++) { |
388 for (size_t i = 0; i < list->collection.size; i++) { |
| 562 void *leftValue = cxIteratorCurrent(left); |
389 void *leftValue = cxIteratorCurrent(left); |
| 563 void *rightValue = cxIteratorCurrent(right); |
390 void *rightValue = cxIteratorCurrent(right); |
| 564 int d = list->collection.cmpfunc(leftValue, rightValue); |
391 // values are already unwrapped, invoke immediately |
| |
392 int d = cx_invoke_compare_func(list, leftValue, rightValue); |
| 565 if (d != 0) { |
393 if (d != 0) { |
| 566 return d; |
394 return d; |
| 567 } |
395 } |
| 568 cxIteratorNext(left); |
396 cxIteratorNext(left); |
| 569 cxIteratorNext(right); |
397 cxIteratorNext(right); |
| 582 return list->collection.size; |
410 return list->collection.size; |
| 583 } |
411 } |
| 584 |
412 |
| 585 int cxListAdd(CxList *list, const void *elem) { |
413 int cxListAdd(CxList *list, const void *elem) { |
| 586 list->collection.sorted = false; |
414 list->collection.sorted = false; |
| 587 return list->cl->insert_element(list, list->collection.size, elem) == NULL; |
415 return list->cl->insert_element(list, list->collection.size, cx_ref(list, elem)) == NULL; |
| 588 } |
416 } |
| 589 |
417 |
| 590 size_t cxListAddArray(CxList *list, const void *array, size_t n) { |
418 size_t cxListAddArray(CxList *list, const void *array, size_t n) { |
| 591 list->collection.sorted = false; |
419 list->collection.sorted = false; |
| 592 return list->cl->insert_array(list, list->collection.size, array, n); |
420 return list->cl->insert_array(list, list->collection.size, array, n); |
| 593 } |
421 } |
| 594 |
422 |
| 595 int cxListInsert(CxList *list, size_t index, const void *elem) { |
423 int cxListInsert(CxList *list, size_t index, const void *elem) { |
| 596 list->collection.sorted = false; |
424 list->collection.sorted = false; |
| 597 return list->cl->insert_element(list, index, elem) == NULL; |
425 return list->cl->insert_element(list, index, cx_ref(list, elem)) == NULL; |
| 598 } |
426 } |
| 599 |
427 |
| 600 void *cxListEmplaceAt(CxList *list, size_t index) { |
428 void *cxListEmplaceAt(CxList *list, size_t index) { |
| 601 list->collection.sorted = false; |
429 list->collection.sorted = false; |
| 602 return list->cl->insert_element(list, index, NULL); |
430 return list->cl->insert_element(list, index, NULL); |
| 619 // tweak the fields of this iterator |
447 // tweak the fields of this iterator |
| 620 iter.elem_count = c; |
448 iter.elem_count = c; |
| 621 iter.index = 0; |
449 iter.index = 0; |
| 622 // replace the valid function to abort iteration when c is reached |
450 // replace the valid function to abort iteration when c is reached |
| 623 iter.base.valid = cx_list_emplace_iterator_valid; |
451 iter.base.valid = cx_list_emplace_iterator_valid; |
| 624 // if we are storing pointers, we want to return the pure pointers. |
|
| 625 // therefore, we must unwrap the "current" method |
|
| 626 if (list->collection.store_pointer) { |
|
| 627 iter.base.current = iter.base.current_impl; |
|
| 628 } |
|
| 629 return iter; |
452 return iter; |
| 630 } |
453 } |
| 631 |
454 |
| 632 CxIterator cxListEmplaceArray(CxList *list, size_t n) { |
455 CxIterator cxListEmplaceArray(CxList *list, size_t n) { |
| 633 return cxListEmplaceArrayAt(list, list->collection.size, n); |
456 return cxListEmplaceArrayAt(list, list->collection.size, n); |
| 634 } |
457 } |
| 635 |
458 |
| 636 int cxListInsertSorted(CxList *list, const void *elem) { |
459 int cxListInsertSorted(CxList *list, const void *elem) { |
| 637 assert(cxCollectionSorted(list)); |
460 assert(cxCollectionSorted(list)); |
| 638 list->collection.sorted = true; |
461 list->collection.sorted = true; |
| 639 const void *data = list->collection.store_pointer ? &elem : elem; |
462 return list->cl->insert_sorted(list, cx_ref(list, elem), 1) == 0; |
| 640 return list->cl->insert_sorted(list, data, 1) == 0; |
|
| 641 } |
463 } |
| 642 |
464 |
| 643 int cxListInsertUnique(CxList *list, const void *elem) { |
465 int cxListInsertUnique(CxList *list, const void *elem) { |
| 644 if (cxCollectionSorted(list)) { |
466 if (cxCollectionSorted(list)) { |
| 645 list->collection.sorted = true; |
467 list->collection.sorted = true; |
| 646 const void *data = list->collection.store_pointer ? &elem : elem; |
468 return list->cl->insert_unique(list, cx_ref(list, elem), 1) == 0; |
| 647 return list->cl->insert_unique(list, data, 1) == 0; |
|
| 648 } else { |
469 } else { |
| 649 if (cxListContains(list, elem)) { |
470 if (cxListContains(list, elem)) { |
| 650 return 0; |
471 return 0; |
| 651 } else { |
472 } else { |
| 652 return cxListAdd(list, elem); |
473 return cxListAdd(list, elem); |
| 685 return n; |
505 return n; |
| 686 } |
506 } |
| 687 } |
507 } |
| 688 |
508 |
| 689 int cxListInsertAfter(CxIterator *iter, const void *elem) { |
509 int cxListInsertAfter(CxIterator *iter, const void *elem) { |
| 690 CxList* list = (CxList*)iter->src_handle; |
510 CxList* list = iter->src_handle; |
| 691 list->collection.sorted = false; |
511 list->collection.sorted = false; |
| 692 return list->cl->insert_iter(iter, elem, 0); |
512 return list->cl->insert_iter(iter, cx_ref(list, elem), 0); |
| 693 } |
513 } |
| 694 |
514 |
| 695 int cxListInsertBefore(CxIterator *iter, const void *elem) { |
515 int cxListInsertBefore(CxIterator *iter, const void *elem) { |
| 696 CxList* list = (CxList*)iter->src_handle; |
516 CxList* list = iter->src_handle; |
| 697 list->collection.sorted = false; |
517 list->collection.sorted = false; |
| 698 return list->cl->insert_iter(iter, elem, 1); |
518 return list->cl->insert_iter(iter, cx_ref(list, elem), 1); |
| 699 } |
519 } |
| 700 |
520 |
| 701 int cxListRemove(CxList *list, size_t index) { |
521 int cxListRemove(CxList *list, size_t index) { |
| 702 return list->cl->remove(list, index, 1, NULL) == 0; |
522 return list->cl->remove(list, index, 1, NULL) == 0; |
| 703 } |
523 } |
| 732 list->collection.sorted = false; |
552 list->collection.sorted = false; |
| 733 return list->cl->swap(list, i, j); |
553 return list->cl->swap(list, i, j); |
| 734 } |
554 } |
| 735 |
555 |
| 736 void *cxListAt(const CxList *list, size_t index) { |
556 void *cxListAt(const CxList *list, size_t index) { |
| 737 return list->cl->at(list, index); |
557 void *result = list->cl->at(list, index); |
| |
558 if (result == NULL) return NULL; |
| |
559 return cx_deref(list, result); |
| 738 } |
560 } |
| 739 |
561 |
| 740 void *cxListFirst(const CxList *list) { |
562 void *cxListFirst(const CxList *list) { |
| 741 return list->cl->at(list, 0); |
563 return cxListAt(list, 0); |
| 742 } |
564 } |
| 743 |
565 |
| 744 void *cxListLast(const CxList *list) { |
566 void *cxListLast(const CxList *list) { |
| 745 return list->cl->at(list, list->collection.size - 1); |
567 return cxListAt(list, list->collection.size - 1); |
| 746 } |
568 } |
| 747 |
569 |
| 748 int cxListSet(CxList *list, size_t index, const void *elem) { |
570 int cxListSet(CxList *list, size_t index, const void *elem) { |
| 749 if (index >= list->collection.size) { |
571 if (index >= list->collection.size) { |
| 750 return 1; |
572 return 1; |
| 751 } |
573 } |
| 752 |
574 |
| 753 if (list->collection.store_pointer) { |
575 if (list->collection.store_pointer) { |
| 754 // For pointer collections, always use climpl |
576 void **target = list->cl->at(list, index); |
| 755 void **target = list->climpl->at(list, index); |
|
| 756 *target = (void *)elem; |
577 *target = (void *)elem; |
| 757 } else { |
578 } else { |
| 758 void *target = list->cl->at(list, index); |
579 void *target = list->cl->at(list, index); |
| 759 memcpy(target, elem, list->collection.elem_size); |
580 memcpy(target, elem, list->collection.elem_size); |
| 760 } |
581 } |
| 761 |
582 |
| 762 return 0; |
583 return 0; |
| 763 } |
584 } |
| 764 |
585 |
| |
586 static void *cx_pl_iter_current(const void *it) { |
| |
587 const struct cx_iterator_s *iter = it; |
| |
588 void **ptr = iter->base.current_impl(it); |
| |
589 return ptr == NULL ? NULL : *ptr; |
| |
590 } |
| |
591 |
| |
592 CX_INLINE CxIterator cx_pl_iter_wrap(const CxList *list, CxIterator iter) { |
| |
593 if (cxCollectionStoresPointers(list)) { |
| |
594 iter.base.current_impl = iter.base.current; |
| |
595 iter.base.current = cx_pl_iter_current; |
| |
596 return iter; |
| |
597 } else { |
| |
598 return iter; |
| |
599 } |
| |
600 } |
| |
601 |
| 765 CxIterator cxListIteratorAt(const CxList *list, size_t index) { |
602 CxIterator cxListIteratorAt(const CxList *list, size_t index) { |
| 766 if (list == NULL) list = cxEmptyList; |
603 if (list == NULL) list = cxEmptyList; |
| 767 return list->cl->iterator(list, index, false); |
604 return cx_pl_iter_wrap(list, list->cl->iterator(list, index, false)); |
| 768 } |
605 } |
| 769 |
606 |
| 770 CxIterator cxListBackwardsIteratorAt(const CxList *list, size_t index) { |
607 CxIterator cxListBackwardsIteratorAt(const CxList *list, size_t index) { |
| 771 if (list == NULL) list = cxEmptyList; |
608 if (list == NULL) list = cxEmptyList; |
| 772 return list->cl->iterator(list, index, true); |
609 return cx_pl_iter_wrap(list, list->cl->iterator(list, index, true)); |
| 773 } |
610 } |
| 774 |
611 |
| 775 CxIterator cxListIterator(const CxList *list) { |
612 CxIterator cxListIterator(const CxList *list) { |
| 776 if (list == NULL) list = cxEmptyList; |
613 if (list == NULL) list = cxEmptyList; |
| 777 return list->cl->iterator(list, 0, false); |
614 return cx_pl_iter_wrap(list, list->cl->iterator(list, 0, false)); |
| 778 } |
615 } |
| 779 |
616 |
| 780 CxIterator cxListBackwardsIterator(const CxList *list) { |
617 CxIterator cxListBackwardsIterator(const CxList *list) { |
| 781 if (list == NULL) list = cxEmptyList; |
618 if (list == NULL) list = cxEmptyList; |
| 782 return list->cl->iterator(list, list->collection.size - 1, true); |
619 return cx_pl_iter_wrap(list, list->cl->iterator(list, list->collection.size - 1, true)); |
| 783 } |
620 } |
| 784 |
621 |
| 785 size_t cxListFind(const CxList *list, const void *elem) { |
622 size_t cxListFind(const CxList *list, const void *elem) { |
| 786 return list->cl->find_remove((CxList*)list, elem, false); |
623 return list->cl->find_remove((CxList*)list, cx_ref(list, elem), false); |
| 787 } |
624 } |
| 788 |
625 |
| 789 bool cxListContains(const CxList* list, const void* elem) { |
626 bool cxListContains(const CxList* list, const void* elem) { |
| 790 return list->cl->find_remove((CxList*)list, elem, false) < list->collection.size; |
627 return list->cl->find_remove((CxList*)list, cx_ref(list, elem), false) < list->collection.size; |
| 791 } |
628 } |
| 792 |
629 |
| 793 bool cxListIndexValid(const CxList *list, size_t index) { |
630 bool cxListIndexValid(const CxList *list, size_t index) { |
| 794 return index < list->collection.size; |
631 return index < list->collection.size; |
| 795 } |
632 } |
| 796 |
633 |
| 797 size_t cxListFindRemove(CxList *list, const void *elem) { |
634 size_t cxListFindRemove(CxList *list, const void *elem) { |
| 798 return list->cl->find_remove(list, elem, true); |
635 return list->cl->find_remove(list, cx_ref(list, elem), true); |
| 799 } |
636 } |
| 800 |
637 |
| 801 void cxListSort(CxList *list) { |
638 void cxListSort(CxList *list) { |
| 802 if (list->collection.sorted) return; |
639 if (list->collection.sorted) return; |
| 803 list->cl->sort(list); |
640 list->cl->sort(list); |
| 827 } |
664 } |
| 828 list->collection.simple_destructor = destr_bak; |
665 list->collection.simple_destructor = destr_bak; |
| 829 list->collection.advanced_destructor = destr2_bak; |
666 list->collection.advanced_destructor = destr2_bak; |
| 830 } |
667 } |
| 831 |
668 |
| 832 static void* cx_list_simple_clone_func(void *dst, const void *src, const CxAllocator *al, void *data) { |
669 static void* cx_list_shallow_clone_func(void *dst, const void *src, const CxAllocator *al, void *data) { |
| 833 size_t elem_size = *(size_t*)data; |
670 size_t elem_size = *(size_t*)data; |
| 834 if (dst == NULL) dst = cxMalloc(al, elem_size); |
671 if (dst == NULL) dst = cxMalloc(al, elem_size); |
| 835 if (dst != NULL) memcpy(dst, src, elem_size); |
672 if (dst != NULL) memcpy(dst, src, elem_size); |
| 836 return dst; |
673 return dst; |
| 837 } |
674 } |
| 838 |
675 |
| 839 #define use_simple_clone_func(list) cx_list_simple_clone_func, NULL, (void*)&((list)->collection.elem_size) |
676 #define use_shallow_clone_func(list) cx_list_shallow_clone_func, NULL, (void*)&((list)->collection.elem_size) |
| 840 |
677 |
| 841 int cxListClone(CxList *dst, const CxList *src, cx_clone_func clone_func, |
678 int cxListClone(CxList *dst, const CxList *src, cx_clone_func clone_func, |
| 842 const CxAllocator *clone_allocator, void *data) { |
679 const CxAllocator *clone_allocator, void *data) { |
| 843 if (clone_allocator == NULL) clone_allocator = cxDefaultAllocator; |
680 if (clone_allocator == NULL) clone_allocator = cxDefaultAllocator; |
| 844 |
681 |
| 969 CxIterator src_iter = cxListIterator(src); |
805 CxIterator src_iter = cxListIterator(src); |
| 970 CxIterator other_iter = cxListIterator(other); |
806 CxIterator other_iter = cxListIterator(other); |
| 971 while (cxIteratorValid(src_iter) && cxIteratorValid(other_iter)) { |
807 while (cxIteratorValid(src_iter) && cxIteratorValid(other_iter)) { |
| 972 void *src_elem = cxIteratorCurrent(src_iter); |
808 void *src_elem = cxIteratorCurrent(src_iter); |
| 973 void *other_elem = cxIteratorCurrent(other_iter); |
809 void *other_elem = cxIteratorCurrent(other_iter); |
| 974 int d = src->collection.cmpfunc(src_elem, other_elem); |
810 int d = cx_list_compare_wrapper(src_elem, other_elem, src); |
| 975 if (d == 0) { |
811 if (d == 0) { |
| 976 // is contained, clone it |
812 // is contained, clone it |
| 977 void **dst_mem = cxListEmplace(dst); |
813 void **dst_mem = cxListEmplace(dst); |
| 978 void *target = cxCollectionStoresPointers(dst) ? NULL : dst_mem; |
814 void *target = cxCollectionStoresPointers(dst) ? NULL : dst_mem; |
| 979 void* dst_ptr = clone_func(target, src_elem, clone_allocator, data); |
815 void* dst_ptr = clone_func(target, src_elem, clone_allocator, data); |
| 1095 } |
931 } |
| 1096 |
932 |
| 1097 return 0; |
933 return 0; |
| 1098 } |
934 } |
| 1099 |
935 |
| 1100 int cxListCloneSimple(CxList *dst, const CxList *src) { |
936 int cxListCloneShallow(CxList *dst, const CxList *src) { |
| 1101 return cxListClone(dst, src, use_simple_clone_func(src)); |
937 return cxListClone(dst, src, use_shallow_clone_func(src)); |
| 1102 } |
938 } |
| 1103 |
939 |
| 1104 int cxListDifferenceSimple(CxList *dst, const CxList *minuend, const CxList *subtrahend) { |
940 int cxListDifferenceShallow(CxList *dst, const CxList *minuend, const CxList *subtrahend) { |
| 1105 return cxListDifference(dst, minuend, subtrahend, use_simple_clone_func(minuend)); |
941 return cxListDifference(dst, minuend, subtrahend, use_shallow_clone_func(minuend)); |
| 1106 } |
942 } |
| 1107 |
943 |
| 1108 int cxListIntersectionSimple(CxList *dst, const CxList *src, const CxList *other) { |
944 int cxListIntersectionShallow(CxList *dst, const CxList *src, const CxList *other) { |
| 1109 return cxListIntersection(dst, src, other, use_simple_clone_func(src)); |
945 return cxListIntersection(dst, src, other, use_shallow_clone_func(src)); |
| 1110 } |
946 } |
| 1111 |
947 |
| 1112 int cxListUnionSimple(CxList *dst, const CxList *src, const CxList *other) { |
948 int cxListUnionShallow(CxList *dst, const CxList *src, const CxList *other) { |
| 1113 return cxListUnion(dst, src, other, use_simple_clone_func(src)); |
949 return cxListUnion(dst, src, other, use_shallow_clone_func(src)); |
| 1114 } |
950 } |
| 1115 |
951 |
| 1116 int cxListReserve(CxList *list, size_t capacity) { |
952 int cxListReserve(CxList *list, size_t capacity) { |
| 1117 if (list->cl->change_capacity == NULL) { |
953 if (list->cl->change_capacity == NULL) { |
| 1118 return 0; |
954 return 0; |