| 564 // lists are compatible |
572 // lists are compatible |
| 565 return list->cl->compare(list, other); |
573 return list->cl->compare(list, other); |
| 566 } |
574 } |
| 567 } |
575 } |
| 568 |
576 |
| 569 CxIterator cxListMutIteratorAt( |
577 size_t cxListSize(const CxList *list) { |
| 570 CxList *list, |
578 return list->collection.size; |
| 571 size_t index |
579 } |
| 572 ) { |
580 |
| 573 if (list == NULL) list = cxEmptyList; |
581 int cxListAdd(CxList *list, const void *elem) { |
| 574 CxIterator it = list->cl->iterator(list, index, false); |
582 list->collection.sorted = false; |
| 575 it.base.mutating = true; |
583 return list->cl->insert_element(list, list->collection.size, elem) == NULL; |
| 576 return it; |
584 } |
| 577 } |
585 |
| 578 |
586 size_t cxListAddArray(CxList *list, const void *array, size_t n) { |
| 579 CxIterator cxListMutBackwardsIteratorAt( |
587 list->collection.sorted = false; |
| 580 CxList *list, |
588 return list->cl->insert_array(list, list->collection.size, array, n); |
| 581 size_t index |
589 } |
| 582 ) { |
590 |
| 583 if (list == NULL) list = cxEmptyList; |
591 int cxListInsert(CxList *list, size_t index, const void *elem) { |
| 584 CxIterator it = list->cl->iterator(list, index, true); |
592 list->collection.sorted = false; |
| 585 it.base.mutating = true; |
593 return list->cl->insert_element(list, index, elem) == NULL; |
| 586 return it; |
594 } |
| 587 } |
595 |
| 588 |
596 void *cxListEmplaceAt(CxList *list, size_t index) { |
| 589 void cxListFree(CxList *list) { |
597 list->collection.sorted = false; |
| 590 if (list == NULL) return; |
598 return list->cl->insert_element(list, index, NULL); |
| 591 list->cl->deallocate(list); |
599 } |
| 592 } |
600 |
| 593 |
601 void *cxListEmplace(CxList *list) { |
| 594 int cxListSet( |
602 list->collection.sorted = false; |
| 595 CxList *list, |
603 return list->cl->insert_element(list, list->collection.size, NULL); |
| 596 size_t index, |
604 } |
| 597 const void *elem |
605 |
| 598 ) { |
606 static bool cx_list_emplace_iterator_valid(const void *it) { |
| |
607 const CxIterator *iter = it; |
| |
608 return iter->index < iter->elem_count; |
| |
609 } |
| |
610 |
| |
611 CxIterator cxListEmplaceArrayAt(CxList *list, size_t index, size_t n) { |
| |
612 list->collection.sorted = false; |
| |
613 size_t c = list->cl->insert_array(list, index, NULL, n); |
| |
614 CxIterator iter = list->cl->iterator(list, index, false); |
| |
615 // tweak the fields of this iterator |
| |
616 iter.elem_count = c; |
| |
617 iter.index = 0; |
| |
618 // replace the valid function to abort iteration when c is reached |
| |
619 iter.base.valid = cx_list_emplace_iterator_valid; |
| |
620 // if we are storing pointers, we want to return the pure pointers. |
| |
621 // therefore, we must unwrap the "current" method |
| |
622 if (list->collection.store_pointer) { |
| |
623 iter.base.current = iter.base.current_impl; |
| |
624 } |
| |
625 return iter; |
| |
626 } |
| |
627 |
| |
628 CxIterator cxListEmplaceArray(CxList *list, size_t n) { |
| |
629 return cxListEmplaceArrayAt(list, list->collection.size, n); |
| |
630 } |
| |
631 |
| |
632 int cxListInsertSorted(CxList *list, const void *elem) { |
| |
633 assert(cxCollectionSorted(list)); |
| |
634 list->collection.sorted = true; |
| |
635 const void *data = list->collection.store_pointer ? &elem : elem; |
| |
636 return list->cl->insert_sorted(list, data, 1) == 0; |
| |
637 } |
| |
638 |
| |
639 int cxListInsertUnique(CxList *list, const void *elem) { |
| |
640 if (cxCollectionSorted(list)) { |
| |
641 list->collection.sorted = true; |
| |
642 const void *data = list->collection.store_pointer ? &elem : elem; |
| |
643 return list->cl->insert_unique(list, data, 1) == 0; |
| |
644 } else { |
| |
645 if (cxListContains(list, elem)) { |
| |
646 return 0; |
| |
647 } else { |
| |
648 return cxListAdd(list, elem); |
| |
649 } |
| |
650 } |
| |
651 } |
| |
652 |
| |
653 size_t cxListInsertArray(CxList *list, size_t index, const void *array, size_t n) { |
| |
654 list->collection.sorted = false; |
| |
655 return list->cl->insert_array(list, index, array, n); |
| |
656 } |
| |
657 |
| |
658 size_t cxListInsertSortedArray(CxList *list, const void *array, size_t n) { |
| |
659 assert(cxCollectionSorted(list)); |
| |
660 list->collection.sorted = true; |
| |
661 return list->cl->insert_sorted(list, array, n); |
| |
662 } |
| |
663 |
| |
664 size_t cxListInsertUniqueArray(CxList *list, const void *array, size_t n) { |
| |
665 if (cxCollectionSorted(list)) { |
| |
666 list->collection.sorted = true; |
| |
667 return list->cl->insert_unique(list, array, n); |
| |
668 } else { |
| |
669 const char *source = array; |
| |
670 for (size_t i = 0 ; i < n; i++) { |
| |
671 // note: this also checks elements added in a previous iteration |
| |
672 const void *data = list->collection.store_pointer ? |
| |
673 *((const void**)source) : source; |
| |
674 if (!cxListContains(list, data)) { |
| |
675 if (cxListAdd(list, data)) { |
| |
676 return i; // LCOV_EXCL_LINE |
| |
677 } |
| |
678 } |
| |
679 source += list->collection.elem_size; |
| |
680 } |
| |
681 return n; |
| |
682 } |
| |
683 } |
| |
684 |
| |
685 int cxListInsertAfter(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, 0); |
| |
689 } |
| |
690 |
| |
691 int cxListInsertBefore(CxIterator *iter, const void *elem) { |
| |
692 CxList* list = (CxList*)iter->src_handle; |
| |
693 list->collection.sorted = false; |
| |
694 return list->cl->insert_iter(iter, elem, 1); |
| |
695 } |
| |
696 |
| |
697 int cxListRemove(CxList *list, size_t index) { |
| |
698 return list->cl->remove(list, index, 1, NULL) == 0; |
| |
699 } |
| |
700 |
| |
701 int cxListRemoveAndGet(CxList *list, size_t index, void *targetbuf) { |
| |
702 return list->cl->remove(list, index, 1, targetbuf) == 0; |
| |
703 } |
| |
704 |
| |
705 int cxListRemoveAndGetFirst(CxList *list, void *targetbuf) { |
| |
706 return list->cl->remove(list, 0, 1, targetbuf) == 0; |
| |
707 } |
| |
708 |
| |
709 int cxListRemoveAndGetLast(CxList *list, void *targetbuf) { |
| |
710 // note: index may wrap - member function will catch that |
| |
711 return list->cl->remove(list, list->collection.size - 1, 1, targetbuf) == 0; |
| |
712 } |
| |
713 |
| |
714 size_t cxListRemoveArray(CxList *list, size_t index, size_t num) { |
| |
715 return list->cl->remove(list, index, num, NULL); |
| |
716 } |
| |
717 |
| |
718 size_t cxListRemoveArrayAndGet(CxList *list, size_t index, size_t num, void *targetbuf) { |
| |
719 return list->cl->remove(list, index, num, targetbuf); |
| |
720 } |
| |
721 |
| |
722 void cxListClear(CxList *list) { |
| |
723 list->cl->clear(list); |
| |
724 list->collection.sorted = true; // empty lists are always sorted |
| |
725 } |
| |
726 |
| |
727 int cxListSwap(CxList *list, size_t i, size_t j) { |
| |
728 list->collection.sorted = false; |
| |
729 return list->cl->swap(list, i, j); |
| |
730 } |
| |
731 |
| |
732 void *cxListAt(const CxList *list, size_t index) { |
| |
733 return list->cl->at(list, index); |
| |
734 } |
| |
735 |
| |
736 void *cxListFirst(const CxList *list) { |
| |
737 return list->cl->at(list, 0); |
| |
738 } |
| |
739 |
| |
740 void *cxListLast(const CxList *list) { |
| |
741 return list->cl->at(list, list->collection.size - 1); |
| |
742 } |
| |
743 |
| |
744 int cxListSet(CxList *list, size_t index, const void *elem) { |
| 599 if (index >= list->collection.size) { |
745 if (index >= list->collection.size) { |
| 600 return 1; |
746 return 1; |
| 601 } |
747 } |
| 602 |
748 |
| 603 if (list->collection.store_pointer) { |
749 if (list->collection.store_pointer) { |
| 609 memcpy(target, elem, list->collection.elem_size); |
755 memcpy(target, elem, list->collection.elem_size); |
| 610 } |
756 } |
| 611 |
757 |
| 612 return 0; |
758 return 0; |
| 613 } |
759 } |
| |
760 |
| |
761 CxIterator cxListIteratorAt(const CxList *list, size_t index) { |
| |
762 if (list == NULL) list = cxEmptyList; |
| |
763 return list->cl->iterator(list, index, false); |
| |
764 } |
| |
765 |
| |
766 CxIterator cxListBackwardsIteratorAt(const CxList *list, size_t index) { |
| |
767 if (list == NULL) list = cxEmptyList; |
| |
768 return list->cl->iterator(list, index, true); |
| |
769 } |
| |
770 |
| |
771 CxIterator cxListIterator(const CxList *list) { |
| |
772 if (list == NULL) list = cxEmptyList; |
| |
773 return list->cl->iterator(list, 0, false); |
| |
774 } |
| |
775 |
| |
776 CxIterator cxListBackwardsIterator(const CxList *list) { |
| |
777 if (list == NULL) list = cxEmptyList; |
| |
778 return list->cl->iterator(list, list->collection.size - 1, true); |
| |
779 } |
| |
780 |
| |
781 size_t cxListFind(const CxList *list, const void *elem) { |
| |
782 return list->cl->find_remove((CxList*)list, elem, false); |
| |
783 } |
| |
784 |
| |
785 bool cxListContains(const CxList* list, const void* elem) { |
| |
786 return list->cl->find_remove((CxList*)list, elem, false) < list->collection.size; |
| |
787 } |
| |
788 |
| |
789 bool cxListIndexValid(const CxList *list, size_t index) { |
| |
790 return index < list->collection.size; |
| |
791 } |
| |
792 |
| |
793 size_t cxListFindRemove(CxList *list, const void *elem) { |
| |
794 return list->cl->find_remove(list, elem, true); |
| |
795 } |
| |
796 |
| |
797 void cxListSort(CxList *list) { |
| |
798 if (list->collection.sorted) return; |
| |
799 list->cl->sort(list); |
| |
800 list->collection.sorted = true; |
| |
801 } |
| |
802 |
| |
803 void cxListReverse(CxList *list) { |
| |
804 // still sorted, but not according to the cmp_func |
| |
805 list->collection.sorted = false; |
| |
806 list->cl->reverse(list); |
| |
807 } |
| |
808 |
| |
809 void cxListFree(CxList *list) { |
| |
810 if (list == NULL) return; |
| |
811 list->cl->deallocate(list); |
| |
812 } |
| |
813 |
| |
814 static void cx_list_pop_uninitialized_elements(CxList *list, size_t n) { |
| |
815 cx_destructor_func destr_bak = list->collection.simple_destructor; |
| |
816 cx_destructor_func2 destr2_bak = list->collection.advanced_destructor; |
| |
817 list->collection.simple_destructor = NULL; |
| |
818 list->collection.advanced_destructor = NULL; |
| |
819 if (n == 1) { |
| |
820 cxListRemove(list, list->collection.size - 1); |
| |
821 } else { |
| |
822 cxListRemoveArray(list,list->collection.size - n, n); |
| |
823 } |
| |
824 list->collection.simple_destructor = destr_bak; |
| |
825 list->collection.advanced_destructor = destr2_bak; |
| |
826 } |
| |
827 |
| |
828 static void* cx_list_simple_clone_func(void *dst, const void *src, const CxAllocator *al, void *data) { |
| |
829 size_t elem_size = *(size_t*)data; |
| |
830 if (dst == NULL) dst = cxMalloc(al, elem_size); |
| |
831 if (dst != NULL) memcpy(dst, src, elem_size); |
| |
832 return dst; |
| |
833 } |
| |
834 |
| |
835 #define use_simple_clone_func(list) cx_list_simple_clone_func, NULL, (void*)&((list)->collection.elem_size) |
| |
836 |
| |
837 int cxListClone(CxList *dst, const CxList *src, cx_clone_func clone_func, |
| |
838 const CxAllocator *clone_allocator, void *data) { |
| |
839 if (clone_allocator == NULL) clone_allocator = cxDefaultAllocator; |
| |
840 |
| |
841 // remember the original size |
| |
842 size_t orig_size = dst->collection.size; |
| |
843 |
| |
844 // first, try to allocate the memory in the new list |
| |
845 CxIterator empl_iter = cxListEmplaceArray(dst, src->collection.size); |
| |
846 |
| |
847 // get an iterator over the source elements |
| |
848 CxIterator src_iter = cxListIterator(src); |
| |
849 |
| |
850 // now clone the elements |
| |
851 size_t cloned = empl_iter.elem_count; |
| |
852 for (size_t i = 0 ; i < empl_iter.elem_count; i++) { |
| |
853 void *src_elem = cxIteratorCurrent(src_iter); |
| |
854 void **dest_memory = cxIteratorCurrent(empl_iter); |
| |
855 void *target = cxCollectionStoresPointers(dst) ? NULL : dest_memory; |
| |
856 void *dest_ptr = clone_func(target, src_elem, clone_allocator, data); |
| |
857 if (dest_ptr == NULL) { |
| |
858 cloned = i; |
| |
859 break; |
| |
860 } |
| |
861 if (cxCollectionStoresPointers(dst)) { |
| |
862 *dest_memory = dest_ptr; |
| |
863 } |
| |
864 cxIteratorNext(src_iter); |
| |
865 cxIteratorNext(empl_iter); |
| |
866 } |
| |
867 |
| |
868 // if we could not clone everything, free the allocated memory |
| |
869 // (disable the destructors!) |
| |
870 if (cloned < src->collection.size) { |
| |
871 cx_list_pop_uninitialized_elements(dst, |
| |
872 dst->collection.size - cloned - orig_size); |
| |
873 return 1; |
| |
874 } |
| |
875 |
| |
876 // set the sorted flag when we know it's sorted |
| |
877 if (orig_size == 0 && src->collection.sorted) { |
| |
878 dst->collection.sorted = true; |
| |
879 } |
| |
880 |
| |
881 return 0; |
| |
882 } |
| |
883 |
| |
884 int cxListDifference(CxList *dst, |
| |
885 const CxList *minuend, const CxList *subtrahend, |
| |
886 cx_clone_func clone_func, const CxAllocator *clone_allocator, void *data) { |
| |
887 if (clone_allocator == NULL) clone_allocator = cxDefaultAllocator; |
| |
888 |
| |
889 // optimize for sorted collections |
| |
890 if (cxCollectionSorted(minuend) && cxCollectionSorted(subtrahend)) { |
| |
891 bool dst_was_empty = cxCollectionSize(dst) == 0; |
| |
892 |
| |
893 CxIterator min_iter = cxListIterator(minuend); |
| |
894 CxIterator sub_iter = cxListIterator(subtrahend); |
| |
895 while (cxIteratorValid(min_iter)) { |
| |
896 void *min_elem = cxIteratorCurrent(min_iter); |
| |
897 void *sub_elem; |
| |
898 int d; |
| |
899 if (cxIteratorValid(sub_iter)) { |
| |
900 sub_elem = cxIteratorCurrent(sub_iter); |
| |
901 cx_compare_func cmp = subtrahend->collection.cmpfunc; |
| |
902 d = cmp(sub_elem, min_elem); |
| |
903 } else { |
| |
904 // no more elements in the subtrahend, |
| |
905 // i.e., the min_elem is larger than any elem of the subtrahend |
| |
906 d = 1; |
| |
907 } |
| |
908 if (d == 0) { |
| |
909 // is contained, so skip it |
| |
910 cxIteratorNext(min_iter); |
| |
911 } else if (d < 0) { |
| |
912 // subtrahend is smaller than minuend, |
| |
913 // check the next element |
| |
914 cxIteratorNext(sub_iter); |
| |
915 } else { |
| |
916 // subtrahend is larger than the dst element, |
| |
917 // clone the minuend and advance |
| |
918 void **dst_mem = cxListEmplace(dst); |
| |
919 void *target = cxCollectionStoresPointers(dst) ? NULL : dst_mem; |
| |
920 void* dst_ptr = clone_func(target, min_elem, clone_allocator, data); |
| |
921 if (dst_ptr == NULL) { |
| |
922 cx_list_pop_uninitialized_elements(dst, 1); |
| |
923 return 1; |
| |
924 } |
| |
925 if (cxCollectionStoresPointers(dst)) { |
| |
926 *dst_mem = dst_ptr; |
| |
927 } |
| |
928 cxIteratorNext(min_iter); |
| |
929 } |
| |
930 } |
| |
931 |
| |
932 // if dst was empty, it is now guaranteed to be sorted |
| |
933 dst->collection.sorted = dst_was_empty; |
| |
934 } else { |
| |
935 CxIterator min_iter = cxListIterator(minuend); |
| |
936 cx_foreach(void *, elem, min_iter) { |
| |
937 if (cxListContains(subtrahend, elem)) { |
| |
938 continue; |
| |
939 } |
| |
940 void **dst_mem = cxListEmplace(dst); |
| |
941 void *target = cxCollectionStoresPointers(dst) ? NULL : dst_mem; |
| |
942 void* dst_ptr = clone_func(target, elem, clone_allocator, data); |
| |
943 if (dst_ptr == NULL) { |
| |
944 cx_list_pop_uninitialized_elements(dst, 1); |
| |
945 return 1; |
| |
946 } |
| |
947 if (cxCollectionStoresPointers(dst)) { |
| |
948 *dst_mem = dst_ptr; |
| |
949 } |
| |
950 } |
| |
951 } |
| |
952 |
| |
953 return 0; |
| |
954 } |
| |
955 |
| |
956 int cxListIntersection(CxList *dst, |
| |
957 const CxList *src, const CxList *other, |
| |
958 cx_clone_func clone_func, const CxAllocator *clone_allocator, void *data) { |
| |
959 if (clone_allocator == NULL) clone_allocator = cxDefaultAllocator; |
| |
960 |
| |
961 // optimize for sorted collections |
| |
962 if (cxCollectionSorted(src) && cxCollectionSorted(other)) { |
| |
963 bool dst_was_empty = cxCollectionSize(dst) == 0; |
| |
964 |
| |
965 CxIterator src_iter = cxListIterator(src); |
| |
966 CxIterator other_iter = cxListIterator(other); |
| |
967 while (cxIteratorValid(src_iter) && cxIteratorValid(other_iter)) { |
| |
968 void *src_elem = cxIteratorCurrent(src_iter); |
| |
969 void *other_elem = cxIteratorCurrent(other_iter); |
| |
970 int d = src->collection.cmpfunc(src_elem, other_elem); |
| |
971 if (d == 0) { |
| |
972 // is contained, clone it |
| |
973 void **dst_mem = cxListEmplace(dst); |
| |
974 void *target = cxCollectionStoresPointers(dst) ? NULL : dst_mem; |
| |
975 void* dst_ptr = clone_func(target, src_elem, clone_allocator, data); |
| |
976 if (dst_ptr == NULL) { |
| |
977 cx_list_pop_uninitialized_elements(dst, 1); |
| |
978 return 1; |
| |
979 } |
| |
980 if (cxCollectionStoresPointers(dst)) { |
| |
981 *dst_mem = dst_ptr; |
| |
982 } |
| |
983 cxIteratorNext(src_iter); |
| |
984 } else if (d < 0) { |
| |
985 // the other element is larger, skip the source element |
| |
986 cxIteratorNext(src_iter); |
| |
987 } else { |
| |
988 // the source element is larger, try to find it in the other list |
| |
989 cxIteratorNext(other_iter); |
| |
990 } |
| |
991 } |
| |
992 |
| |
993 // if dst was empty, it is now guaranteed to be sorted |
| |
994 dst->collection.sorted = dst_was_empty; |
| |
995 } else { |
| |
996 CxIterator src_iter = cxListIterator(src); |
| |
997 cx_foreach(void *, elem, src_iter) { |
| |
998 if (!cxListContains(other, elem)) { |
| |
999 continue; |
| |
1000 } |
| |
1001 void **dst_mem = cxListEmplace(dst); |
| |
1002 void *target = cxCollectionStoresPointers(dst) ? NULL : dst_mem; |
| |
1003 void* dst_ptr = clone_func(target, elem, clone_allocator, data); |
| |
1004 if (dst_ptr == NULL) { |
| |
1005 cx_list_pop_uninitialized_elements(dst, 1); |
| |
1006 return 1; |
| |
1007 } |
| |
1008 if (cxCollectionStoresPointers(dst)) { |
| |
1009 *dst_mem = dst_ptr; |
| |
1010 } |
| |
1011 } |
| |
1012 } |
| |
1013 |
| |
1014 return 0; |
| |
1015 } |
| |
1016 |
| |
1017 int cxListUnion(CxList *dst, |
| |
1018 const CxList *src, const CxList *other, |
| |
1019 cx_clone_func clone_func, const CxAllocator *clone_allocator, void *data) { |
| |
1020 if (clone_allocator == NULL) clone_allocator = cxDefaultAllocator; |
| |
1021 |
| |
1022 // optimize for sorted collections |
| |
1023 if (cxCollectionSorted(src) && cxCollectionSorted(other)) { |
| |
1024 bool dst_was_empty = cxCollectionSize(dst) == 0; |
| |
1025 |
| |
1026 CxIterator src_iter = cxListIterator(src); |
| |
1027 CxIterator other_iter = cxListIterator(other); |
| |
1028 while (cxIteratorValid(src_iter) || cxIteratorValid(other_iter)) { |
| |
1029 void *src_elem, *other_elem; |
| |
1030 int d; |
| |
1031 if (!cxIteratorValid(src_iter)) { |
| |
1032 other_elem = cxIteratorCurrent(other_iter); |
| |
1033 d = 1; |
| |
1034 } else if (!cxIteratorValid(other_iter)) { |
| |
1035 src_elem = cxIteratorCurrent(src_iter); |
| |
1036 d = -1; |
| |
1037 } else { |
| |
1038 src_elem = cxIteratorCurrent(src_iter); |
| |
1039 other_elem = cxIteratorCurrent(other_iter); |
| |
1040 d = src->collection.cmpfunc(src_elem, other_elem); |
| |
1041 } |
| |
1042 void *clone_from; |
| |
1043 if (d < 0) { |
| |
1044 // source element is smaller clone it |
| |
1045 clone_from = src_elem; |
| |
1046 cxIteratorNext(src_iter); |
| |
1047 } else if (d == 0) { |
| |
1048 // both elements are equal, clone from the source, skip other |
| |
1049 clone_from = src_elem; |
| |
1050 cxIteratorNext(src_iter); |
| |
1051 cxIteratorNext(other_iter); |
| |
1052 } else { |
| |
1053 // the other element is smaller, clone it |
| |
1054 clone_from = other_elem; |
| |
1055 cxIteratorNext(other_iter); |
| |
1056 } |
| |
1057 void **dst_mem = cxListEmplace(dst); |
| |
1058 void *target = cxCollectionStoresPointers(dst) ? NULL : dst_mem; |
| |
1059 void* dst_ptr = clone_func(target, clone_from, clone_allocator, data); |
| |
1060 if (dst_ptr == NULL) { |
| |
1061 cx_list_pop_uninitialized_elements(dst, 1); |
| |
1062 return 1; |
| |
1063 } |
| |
1064 if (cxCollectionStoresPointers(dst)) { |
| |
1065 *dst_mem = dst_ptr; |
| |
1066 } |
| |
1067 } |
| |
1068 |
| |
1069 // if dst was empty, it is now guaranteed to be sorted |
| |
1070 dst->collection.sorted = dst_was_empty; |
| |
1071 } else { |
| |
1072 if (cxListClone(dst, src, clone_func, clone_allocator, data)) { |
| |
1073 return 1; |
| |
1074 } |
| |
1075 CxIterator other_iter = cxListIterator(other); |
| |
1076 cx_foreach(void *, elem, other_iter) { |
| |
1077 if (cxListContains(src, elem)) { |
| |
1078 continue; |
| |
1079 } |
| |
1080 void **dst_mem = cxListEmplace(dst); |
| |
1081 void *target = cxCollectionStoresPointers(dst) ? NULL : dst_mem; |
| |
1082 void* dst_ptr = clone_func(target, elem, clone_allocator, data); |
| |
1083 if (dst_ptr == NULL) { |
| |
1084 cx_list_pop_uninitialized_elements(dst, 1); |
| |
1085 return 1; |
| |
1086 } |
| |
1087 if (cxCollectionStoresPointers(dst)) { |
| |
1088 *dst_mem = dst_ptr; |
| |
1089 } |
| |
1090 } |
| |
1091 } |
| |
1092 |
| |
1093 return 0; |
| |
1094 } |
| |
1095 |
| |
1096 int cxListCloneSimple(CxList *dst, const CxList *src) { |
| |
1097 return cxListClone(dst, src, use_simple_clone_func(src)); |
| |
1098 } |
| |
1099 |
| |
1100 int cxListDifferenceSimple(CxList *dst, const CxList *minuend, const CxList *subtrahend) { |
| |
1101 return cxListDifference(dst, minuend, subtrahend, use_simple_clone_func(minuend)); |
| |
1102 } |
| |
1103 |
| |
1104 int cxListIntersectionSimple(CxList *dst, const CxList *src, const CxList *other) { |
| |
1105 return cxListIntersection(dst, src, other, use_simple_clone_func(src)); |
| |
1106 } |
| |
1107 |
| |
1108 int cxListUnionSimple(CxList *dst, const CxList *src, const CxList *other) { |
| |
1109 return cxListUnion(dst, src, other, use_simple_clone_func(src)); |
| |
1110 } |
| |
1111 |
| |
1112 int cxListReserve(CxList *list, size_t capacity) { |
| |
1113 if (list->cl->change_capacity == NULL) { |
| |
1114 return 0; |
| |
1115 } |
| |
1116 if (capacity <= cxCollectionSize(list)) { |
| |
1117 return 0; |
| |
1118 } |
| |
1119 return list->cl->change_capacity(list, capacity); |
| |
1120 } |
| |
1121 |
| |
1122 int cxListShrink(CxList *list) { |
| |
1123 if (list->cl->change_capacity == NULL) { |
| |
1124 return 0; |
| |
1125 } |
| |
1126 return list->cl->change_capacity(list, cxCollectionSize(list)); |
| |
1127 } |