ucx/list.c

changeset 943
9b5948aa5b90
parent 870
e167cf006213
equal deleted inserted replaced
942:488178e3e328 943:9b5948aa5b90
183 const struct cx_iterator_s *iter = it; 183 const struct cx_iterator_s *iter = it;
184 void **ptr = iter->base.current_impl(it); 184 void **ptr = iter->base.current_impl(it);
185 return ptr == NULL ? NULL : *ptr; 185 return ptr == NULL ? NULL : *ptr;
186 } 186 }
187 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
188 static struct cx_iterator_s cx_pl_iterator( 196 static struct cx_iterator_s cx_pl_iterator(
189 const struct cx_list_s *list, 197 const struct cx_list_s *list,
190 size_t index, 198 size_t index,
191 bool backwards 199 bool backwards
192 ) { 200 ) {
209 cx_pl_at, 217 cx_pl_at,
210 cx_pl_find_remove, 218 cx_pl_find_remove,
211 cx_pl_sort, 219 cx_pl_sort,
212 cx_pl_compare, 220 cx_pl_compare,
213 cx_pl_reverse, 221 cx_pl_reverse,
222 cx_pl_change_capacity,
214 cx_pl_iterator, 223 cx_pl_iterator,
215 }; 224 };
216 // </editor-fold> 225 // </editor-fold>
217 226
218 // <editor-fold desc="empty list implementation"> 227 // <editor-fold desc="empty list implementation">
265 cx_emptyl_at, 274 cx_emptyl_at,
266 cx_emptyl_find_remove, 275 cx_emptyl_find_remove,
267 cx_emptyl_noop, 276 cx_emptyl_noop,
268 NULL, 277 NULL,
269 cx_emptyl_noop, 278 cx_emptyl_noop,
279 NULL,
270 cx_emptyl_iterator, 280 cx_emptyl_iterator,
271 }; 281 };
272 282
273 CxList cx_empty_list = { 283 CxList cx_empty_list = {
274 { 284 {
802 812
803 void cxListFree(CxList *list) { 813 void cxListFree(CxList *list) {
804 if (list == NULL) return; 814 if (list == NULL) return;
805 list->cl->deallocate(list); 815 list->cl->deallocate(list);
806 } 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 = NULL, *other_elem = NULL;
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