| 991 } |
991 } |
| 992 } |
992 } |
| 993 |
993 |
| 994 return 0; |
994 return 0; |
| 995 } |
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 } |