ucx/list.c

changeset 22
112b85020dc9
parent 21
5ea41679e15d
child 23
b26390e77237
equal deleted inserted replaced
21:5ea41679e15d 22:112b85020dc9
27 */ 27 */
28 28
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 33
33 // <editor-fold desc="Store Pointers Functionality"> 34 // <editor-fold desc="Store Pointers Functionality">
34 35
35 static _Thread_local cx_compare_func cx_pl_cmpfunc_impl; 36 static _Thread_local cx_compare_func cx_pl_cmpfunc_impl;
36 37
37 static int cx_pl_cmpfunc( 38 static int cx_pl_cmpfunc(
38 const void *l, 39 const void *l,
39 const void *r 40 const void *r
40 ) { 41 ) {
42 // l and r are guaranteed to be non-NULL pointing to the list's memory
41 void *const *lptr = l; 43 void *const *lptr = l;
42 void *const *rptr = r; 44 void *const *rptr = r;
43 const void *left = lptr == NULL ? NULL : *lptr; 45 const void *left = *lptr;
44 const void *right = rptr == NULL ? NULL : *rptr; 46 const void *right = *rptr;
47 if (left == NULL) {
48 // NULL is smaller than any value except NULL
49 return right == NULL ? 0 : -1;
50 } else if (right == NULL) {
51 // any value is larger than NULL
52 return 1;
53 }
45 return cx_pl_cmpfunc_impl(left, right); 54 return cx_pl_cmpfunc_impl(left, right);
46 } 55 }
47 56
48 static void cx_pl_hack_cmpfunc(const struct cx_list_s *list) { 57 static void cx_pl_hack_cmpfunc(const struct cx_list_s *list) {
49 // cast away const - this is the hacky thing 58 // cast away const - this is the hacky thing
88 size_t result = list->climpl->insert_sorted(list, array, n); 97 size_t result = list->climpl->insert_sorted(list, array, n);
89 cx_pl_unhack_cmpfunc(list); 98 cx_pl_unhack_cmpfunc(list);
90 return result; 99 return result;
91 } 100 }
92 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
93 static int cx_pl_insert_iter( 113 static int cx_pl_insert_iter(
94 struct cx_iterator_s *iter, 114 struct cx_iterator_s *iter,
95 const void *elem, 115 const void *elem,
96 int prepend 116 int prepend
97 ) { 117 ) {
98 struct cx_list_s *list = iter->src_handle.m; 118 struct cx_list_s *list = iter->src_handle;
99 return list->climpl->insert_iter(iter, &elem, prepend); 119 return list->climpl->insert_iter(iter, &elem, prepend);
100 } 120 }
101 121
102 static size_t cx_pl_remove( 122 static size_t cx_pl_remove(
103 struct cx_list_s *list, 123 struct cx_list_s *list,
163 const struct cx_iterator_s *iter = it; 183 const struct cx_iterator_s *iter = it;
164 void **ptr = iter->base.current_impl(it); 184 void **ptr = iter->base.current_impl(it);
165 return ptr == NULL ? NULL : *ptr; 185 return ptr == NULL ? NULL : *ptr;
166 } 186 }
167 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
168 static struct cx_iterator_s cx_pl_iterator( 196 static struct cx_iterator_s cx_pl_iterator(
169 const struct cx_list_s *list, 197 const struct cx_list_s *list,
170 size_t index, 198 size_t index,
171 bool backwards 199 bool backwards
172 ) { 200 ) {
179 static cx_list_class cx_pointer_list_class = { 207 static cx_list_class cx_pointer_list_class = {
180 cx_pl_destructor, 208 cx_pl_destructor,
181 cx_pl_insert_element, 209 cx_pl_insert_element,
182 cx_pl_insert_array, 210 cx_pl_insert_array,
183 cx_pl_insert_sorted, 211 cx_pl_insert_sorted,
212 cx_pl_insert_unique,
184 cx_pl_insert_iter, 213 cx_pl_insert_iter,
185 cx_pl_remove, 214 cx_pl_remove,
186 cx_pl_clear, 215 cx_pl_clear,
187 cx_pl_swap, 216 cx_pl_swap,
188 cx_pl_at, 217 cx_pl_at,
189 cx_pl_find_remove, 218 cx_pl_find_remove,
190 cx_pl_sort, 219 cx_pl_sort,
191 cx_pl_compare, 220 cx_pl_compare,
192 cx_pl_reverse, 221 cx_pl_reverse,
222 cx_pl_change_capacity,
193 cx_pl_iterator, 223 cx_pl_iterator,
194 }; 224 };
195 // </editor-fold> 225 // </editor-fold>
196 226
197 // <editor-fold desc="empty list implementation"> 227 // <editor-fold desc="empty list implementation">
223 const struct cx_list_s *list, 253 const struct cx_list_s *list,
224 size_t index, 254 size_t index,
225 cx_attr_unused bool backwards 255 cx_attr_unused bool backwards
226 ) { 256 ) {
227 CxIterator iter = {0}; 257 CxIterator iter = {0};
228 iter.src_handle.c = list; 258 iter.src_handle = (void*) list;
229 iter.index = index; 259 iter.index = index;
230 iter.base.valid = cx_emptyl_iter_valid; 260 iter.base.valid = cx_emptyl_iter_valid;
231 return iter; 261 return iter;
232 } 262 }
233 263
236 NULL, 266 NULL,
237 NULL, 267 NULL,
238 NULL, 268 NULL,
239 NULL, 269 NULL,
240 NULL, 270 NULL,
271 NULL,
241 cx_emptyl_noop, 272 cx_emptyl_noop,
242 NULL, 273 NULL,
243 cx_emptyl_at, 274 cx_emptyl_at,
244 cx_emptyl_find_remove, 275 cx_emptyl_find_remove,
245 cx_emptyl_noop, 276 cx_emptyl_noop,
246 NULL, 277 NULL,
247 cx_emptyl_noop, 278 cx_emptyl_noop,
279 NULL,
248 cx_emptyl_iterator, 280 cx_emptyl_iterator,
249 }; 281 };
250 282
251 CxList cx_empty_list = { 283 CxList cx_empty_list = {
252 { 284 {
276 struct cx_list_s *list, 308 struct cx_list_s *list,
277 size_t index, 309 size_t index,
278 const void *data, 310 const void *data,
279 size_t n 311 size_t n
280 ) { 312 ) {
281 size_t elem_size = list->collection.elem_size;
282 const char *src = data; 313 const char *src = data;
283 size_t i = 0; 314 size_t i = 0;
284 for (; i < n; i++) { 315 for (; i < n; i++) {
285 if (NULL == invoke_list_func( 316 if (NULL == invoke_list_func(
286 insert_element, list, index + i, 317 insert_element, list, index + i, src)
287 src + (i * elem_size))) return i; 318 ) {
319 return i; // LCOV_EXCL_LINE
320 }
321 if (src != NULL) {
322 src += list->collection.elem_size;
323 }
288 } 324 }
289 return i; 325 return i;
326 }
327
328 static size_t cx_list_default_insert_sorted_impl(
329 struct cx_list_s *list,
330 const void *sorted_data,
331 size_t n,
332 bool allow_duplicates
333 ) {
334 // corner case
335 if (n == 0) return 0;
336
337 size_t elem_size = list->collection.elem_size;
338 cx_compare_func cmp = list->collection.cmpfunc;
339 const char *src = sorted_data;
340
341 // track indices and number of inserted items
342 size_t di = 0, si = 0, processed = 0;
343
344 // search the list for insertion points
345 while (di < list->collection.size) {
346 const void *list_elm = invoke_list_func(at, list, di);
347
348 // compare the current list element with the first source element
349 // if less, skip the list elements
350 // if equal, skip the list elements and optionally the source elements
351 {
352 int d = cmp(list_elm, src);
353 if (d <= 0) {
354 if (!allow_duplicates && d == 0) {
355 src += elem_size;
356 si++;
357 processed++; // we also count duplicates for the return value
358 while (si < n && cmp(list_elm, src) == 0) {
359 src += elem_size;
360 si++;
361 processed++;
362 }
363 if (processed == n) {
364 return processed;
365 }
366 }
367 di++;
368 continue;
369 }
370 }
371
372 // determine the number of consecutive elements that can be inserted
373 size_t ins = 1, skip = 0;
374 const char *next = src;
375 while (++si < n) {
376 if (!allow_duplicates) {
377 // skip duplicates within the source
378 if (cmp(next, next + elem_size) == 0) {
379 next += elem_size;
380 skip++;
381 continue;
382 } else {
383 if (skip > 0) {
384 // if we had to skip something, we must wait for the next run
385 next += elem_size;
386 break;
387 }
388 }
389 }
390 next += elem_size;
391 // once we become larger than the list elem, break
392 if (cmp(list_elm, next) <= 0) {
393 break;
394 }
395 // otherwise, we can insert one more
396 ins++;
397 }
398
399 // insert the elements at location si
400 if (ins == 1) {
401 if (NULL == invoke_list_func(insert_element, list, di, src)) {
402 return processed; // LCOV_EXCL_LINE
403 }
404 } else {
405 size_t r = invoke_list_func(insert_array, list, di, src, ins);
406 if (r < ins) {
407 return processed + r; // LCOV_EXCL_LINE
408 }
409 }
410 processed += ins + skip;
411 di += ins;
412
413 // everything inserted?
414 if (processed == n) {
415 return processed;
416 }
417 src = next;
418 }
419
420 // insert remaining items
421 if (si < n) {
422 if (allow_duplicates) {
423 processed += invoke_list_func(insert_array, list, di, src, n - si);
424 } else {
425 const void *last = di == 0 ? NULL : invoke_list_func(at, list, di - 1);
426 for (; si < n; si++) {
427 // skip duplicates within the source
428 if (last == NULL || cmp(last, src) != 0) {
429 if (NULL == invoke_list_func(insert_element, list, di, src)) {
430 return processed; // LCOV_EXCL_LINE
431 }
432 last = src;
433 di++;
434 }
435 processed++;
436 src += elem_size;
437 }
438 }
439 }
440
441 return processed;
290 } 442 }
291 443
292 size_t cx_list_default_insert_sorted( 444 size_t cx_list_default_insert_sorted(
293 struct cx_list_s *list, 445 struct cx_list_s *list,
294 const void *sorted_data, 446 const void *sorted_data,
295 size_t n 447 size_t n
296 ) { 448 ) {
297 // corner case 449 return cx_list_default_insert_sorted_impl(list, sorted_data, n, true);
298 if (n == 0) return 0; 450 }
299 451
300 size_t elem_size = list->collection.elem_size; 452 size_t cx_list_default_insert_unique(
301 cx_compare_func cmp = list->collection.cmpfunc; 453 struct cx_list_s *list,
302 const char *src = sorted_data; 454 const void *sorted_data,
303 455 size_t n
304 // track indices and number of inserted items 456 ) {
305 size_t di = 0, si = 0, inserted = 0; 457 return cx_list_default_insert_sorted_impl(list, sorted_data, n, false);
306
307 // search the list for insertion points
308 for (; di < list->collection.size; di++) {
309 const void *list_elm = invoke_list_func(at, list, di);
310
311 // compare current list element with first source element
312 // if less or equal, skip
313 if (cmp(list_elm, src) <= 0) {
314 continue;
315 }
316
317 // determine number of consecutive elements that can be inserted
318 size_t ins = 1;
319 const char *next = src;
320 while (++si < n) {
321 next += elem_size;
322 // once we become larger than the list elem, break
323 if (cmp(list_elm, next) <= 0) {
324 break;
325 }
326 // otherwise, we can insert one more
327 ins++;
328 }
329
330 // insert the elements at location si
331 if (ins == 1) {
332 if (NULL == invoke_list_func(
333 insert_element, list, di, src)) return inserted;
334 } else {
335 size_t r = invoke_list_func(insert_array, list, di, src, ins);
336 if (r < ins) return inserted + r;
337 }
338 inserted += ins;
339 di += ins;
340
341 // everything inserted?
342 if (inserted == n) return inserted;
343 src = next;
344 }
345
346 // insert remaining items
347 if (si < n) {
348 inserted += invoke_list_func(insert_array, list, di, src, n - si);
349 }
350
351 return inserted;
352 } 458 }
353 459
354 void cx_list_default_sort(struct cx_list_s *list) { 460 void cx_list_default_sort(struct cx_list_s *list) {
355 size_t elem_size = list->collection.elem_size; 461 size_t elem_size = list->collection.elem_size;
356 size_t list_size = list->collection.size; 462 size_t list_size = list->collection.size;
357 void *tmp = cxMallocDefault(elem_size * list_size); 463 void *tmp = cxMallocDefault(elem_size * list_size);
358 if (tmp == NULL) abort(); 464 if (tmp == NULL) abort(); // LCOV_EXCL_LINE
359 465
360 // copy elements from source array 466 // copy elements from source array
361 char *loc = tmp; 467 char *loc = tmp;
362 for (size_t i = 0; i < list_size; i++) { 468 for (size_t i = 0; i < list_size; i++) {
363 void *src = invoke_list_func(at, list, i); 469 void *src = invoke_list_func(at, list, i);
386 if (j >= list->collection.size) return 1; 492 if (j >= list->collection.size) return 1;
387 493
388 size_t elem_size = list->collection.elem_size; 494 size_t elem_size = list->collection.elem_size;
389 495
390 void *tmp = cxMallocDefault(elem_size); 496 void *tmp = cxMallocDefault(elem_size);
391 if (tmp == NULL) return 1; 497 if (tmp == NULL) return 1; // LCOV_EXCL_LINE
392 498
393 void *ip = invoke_list_func(at, list, i); 499 void *ip = invoke_list_func(at, list, i);
394 void *jp = invoke_list_func(at, list, j); 500 void *jp = invoke_list_func(at, list, j);
395 501
396 memcpy(tmp, ip, elem_size); 502 memcpy(tmp, ip, elem_size);
470 // lists are compatible 576 // lists are compatible
471 return list->cl->compare(list, other); 577 return list->cl->compare(list, other);
472 } 578 }
473 } 579 }
474 580
475 CxIterator cxListMutIteratorAt( 581 size_t cxListSize(const CxList *list) {
476 CxList *list, 582 return list->collection.size;
477 size_t index 583 }
478 ) { 584
479 CxIterator it = list->cl->iterator(list, index, false); 585 int cxListAdd(CxList *list, const void *elem) {
480 it.base.mutating = true; 586 list->collection.sorted = false;
481 return it; 587 return list->cl->insert_element(list, list->collection.size, elem) == NULL;
482 } 588 }
483 589
484 CxIterator cxListMutBackwardsIteratorAt( 590 size_t cxListAddArray(CxList *list, const void *array, size_t n) {
485 CxList *list, 591 list->collection.sorted = false;
486 size_t index 592 return list->cl->insert_array(list, list->collection.size, array, n);
487 ) { 593 }
488 CxIterator it = list->cl->iterator(list, index, true); 594
489 it.base.mutating = true; 595 int cxListInsert(CxList *list, size_t index, const void *elem) {
490 return it; 596 list->collection.sorted = false;
491 } 597 return list->cl->insert_element(list, index, elem) == NULL;
492 598 }
493 void cxListFree(CxList *list) { 599
494 if (list == NULL) return; 600 void *cxListEmplaceAt(CxList *list, size_t index) {
495 list->cl->deallocate(list); 601 list->collection.sorted = false;
496 } 602 return list->cl->insert_element(list, index, NULL);
497 603 }
498 int cxListSet( 604
499 CxList *list, 605 void *cxListEmplace(CxList *list) {
500 size_t index, 606 list->collection.sorted = false;
501 const void *elem 607 return list->cl->insert_element(list, list->collection.size, NULL);
502 ) { 608 }
609
610 static bool cx_list_emplace_iterator_valid(const void *it) {
611 const CxIterator *iter = it;
612 return iter->index < iter->elem_count;
613 }
614
615 CxIterator cxListEmplaceArrayAt(CxList *list, size_t index, size_t n) {
616 list->collection.sorted = false;
617 size_t c = list->cl->insert_array(list, index, NULL, n);
618 CxIterator iter = list->cl->iterator(list, index, false);
619 // tweak the fields of this iterator
620 iter.elem_count = c;
621 iter.index = 0;
622 // replace the valid function to abort iteration when c is reached
623 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;
630 }
631
632 CxIterator cxListEmplaceArray(CxList *list, size_t n) {
633 return cxListEmplaceArrayAt(list, list->collection.size, n);
634 }
635
636 int cxListInsertSorted(CxList *list, const void *elem) {
637 assert(cxCollectionSorted(list));
638 list->collection.sorted = true;
639 const void *data = list->collection.store_pointer ? &elem : elem;
640 return list->cl->insert_sorted(list, data, 1) == 0;
641 }
642
643 int cxListInsertUnique(CxList *list, const void *elem) {
644 if (cxCollectionSorted(list)) {
645 list->collection.sorted = true;
646 const void *data = list->collection.store_pointer ? &elem : elem;
647 return list->cl->insert_unique(list, data, 1) == 0;
648 } else {
649 if (cxListContains(list, elem)) {
650 return 0;
651 } else {
652 return cxListAdd(list, elem);
653 }
654 }
655 }
656
657 size_t cxListInsertArray(CxList *list, size_t index, const void *array, size_t n) {
658 list->collection.sorted = false;
659 return list->cl->insert_array(list, index, array, n);
660 }
661
662 size_t cxListInsertSortedArray(CxList *list, const void *array, size_t n) {
663 assert(cxCollectionSorted(list));
664 list->collection.sorted = true;
665 return list->cl->insert_sorted(list, array, n);
666 }
667
668 size_t cxListInsertUniqueArray(CxList *list, const void *array, size_t n) {
669 if (cxCollectionSorted(list)) {
670 list->collection.sorted = true;
671 return list->cl->insert_unique(list, array, n);
672 } else {
673 const char *source = array;
674 for (size_t i = 0 ; i < n; i++) {
675 // note: this also checks elements added in a previous iteration
676 const void *data = list->collection.store_pointer ?
677 *((const void**)source) : source;
678 if (!cxListContains(list, data)) {
679 if (cxListAdd(list, data)) {
680 return i; // LCOV_EXCL_LINE
681 }
682 }
683 source += list->collection.elem_size;
684 }
685 return n;
686 }
687 }
688
689 int cxListInsertAfter(CxIterator *iter, const void *elem) {
690 CxList* list = (CxList*)iter->src_handle;
691 list->collection.sorted = false;
692 return list->cl->insert_iter(iter, elem, 0);
693 }
694
695 int cxListInsertBefore(CxIterator *iter, const void *elem) {
696 CxList* list = (CxList*)iter->src_handle;
697 list->collection.sorted = false;
698 return list->cl->insert_iter(iter, elem, 1);
699 }
700
701 int cxListRemove(CxList *list, size_t index) {
702 return list->cl->remove(list, index, 1, NULL) == 0;
703 }
704
705 int cxListRemoveAndGet(CxList *list, size_t index, void *targetbuf) {
706 return list->cl->remove(list, index, 1, targetbuf) == 0;
707 }
708
709 int cxListRemoveAndGetFirst(CxList *list, void *targetbuf) {
710 return list->cl->remove(list, 0, 1, targetbuf) == 0;
711 }
712
713 int cxListRemoveAndGetLast(CxList *list, void *targetbuf) {
714 // note: index may wrap - member function will catch that
715 return list->cl->remove(list, list->collection.size - 1, 1, targetbuf) == 0;
716 }
717
718 size_t cxListRemoveArray(CxList *list, size_t index, size_t num) {
719 return list->cl->remove(list, index, num, NULL);
720 }
721
722 size_t cxListRemoveArrayAndGet(CxList *list, size_t index, size_t num, void *targetbuf) {
723 return list->cl->remove(list, index, num, targetbuf);
724 }
725
726 void cxListClear(CxList *list) {
727 list->cl->clear(list);
728 list->collection.sorted = true; // empty lists are always sorted
729 }
730
731 int cxListSwap(CxList *list, size_t i, size_t j) {
732 list->collection.sorted = false;
733 return list->cl->swap(list, i, j);
734 }
735
736 void *cxListAt(const CxList *list, size_t index) {
737 return list->cl->at(list, index);
738 }
739
740 void *cxListFirst(const CxList *list) {
741 return list->cl->at(list, 0);
742 }
743
744 void *cxListLast(const CxList *list) {
745 return list->cl->at(list, list->collection.size - 1);
746 }
747
748 int cxListSet(CxList *list, size_t index, const void *elem) {
503 if (index >= list->collection.size) { 749 if (index >= list->collection.size) {
504 return 1; 750 return 1;
505 } 751 }
506 752
507 if (list->collection.store_pointer) { 753 if (list->collection.store_pointer) {
513 memcpy(target, elem, list->collection.elem_size); 759 memcpy(target, elem, list->collection.elem_size);
514 } 760 }
515 761
516 return 0; 762 return 0;
517 } 763 }
764
765 CxIterator cxListIteratorAt(const CxList *list, size_t index) {
766 if (list == NULL) list = cxEmptyList;
767 return list->cl->iterator(list, index, false);
768 }
769
770 CxIterator cxListBackwardsIteratorAt(const CxList *list, size_t index) {
771 if (list == NULL) list = cxEmptyList;
772 return list->cl->iterator(list, index, true);
773 }
774
775 CxIterator cxListIterator(const CxList *list) {
776 if (list == NULL) list = cxEmptyList;
777 return list->cl->iterator(list, 0, false);
778 }
779
780 CxIterator cxListBackwardsIterator(const CxList *list) {
781 if (list == NULL) list = cxEmptyList;
782 return list->cl->iterator(list, list->collection.size - 1, true);
783 }
784
785 size_t cxListFind(const CxList *list, const void *elem) {
786 return list->cl->find_remove((CxList*)list, elem, false);
787 }
788
789 bool cxListContains(const CxList* list, const void* elem) {
790 return list->cl->find_remove((CxList*)list, elem, false) < list->collection.size;
791 }
792
793 bool cxListIndexValid(const CxList *list, size_t index) {
794 return index < list->collection.size;
795 }
796
797 size_t cxListFindRemove(CxList *list, const void *elem) {
798 return list->cl->find_remove(list, elem, true);
799 }
800
801 void cxListSort(CxList *list) {
802 if (list->collection.sorted) return;
803 list->cl->sort(list);
804 list->collection.sorted = true;
805 }
806
807 void cxListReverse(CxList *list) {
808 // still sorted, but not according to the cmp_func
809 list->collection.sorted = false;
810 list->cl->reverse(list);
811 }
812
813 void cxListFree(CxList *list) {
814 if (list == NULL) return;
815 list->cl->deallocate(list);
816 }
817
818 static void cx_list_pop_uninitialized_elements(CxList *list, size_t n) {
819 cx_destructor_func destr_bak = list->collection.simple_destructor;
820 cx_destructor_func2 destr2_bak = list->collection.advanced_destructor;
821 list->collection.simple_destructor = NULL;
822 list->collection.advanced_destructor = NULL;
823 if (n == 1) {
824 cxListRemove(list, list->collection.size - 1);
825 } else {
826 cxListRemoveArray(list,list->collection.size - n, n);
827 }
828 list->collection.simple_destructor = destr_bak;
829 list->collection.advanced_destructor = destr2_bak;
830 }
831
832 static void* cx_list_simple_clone_func(void *dst, const void *src, const CxAllocator *al, void *data) {
833 size_t elem_size = *(size_t*)data;
834 if (dst == NULL) dst = cxMalloc(al, elem_size);
835 if (dst != NULL) memcpy(dst, src, elem_size);
836 return dst;
837 }
838
839 #define use_simple_clone_func(list) cx_list_simple_clone_func, NULL, (void*)&((list)->collection.elem_size)
840
841 int cxListClone(CxList *dst, const CxList *src, cx_clone_func clone_func,
842 const CxAllocator *clone_allocator, void *data) {
843 if (clone_allocator == NULL) clone_allocator = cxDefaultAllocator;
844
845 // remember the original size
846 size_t orig_size = dst->collection.size;
847
848 // first, try to allocate the memory in the new list
849 CxIterator empl_iter = cxListEmplaceArray(dst, src->collection.size);
850
851 // get an iterator over the source elements
852 CxIterator src_iter = cxListIterator(src);
853
854 // now clone the elements
855 size_t cloned = empl_iter.elem_count;
856 for (size_t i = 0 ; i < empl_iter.elem_count; i++) {
857 void *src_elem = cxIteratorCurrent(src_iter);
858 void **dest_memory = cxIteratorCurrent(empl_iter);
859 void *target = cxCollectionStoresPointers(dst) ? NULL : dest_memory;
860 void *dest_ptr = clone_func(target, src_elem, clone_allocator, data);
861 if (dest_ptr == NULL) {
862 cloned = i;
863 break;
864 }
865 if (cxCollectionStoresPointers(dst)) {
866 *dest_memory = dest_ptr;
867 }
868 cxIteratorNext(src_iter);
869 cxIteratorNext(empl_iter);
870 }
871
872 // if we could not clone everything, free the allocated memory
873 // (disable the destructors!)
874 if (cloned < src->collection.size) {
875 cx_list_pop_uninitialized_elements(dst,
876 dst->collection.size - cloned - orig_size);
877 return 1;
878 }
879
880 // set the sorted flag when we know it's sorted
881 if (orig_size == 0 && src->collection.sorted) {
882 dst->collection.sorted = true;
883 }
884
885 return 0;
886 }
887
888 int cxListDifference(CxList *dst,
889 const CxList *minuend, const CxList *subtrahend,
890 cx_clone_func clone_func, const CxAllocator *clone_allocator, void *data) {
891 if (clone_allocator == NULL) clone_allocator = cxDefaultAllocator;
892
893 // optimize for sorted collections
894 if (cxCollectionSorted(minuend) && cxCollectionSorted(subtrahend)) {
895 bool dst_was_empty = cxCollectionSize(dst) == 0;
896
897 CxIterator min_iter = cxListIterator(minuend);
898 CxIterator sub_iter = cxListIterator(subtrahend);
899 while (cxIteratorValid(min_iter)) {
900 void *min_elem = cxIteratorCurrent(min_iter);
901 void *sub_elem;
902 int d;
903 if (cxIteratorValid(sub_iter)) {
904 sub_elem = cxIteratorCurrent(sub_iter);
905 cx_compare_func cmp = subtrahend->collection.cmpfunc;
906 d = cmp(sub_elem, min_elem);
907 } else {
908 // no more elements in the subtrahend,
909 // i.e., the min_elem is larger than any elem of the subtrahend
910 d = 1;
911 }
912 if (d == 0) {
913 // is contained, so skip it
914 cxIteratorNext(min_iter);
915 } else if (d < 0) {
916 // subtrahend is smaller than minuend,
917 // check the next element
918 cxIteratorNext(sub_iter);
919 } else {
920 // subtrahend is larger than the dst element,
921 // clone the minuend and advance
922 void **dst_mem = cxListEmplace(dst);
923 void *target = cxCollectionStoresPointers(dst) ? NULL : dst_mem;
924 void* dst_ptr = clone_func(target, min_elem, clone_allocator, data);
925 if (dst_ptr == NULL) {
926 cx_list_pop_uninitialized_elements(dst, 1);
927 return 1;
928 }
929 if (cxCollectionStoresPointers(dst)) {
930 *dst_mem = dst_ptr;
931 }
932 cxIteratorNext(min_iter);
933 }
934 }
935
936 // if dst was empty, it is now guaranteed to be sorted
937 dst->collection.sorted = dst_was_empty;
938 } else {
939 CxIterator min_iter = cxListIterator(minuend);
940 cx_foreach(void *, elem, min_iter) {
941 if (cxListContains(subtrahend, elem)) {
942 continue;
943 }
944 void **dst_mem = cxListEmplace(dst);
945 void *target = cxCollectionStoresPointers(dst) ? NULL : dst_mem;
946 void* dst_ptr = clone_func(target, elem, clone_allocator, data);
947 if (dst_ptr == NULL) {
948 cx_list_pop_uninitialized_elements(dst, 1);
949 return 1;
950 }
951 if (cxCollectionStoresPointers(dst)) {
952 *dst_mem = dst_ptr;
953 }
954 }
955 }
956
957 return 0;
958 }
959
960 int cxListIntersection(CxList *dst,
961 const CxList *src, const CxList *other,
962 cx_clone_func clone_func, const CxAllocator *clone_allocator, void *data) {
963 if (clone_allocator == NULL) clone_allocator = cxDefaultAllocator;
964
965 // optimize for sorted collections
966 if (cxCollectionSorted(src) && cxCollectionSorted(other)) {
967 bool dst_was_empty = cxCollectionSize(dst) == 0;
968
969 CxIterator src_iter = cxListIterator(src);
970 CxIterator other_iter = cxListIterator(other);
971 while (cxIteratorValid(src_iter) && cxIteratorValid(other_iter)) {
972 void *src_elem = cxIteratorCurrent(src_iter);
973 void *other_elem = cxIteratorCurrent(other_iter);
974 int d = src->collection.cmpfunc(src_elem, other_elem);
975 if (d == 0) {
976 // is contained, clone it
977 void **dst_mem = cxListEmplace(dst);
978 void *target = cxCollectionStoresPointers(dst) ? NULL : dst_mem;
979 void* dst_ptr = clone_func(target, src_elem, clone_allocator, data);
980 if (dst_ptr == NULL) {
981 cx_list_pop_uninitialized_elements(dst, 1);
982 return 1;
983 }
984 if (cxCollectionStoresPointers(dst)) {
985 *dst_mem = dst_ptr;
986 }
987 cxIteratorNext(src_iter);
988 } else if (d < 0) {
989 // the other element is larger, skip the source element
990 cxIteratorNext(src_iter);
991 } else {
992 // the source element is larger, try to find it in the other list
993 cxIteratorNext(other_iter);
994 }
995 }
996
997 // if dst was empty, it is now guaranteed to be sorted
998 dst->collection.sorted = dst_was_empty;
999 } else {
1000 CxIterator src_iter = cxListIterator(src);
1001 cx_foreach(void *, elem, src_iter) {
1002 if (!cxListContains(other, elem)) {
1003 continue;
1004 }
1005 void **dst_mem = cxListEmplace(dst);
1006 void *target = cxCollectionStoresPointers(dst) ? NULL : dst_mem;
1007 void* dst_ptr = clone_func(target, elem, clone_allocator, data);
1008 if (dst_ptr == NULL) {
1009 cx_list_pop_uninitialized_elements(dst, 1);
1010 return 1;
1011 }
1012 if (cxCollectionStoresPointers(dst)) {
1013 *dst_mem = dst_ptr;
1014 }
1015 }
1016 }
1017
1018 return 0;
1019 }
1020
1021 int cxListUnion(CxList *dst,
1022 const CxList *src, const CxList *other,
1023 cx_clone_func clone_func, const CxAllocator *clone_allocator, void *data) {
1024 if (clone_allocator == NULL) clone_allocator = cxDefaultAllocator;
1025
1026 // optimize for sorted collections
1027 if (cxCollectionSorted(src) && cxCollectionSorted(other)) {
1028 bool dst_was_empty = cxCollectionSize(dst) == 0;
1029
1030 CxIterator src_iter = cxListIterator(src);
1031 CxIterator other_iter = cxListIterator(other);
1032 while (cxIteratorValid(src_iter) || cxIteratorValid(other_iter)) {
1033 void *src_elem, *other_elem;
1034 int d;
1035 if (!cxIteratorValid(src_iter)) {
1036 other_elem = cxIteratorCurrent(other_iter);
1037 d = 1;
1038 } else if (!cxIteratorValid(other_iter)) {
1039 src_elem = cxIteratorCurrent(src_iter);
1040 d = -1;
1041 } else {
1042 src_elem = cxIteratorCurrent(src_iter);
1043 other_elem = cxIteratorCurrent(other_iter);
1044 d = src->collection.cmpfunc(src_elem, other_elem);
1045 }
1046 void *clone_from;
1047 if (d < 0) {
1048 // source element is smaller clone it
1049 clone_from = src_elem;
1050 cxIteratorNext(src_iter);
1051 } else if (d == 0) {
1052 // both elements are equal, clone from the source, skip other
1053 clone_from = src_elem;
1054 cxIteratorNext(src_iter);
1055 cxIteratorNext(other_iter);
1056 } else {
1057 // the other element is smaller, clone it
1058 clone_from = other_elem;
1059 cxIteratorNext(other_iter);
1060 }
1061 void **dst_mem = cxListEmplace(dst);
1062 void *target = cxCollectionStoresPointers(dst) ? NULL : dst_mem;
1063 void* dst_ptr = clone_func(target, clone_from, clone_allocator, data);
1064 if (dst_ptr == NULL) {
1065 cx_list_pop_uninitialized_elements(dst, 1);
1066 return 1;
1067 }
1068 if (cxCollectionStoresPointers(dst)) {
1069 *dst_mem = dst_ptr;
1070 }
1071 }
1072
1073 // if dst was empty, it is now guaranteed to be sorted
1074 dst->collection.sorted = dst_was_empty;
1075 } else {
1076 if (cxListClone(dst, src, clone_func, clone_allocator, data)) {
1077 return 1;
1078 }
1079 CxIterator other_iter = cxListIterator(other);
1080 cx_foreach(void *, elem, other_iter) {
1081 if (cxListContains(src, elem)) {
1082 continue;
1083 }
1084 void **dst_mem = cxListEmplace(dst);
1085 void *target = cxCollectionStoresPointers(dst) ? NULL : dst_mem;
1086 void* dst_ptr = clone_func(target, elem, clone_allocator, data);
1087 if (dst_ptr == NULL) {
1088 cx_list_pop_uninitialized_elements(dst, 1);
1089 return 1;
1090 }
1091 if (cxCollectionStoresPointers(dst)) {
1092 *dst_mem = dst_ptr;
1093 }
1094 }
1095 }
1096
1097 return 0;
1098 }
1099
1100 int cxListCloneSimple(CxList *dst, const CxList *src) {
1101 return cxListClone(dst, src, use_simple_clone_func(src));
1102 }
1103
1104 int cxListDifferenceSimple(CxList *dst, const CxList *minuend, const CxList *subtrahend) {
1105 return cxListDifference(dst, minuend, subtrahend, use_simple_clone_func(minuend));
1106 }
1107
1108 int cxListIntersectionSimple(CxList *dst, const CxList *src, const CxList *other) {
1109 return cxListIntersection(dst, src, other, use_simple_clone_func(src));
1110 }
1111
1112 int cxListUnionSimple(CxList *dst, const CxList *src, const CxList *other) {
1113 return cxListUnion(dst, src, other, use_simple_clone_func(src));
1114 }
1115
1116 int cxListReserve(CxList *list, size_t capacity) {
1117 if (list->cl->change_capacity == NULL) {
1118 return 0;
1119 }
1120 if (capacity <= cxCollectionSize(list)) {
1121 return 0;
1122 }
1123 return list->cl->change_capacity(list, capacity);
1124 }
1125
1126 int cxListShrink(CxList *list) {
1127 if (list->cl->change_capacity == NULL) {
1128 return 0;
1129 }
1130 return list->cl->change_capacity(list, cxCollectionSize(list));
1131 }

mercurial