ucx/list.c

branch
dav-2
changeset 889
42cdbf9bbd49
parent 886
da79af4baec8
equal deleted inserted replaced
887:26541c37b619 889:42cdbf9bbd49
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,
179 static cx_list_class cx_pointer_list_class = { 199 static cx_list_class cx_pointer_list_class = {
180 cx_pl_destructor, 200 cx_pl_destructor,
181 cx_pl_insert_element, 201 cx_pl_insert_element,
182 cx_pl_insert_array, 202 cx_pl_insert_array,
183 cx_pl_insert_sorted, 203 cx_pl_insert_sorted,
204 cx_pl_insert_unique,
184 cx_pl_insert_iter, 205 cx_pl_insert_iter,
185 cx_pl_remove, 206 cx_pl_remove,
186 cx_pl_clear, 207 cx_pl_clear,
187 cx_pl_swap, 208 cx_pl_swap,
188 cx_pl_at, 209 cx_pl_at,
223 const struct cx_list_s *list, 244 const struct cx_list_s *list,
224 size_t index, 245 size_t index,
225 cx_attr_unused bool backwards 246 cx_attr_unused bool backwards
226 ) { 247 ) {
227 CxIterator iter = {0}; 248 CxIterator iter = {0};
228 iter.src_handle.c = list; 249 iter.src_handle = (void*) list;
229 iter.index = index; 250 iter.index = index;
230 iter.base.valid = cx_emptyl_iter_valid; 251 iter.base.valid = cx_emptyl_iter_valid;
231 return iter; 252 return iter;
232 } 253 }
233 254
234 static cx_list_class cx_empty_list_class = { 255 static cx_list_class cx_empty_list_class = {
235 cx_emptyl_noop, 256 cx_emptyl_noop,
257 NULL,
236 NULL, 258 NULL,
237 NULL, 259 NULL,
238 NULL, 260 NULL,
239 NULL, 261 NULL,
240 NULL, 262 NULL,
276 struct cx_list_s *list, 298 struct cx_list_s *list,
277 size_t index, 299 size_t index,
278 const void *data, 300 const void *data,
279 size_t n 301 size_t n
280 ) { 302 ) {
281 size_t elem_size = list->collection.elem_size;
282 const char *src = data; 303 const char *src = data;
283 size_t i = 0; 304 size_t i = 0;
284 for (; i < n; i++) { 305 for (; i < n; i++) {
285 if (NULL == invoke_list_func( 306 if (NULL == invoke_list_func(
286 insert_element, list, index + i, 307 insert_element, list, index + i, src)
287 src + (i * elem_size))) return i; 308 ) {
309 return i; // LCOV_EXCL_LINE
310 }
311 if (src != NULL) {
312 src += list->collection.elem_size;
313 }
288 } 314 }
289 return i; 315 return i;
316 }
317
318 static size_t cx_list_default_insert_sorted_impl(
319 struct cx_list_s *list,
320 const void *sorted_data,
321 size_t n,
322 bool allow_duplicates
323 ) {
324 // corner case
325 if (n == 0) return 0;
326
327 size_t elem_size = list->collection.elem_size;
328 cx_compare_func cmp = list->collection.cmpfunc;
329 const char *src = sorted_data;
330
331 // track indices and number of inserted items
332 size_t di = 0, si = 0, processed = 0;
333
334 // search the list for insertion points
335 while (di < list->collection.size) {
336 const void *list_elm = invoke_list_func(at, list, di);
337
338 // compare the current list element with the first source element
339 // if less, skip the list elements
340 // if equal, skip the list elements and optionally the source elements
341 {
342 int d = cmp(list_elm, src);
343 if (d <= 0) {
344 if (!allow_duplicates && d == 0) {
345 src += elem_size;
346 si++;
347 processed++; // we also count duplicates for the return value
348 while (si < n && cmp(list_elm, src) == 0) {
349 src += elem_size;
350 si++;
351 processed++;
352 }
353 if (processed == n) {
354 return processed;
355 }
356 }
357 di++;
358 continue;
359 }
360 }
361
362 // determine the number of consecutive elements that can be inserted
363 size_t ins = 1, skip = 0;
364 const char *next = src;
365 while (++si < n) {
366 if (!allow_duplicates) {
367 // skip duplicates within the source
368 if (cmp(next, next + elem_size) == 0) {
369 next += elem_size;
370 skip++;
371 continue;
372 } else {
373 if (skip > 0) {
374 // if we had to skip something, we must wait for the next run
375 next += elem_size;
376 break;
377 }
378 }
379 }
380 next += elem_size;
381 // once we become larger than the list elem, break
382 if (cmp(list_elm, next) <= 0) {
383 break;
384 }
385 // otherwise, we can insert one more
386 ins++;
387 }
388
389 // insert the elements at location si
390 if (ins == 1) {
391 if (NULL == invoke_list_func(insert_element, list, di, src)) {
392 return processed; // LCOV_EXCL_LINE
393 }
394 } else {
395 size_t r = invoke_list_func(insert_array, list, di, src, ins);
396 if (r < ins) {
397 return processed + r; // LCOV_EXCL_LINE
398 }
399 }
400 processed += ins + skip;
401 di += ins;
402
403 // everything inserted?
404 if (processed == n) {
405 return processed;
406 }
407 src = next;
408 }
409
410 // insert remaining items
411 if (si < n) {
412 if (allow_duplicates) {
413 processed += invoke_list_func(insert_array, list, di, src, n - si);
414 } else {
415 const void *last = di == 0 ? NULL : invoke_list_func(at, list, di - 1);
416 for (; si < n; si++) {
417 // skip duplicates within the source
418 if (last == NULL || cmp(last, src) != 0) {
419 if (NULL == invoke_list_func(insert_element, list, di, src)) {
420 return processed; // LCOV_EXCL_LINE
421 }
422 last = src;
423 di++;
424 }
425 processed++;
426 src += elem_size;
427 }
428 }
429 }
430
431 return processed;
290 } 432 }
291 433
292 size_t cx_list_default_insert_sorted( 434 size_t cx_list_default_insert_sorted(
293 struct cx_list_s *list, 435 struct cx_list_s *list,
294 const void *sorted_data, 436 const void *sorted_data,
295 size_t n 437 size_t n
296 ) { 438 ) {
297 // corner case 439 return cx_list_default_insert_sorted_impl(list, sorted_data, n, true);
298 if (n == 0) return 0; 440 }
299 441
300 size_t elem_size = list->collection.elem_size; 442 size_t cx_list_default_insert_unique(
301 cx_compare_func cmp = list->collection.cmpfunc; 443 struct cx_list_s *list,
302 const char *src = sorted_data; 444 const void *sorted_data,
303 445 size_t n
304 // track indices and number of inserted items 446 ) {
305 size_t di = 0, si = 0, inserted = 0; 447 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 } 448 }
353 449
354 void cx_list_default_sort(struct cx_list_s *list) { 450 void cx_list_default_sort(struct cx_list_s *list) {
355 size_t elem_size = list->collection.elem_size; 451 size_t elem_size = list->collection.elem_size;
356 size_t list_size = list->collection.size; 452 size_t list_size = list->collection.size;
357 void *tmp = cxMallocDefault(elem_size * list_size); 453 void *tmp = cxMallocDefault(elem_size * list_size);
358 if (tmp == NULL) abort(); 454 if (tmp == NULL) abort(); // LCOV_EXCL_LINE
359 455
360 // copy elements from source array 456 // copy elements from source array
361 char *loc = tmp; 457 char *loc = tmp;
362 for (size_t i = 0; i < list_size; i++) { 458 for (size_t i = 0; i < list_size; i++) {
363 void *src = invoke_list_func(at, list, i); 459 void *src = invoke_list_func(at, list, i);
386 if (j >= list->collection.size) return 1; 482 if (j >= list->collection.size) return 1;
387 483
388 size_t elem_size = list->collection.elem_size; 484 size_t elem_size = list->collection.elem_size;
389 485
390 void *tmp = cxMallocDefault(elem_size); 486 void *tmp = cxMallocDefault(elem_size);
391 if (tmp == NULL) return 1; 487 if (tmp == NULL) return 1; // LCOV_EXCL_LINE
392 488
393 void *ip = invoke_list_func(at, list, i); 489 void *ip = invoke_list_func(at, list, i);
394 void *jp = invoke_list_func(at, list, j); 490 void *jp = invoke_list_func(at, list, j);
395 491
396 memcpy(tmp, ip, elem_size); 492 memcpy(tmp, ip, elem_size);
470 // lists are compatible 566 // lists are compatible
471 return list->cl->compare(list, other); 567 return list->cl->compare(list, other);
472 } 568 }
473 } 569 }
474 570
475 CxIterator cxListMutIteratorAt( 571 size_t cxListSize(const CxList *list) {
476 CxList *list, 572 return list->collection.size;
477 size_t index 573 }
478 ) { 574
479 if (list == NULL) list = cxEmptyList; 575 int cxListAdd(CxList *list, const void *elem) {
480 CxIterator it = list->cl->iterator(list, index, false); 576 list->collection.sorted = false;
481 it.base.mutating = true; 577 return list->cl->insert_element(list, list->collection.size, elem) == NULL;
482 return it; 578 }
483 } 579
484 580 size_t cxListAddArray(CxList *list, const void *array, size_t n) {
485 CxIterator cxListMutBackwardsIteratorAt( 581 list->collection.sorted = false;
486 CxList *list, 582 return list->cl->insert_array(list, list->collection.size, array, n);
487 size_t index 583 }
488 ) { 584
489 if (list == NULL) list = cxEmptyList; 585 int cxListInsert(CxList *list, size_t index, const void *elem) {
490 CxIterator it = list->cl->iterator(list, index, true); 586 list->collection.sorted = false;
491 it.base.mutating = true; 587 return list->cl->insert_element(list, index, elem) == NULL;
492 return it; 588 }
493 } 589
494 590 void *cxListEmplaceAt(CxList *list, size_t index) {
495 void cxListFree(CxList *list) { 591 list->collection.sorted = false;
496 if (list == NULL) return; 592 return list->cl->insert_element(list, index, NULL);
497 list->cl->deallocate(list); 593 }
498 } 594
499 595 void *cxListEmplace(CxList *list) {
500 int cxListSet( 596 list->collection.sorted = false;
501 CxList *list, 597 return list->cl->insert_element(list, list->collection.size, NULL);
502 size_t index, 598 }
503 const void *elem 599
504 ) { 600 static bool cx_list_emplace_iterator_valid(const void *it) {
601 const CxIterator *iter = it;
602 return iter->index < iter->elem_count;
603 }
604
605 CxIterator cxListEmplaceArrayAt(CxList *list, size_t index, size_t n) {
606 list->collection.sorted = false;
607 size_t c = list->cl->insert_array(list, index, NULL, n);
608 CxIterator iter = list->cl->iterator(list, index, false);
609 // tweak the fields of this iterator
610 iter.elem_count = c;
611 iter.index = 0;
612 // replace the valid function to abort iteration when c is reached
613 iter.base.valid = cx_list_emplace_iterator_valid;
614 // if we are storing pointers, we want to return the pure pointers.
615 // therefore, we must unwrap the "current" method
616 if (list->collection.store_pointer) {
617 iter.base.current = iter.base.current_impl;
618 }
619 return iter;
620 }
621
622 CxIterator cxListEmplaceArray(CxList *list, size_t n) {
623 return cxListEmplaceArrayAt(list, list->collection.size, n);
624 }
625
626 int cxListInsertSorted(CxList *list, const void *elem) {
627 assert(cxCollectionSorted(list));
628 list->collection.sorted = true;
629 const void *data = list->collection.store_pointer ? &elem : elem;
630 return list->cl->insert_sorted(list, data, 1) == 0;
631 }
632
633 int cxListInsertUnique(CxList *list, const void *elem) {
634 if (cxCollectionSorted(list)) {
635 list->collection.sorted = true;
636 const void *data = list->collection.store_pointer ? &elem : elem;
637 return list->cl->insert_unique(list, data, 1) == 0;
638 } else {
639 if (cxListContains(list, elem)) {
640 return 0;
641 } else {
642 return cxListAdd(list, elem);
643 }
644 }
645 }
646
647 size_t cxListInsertArray(CxList *list, size_t index, const void *array, size_t n) {
648 list->collection.sorted = false;
649 return list->cl->insert_array(list, index, array, n);
650 }
651
652 size_t cxListInsertSortedArray(CxList *list, const void *array, size_t n) {
653 assert(cxCollectionSorted(list));
654 list->collection.sorted = true;
655 return list->cl->insert_sorted(list, array, n);
656 }
657
658 size_t cxListInsertUniqueArray(CxList *list, const void *array, size_t n) {
659 if (cxCollectionSorted(list)) {
660 list->collection.sorted = true;
661 return list->cl->insert_unique(list, array, n);
662 } else {
663 const char *source = array;
664 for (size_t i = 0 ; i < n; i++) {
665 // note: this also checks elements added in a previous iteration
666 const void *data = list->collection.store_pointer ?
667 *((const void**)source) : source;
668 if (!cxListContains(list, data)) {
669 if (cxListAdd(list, data)) {
670 return i; // LCOV_EXCL_LINE
671 }
672 }
673 source += list->collection.elem_size;
674 }
675 return n;
676 }
677 }
678
679 int cxListInsertAfter(CxIterator *iter, const void *elem) {
680 CxList* list = (CxList*)iter->src_handle;
681 list->collection.sorted = false;
682 return list->cl->insert_iter(iter, elem, 0);
683 }
684
685 int cxListInsertBefore(CxIterator *iter, const void *elem) {
686 CxList* list = (CxList*)iter->src_handle;
687 list->collection.sorted = false;
688 return list->cl->insert_iter(iter, elem, 1);
689 }
690
691 int cxListRemove(CxList *list, size_t index) {
692 return list->cl->remove(list, index, 1, NULL) == 0;
693 }
694
695 int cxListRemoveAndGet(CxList *list, size_t index, void *targetbuf) {
696 return list->cl->remove(list, index, 1, targetbuf) == 0;
697 }
698
699 int cxListRemoveAndGetFirst(CxList *list, void *targetbuf) {
700 return list->cl->remove(list, 0, 1, targetbuf) == 0;
701 }
702
703 int cxListRemoveAndGetLast(CxList *list, void *targetbuf) {
704 // note: index may wrap - member function will catch that
705 return list->cl->remove(list, list->collection.size - 1, 1, targetbuf) == 0;
706 }
707
708 size_t cxListRemoveArray(CxList *list, size_t index, size_t num) {
709 return list->cl->remove(list, index, num, NULL);
710 }
711
712 size_t cxListRemoveArrayAndGet(CxList *list, size_t index, size_t num, void *targetbuf) {
713 return list->cl->remove(list, index, num, targetbuf);
714 }
715
716 void cxListClear(CxList *list) {
717 list->cl->clear(list);
718 list->collection.sorted = true; // empty lists are always sorted
719 }
720
721 int cxListSwap(CxList *list, size_t i, size_t j) {
722 list->collection.sorted = false;
723 return list->cl->swap(list, i, j);
724 }
725
726 void *cxListAt(const CxList *list, size_t index) {
727 return list->cl->at(list, index);
728 }
729
730 void *cxListFirst(const CxList *list) {
731 return list->cl->at(list, 0);
732 }
733
734 void *cxListLast(const CxList *list) {
735 return list->cl->at(list, list->collection.size - 1);
736 }
737
738 int cxListSet(CxList *list, size_t index, const void *elem) {
505 if (index >= list->collection.size) { 739 if (index >= list->collection.size) {
506 return 1; 740 return 1;
507 } 741 }
508 742
509 if (list->collection.store_pointer) { 743 if (list->collection.store_pointer) {
515 memcpy(target, elem, list->collection.elem_size); 749 memcpy(target, elem, list->collection.elem_size);
516 } 750 }
517 751
518 return 0; 752 return 0;
519 } 753 }
754
755 CxIterator cxListIteratorAt(const CxList *list, size_t index) {
756 if (list == NULL) list = cxEmptyList;
757 return list->cl->iterator(list, index, false);
758 }
759
760 CxIterator cxListBackwardsIteratorAt(const CxList *list, size_t index) {
761 if (list == NULL) list = cxEmptyList;
762 return list->cl->iterator(list, index, true);
763 }
764
765 CxIterator cxListIterator(const CxList *list) {
766 if (list == NULL) list = cxEmptyList;
767 return list->cl->iterator(list, 0, false);
768 }
769
770 CxIterator cxListBackwardsIterator(const CxList *list) {
771 if (list == NULL) list = cxEmptyList;
772 return list->cl->iterator(list, list->collection.size - 1, true);
773 }
774
775 size_t cxListFind(const CxList *list, const void *elem) {
776 return list->cl->find_remove((CxList*)list, elem, false);
777 }
778
779 bool cxListContains(const CxList* list, const void* elem) {
780 return list->cl->find_remove((CxList*)list, elem, false) < list->collection.size;
781 }
782
783 bool cxListIndexValid(const CxList *list, size_t index) {
784 return index < list->collection.size;
785 }
786
787 size_t cxListFindRemove(CxList *list, const void *elem) {
788 return list->cl->find_remove(list, elem, true);
789 }
790
791 void cxListSort(CxList *list) {
792 if (list->collection.sorted) return;
793 list->cl->sort(list);
794 list->collection.sorted = true;
795 }
796
797 void cxListReverse(CxList *list) {
798 // still sorted, but not according to the cmp_func
799 list->collection.sorted = false;
800 list->cl->reverse(list);
801 }
802
803 void cxListFree(CxList *list) {
804 if (list == NULL) return;
805 list->cl->deallocate(list);
806 }
807
808 static void cx_list_pop_uninitialized_elements(CxList *list, size_t n) {
809 cx_destructor_func destr_bak = list->collection.simple_destructor;
810 cx_destructor_func2 destr2_bak = list->collection.advanced_destructor;
811 list->collection.simple_destructor = NULL;
812 list->collection.advanced_destructor = NULL;
813 if (n == 1) {
814 cxListRemove(list, list->collection.size - 1);
815 } else {
816 cxListRemoveArray(list,list->collection.size - n, n);
817 }
818 list->collection.simple_destructor = destr_bak;
819 list->collection.advanced_destructor = destr2_bak;
820 }
821
822 int cxListClone(CxList *dst, const CxList *src, cx_clone_func clone_func,
823 const CxAllocator *clone_allocator, void *data) {
824 if (clone_allocator == NULL) clone_allocator = cxDefaultAllocator;
825
826 // remember the original size
827 size_t orig_size = dst->collection.size;
828
829 // first, try to allocate the memory in the new list
830 CxIterator empl_iter = cxListEmplaceArray(dst, src->collection.size);
831
832 // get an iterator over the source elements
833 CxIterator src_iter = cxListIterator(src);
834
835 // now clone the elements
836 size_t cloned = empl_iter.elem_count;
837 for (size_t i = 0 ; i < empl_iter.elem_count; i++) {
838 void *src_elem = cxIteratorCurrent(src_iter);
839 void **dest_memory = cxIteratorCurrent(empl_iter);
840 void *target = cxCollectionStoresPointers(dst) ? NULL : dest_memory;
841 void *dest_ptr = clone_func(target, src_elem, clone_allocator, data);
842 if (dest_ptr == NULL) {
843 cloned = i;
844 break;
845 }
846 if (cxCollectionStoresPointers(dst)) {
847 *dest_memory = dest_ptr;
848 }
849 cxIteratorNext(src_iter);
850 cxIteratorNext(empl_iter);
851 }
852
853 // if we could not clone everything, free the allocated memory
854 // (disable the destructors!)
855 if (cloned < src->collection.size) {
856 cx_list_pop_uninitialized_elements(dst,
857 dst->collection.size - cloned - orig_size);
858 return 1;
859 }
860
861 return 0;
862 }
863
864 int cxListDifference(CxList *dst,
865 const CxList *minuend, const CxList *subtrahend,
866 cx_clone_func clone_func, const CxAllocator *clone_allocator, void *data) {
867 if (clone_allocator == NULL) clone_allocator = cxDefaultAllocator;
868
869 // optimize for sorted collections
870 if (cxCollectionSorted(minuend) && cxCollectionSorted(subtrahend)) {
871 bool dst_was_empty = cxCollectionSize(dst) == 0;
872
873 CxIterator min_iter = cxListIterator(minuend);
874 CxIterator sub_iter = cxListIterator(subtrahend);
875 while (cxIteratorValid(min_iter)) {
876 void *min_elem = cxIteratorCurrent(min_iter);
877 void *sub_elem;
878 int d;
879 if (cxIteratorValid(sub_iter)) {
880 sub_elem = cxIteratorCurrent(sub_iter);
881 cx_compare_func cmp = subtrahend->collection.cmpfunc;
882 d = cmp(sub_elem, min_elem);
883 } else {
884 // no more elements in the subtrahend,
885 // i.e., the min_elem is larger than any elem of the subtrahend
886 d = 1;
887 }
888 if (d == 0) {
889 // is contained, so skip it
890 cxIteratorNext(min_iter);
891 } else if (d < 0) {
892 // subtrahend is smaller than minuend,
893 // check the next element
894 cxIteratorNext(sub_iter);
895 } else {
896 // subtrahend is larger than the dst element,
897 // clone the minuend and advance
898 void **dst_mem = cxListEmplace(dst);
899 void *target = cxCollectionStoresPointers(dst) ? NULL : dst_mem;
900 void* dst_ptr = clone_func(target, min_elem, clone_allocator, data);
901 if (dst_ptr == NULL) {
902 cx_list_pop_uninitialized_elements(dst, 1);
903 return 1;
904 }
905 if (cxCollectionStoresPointers(dst)) {
906 *dst_mem = dst_ptr;
907 }
908 cxIteratorNext(min_iter);
909 }
910 }
911
912 // if dst was empty, it is now guaranteed to be sorted
913 dst->collection.sorted = dst_was_empty;
914 } else {
915 CxIterator min_iter = cxListIterator(minuend);
916 cx_foreach(void *, elem, min_iter) {
917 if (cxListContains(subtrahend, elem)) {
918 continue;
919 }
920 void **dst_mem = cxListEmplace(dst);
921 void *target = cxCollectionStoresPointers(dst) ? NULL : dst_mem;
922 void* dst_ptr = clone_func(target, elem, clone_allocator, data);
923 if (dst_ptr == NULL) {
924 cx_list_pop_uninitialized_elements(dst, 1);
925 return 1;
926 }
927 if (cxCollectionStoresPointers(dst)) {
928 *dst_mem = dst_ptr;
929 }
930 }
931 }
932
933 return 0;
934 }
935
936 int cxListIntersection(CxList *dst,
937 const CxList *src, const CxList *other,
938 cx_clone_func clone_func, const CxAllocator *clone_allocator, void *data) {
939 if (clone_allocator == NULL) clone_allocator = cxDefaultAllocator;
940
941 // optimize for sorted collections
942 if (cxCollectionSorted(src) && cxCollectionSorted(other)) {
943 bool dst_was_empty = cxCollectionSize(dst) == 0;
944
945 CxIterator src_iter = cxListIterator(src);
946 CxIterator other_iter = cxListIterator(other);
947 while (cxIteratorValid(src_iter) && cxIteratorValid(other_iter)) {
948 void *src_elem = cxIteratorCurrent(src_iter);
949 void *other_elem = cxIteratorCurrent(other_iter);
950 int d = src->collection.cmpfunc(src_elem, other_elem);
951 if (d == 0) {
952 // is contained, clone it
953 void **dst_mem = cxListEmplace(dst);
954 void *target = cxCollectionStoresPointers(dst) ? NULL : dst_mem;
955 void* dst_ptr = clone_func(target, src_elem, clone_allocator, data);
956 if (dst_ptr == NULL) {
957 cx_list_pop_uninitialized_elements(dst, 1);
958 return 1;
959 }
960 if (cxCollectionStoresPointers(dst)) {
961 *dst_mem = dst_ptr;
962 }
963 cxIteratorNext(src_iter);
964 } else if (d < 0) {
965 // the other element is larger, skip the source element
966 cxIteratorNext(src_iter);
967 } else {
968 // the source element is larger, try to find it in the other list
969 cxIteratorNext(other_iter);
970 }
971 }
972
973 // if dst was empty, it is now guaranteed to be sorted
974 dst->collection.sorted = dst_was_empty;
975 } else {
976 CxIterator src_iter = cxListIterator(src);
977 cx_foreach(void *, elem, src_iter) {
978 if (!cxListContains(other, elem)) {
979 continue;
980 }
981 void **dst_mem = cxListEmplace(dst);
982 void *target = cxCollectionStoresPointers(dst) ? NULL : dst_mem;
983 void* dst_ptr = clone_func(target, elem, clone_allocator, data);
984 if (dst_ptr == NULL) {
985 cx_list_pop_uninitialized_elements(dst, 1);
986 return 1;
987 }
988 if (cxCollectionStoresPointers(dst)) {
989 *dst_mem = dst_ptr;
990 }
991 }
992 }
993
994 return 0;
995 }
996
997 int cxListUnion(CxList *dst,
998 const CxList *src, const CxList *other,
999 cx_clone_func clone_func, const CxAllocator *clone_allocator, void *data) {
1000 if (clone_allocator == NULL) clone_allocator = cxDefaultAllocator;
1001
1002 // optimize for sorted collections
1003 if (cxCollectionSorted(src) && cxCollectionSorted(other)) {
1004 bool dst_was_empty = cxCollectionSize(dst) == 0;
1005
1006 CxIterator src_iter = cxListIterator(src);
1007 CxIterator other_iter = cxListIterator(other);
1008 while (cxIteratorValid(src_iter) || cxIteratorValid(other_iter)) {
1009 void *src_elem, *other_elem;
1010 int d;
1011 if (!cxIteratorValid(src_iter)) {
1012 other_elem = cxIteratorCurrent(other_iter);
1013 d = 1;
1014 } else if (!cxIteratorValid(other_iter)) {
1015 src_elem = cxIteratorCurrent(src_iter);
1016 d = -1;
1017 } else {
1018 src_elem = cxIteratorCurrent(src_iter);
1019 other_elem = cxIteratorCurrent(other_iter);
1020 d = src->collection.cmpfunc(src_elem, other_elem);
1021 }
1022 if (d <= 0) {
1023 // source element is smaller or equal, clone it
1024 void **dst_mem = cxListEmplace(dst);
1025 void *target = cxCollectionStoresPointers(dst) ? NULL : dst_mem;
1026 void* dst_ptr = clone_func(target, src_elem, clone_allocator, data);
1027 if (dst_ptr == NULL) {
1028 cx_list_pop_uninitialized_elements(dst, 1);
1029 return 1;
1030 }
1031 if (cxCollectionStoresPointers(dst)) {
1032 *dst_mem = dst_ptr;
1033 }
1034 cxIteratorNext(src_iter);
1035 // if the other element was equal, skip it
1036 if (d == 0) {
1037 cxIteratorNext(other_iter);
1038 }
1039 } else {
1040 // the other element is smaller, clone it
1041 void **dst_mem = cxListEmplace(dst);
1042 void *target = cxCollectionStoresPointers(dst) ? NULL : dst_mem;
1043 void* dst_ptr = clone_func(target, other_elem, clone_allocator, data);
1044 if (dst_ptr == NULL) {
1045 cx_list_pop_uninitialized_elements(dst, 1);
1046 return 1;
1047 }
1048 if (cxCollectionStoresPointers(dst)) {
1049 *dst_mem = dst_ptr;
1050 }
1051 cxIteratorNext(other_iter);
1052 }
1053 }
1054
1055 // if dst was empty, it is now guaranteed to be sorted
1056 dst->collection.sorted = dst_was_empty;
1057 } else {
1058 if (cxListClone(dst, src, clone_func, clone_allocator, data)) {
1059 return 1;
1060 }
1061 CxIterator other_iter = cxListIterator(other);
1062 cx_foreach(void *, elem, other_iter) {
1063 if (cxListContains(src, elem)) {
1064 continue;
1065 }
1066 void **dst_mem = cxListEmplace(dst);
1067 void *target = cxCollectionStoresPointers(dst) ? NULL : dst_mem;
1068 void* dst_ptr = clone_func(target, elem, clone_allocator, data);
1069 if (dst_ptr == NULL) {
1070 cx_list_pop_uninitialized_elements(dst, 1);
1071 return 1;
1072 }
1073 if (cxCollectionStoresPointers(dst)) {
1074 *dst_mem = dst_ptr;
1075 }
1076 }
1077 }
1078
1079 return 0;
1080 }

mercurial