# HG changeset patch # User Mike Becker # Date 1762701127 -3600 # Node ID 83146195a1db253b05fdca70725cc5a75641bf01 # Parent ac1baaed2fd7fa00001a945bd23fdc87cff7e1f8 add tests for simple clone functions resolves #757 diff -r ac1baaed2fd7 -r 83146195a1db src/list.c --- a/src/list.c Sat Nov 08 23:45:19 2025 +0100 +++ b/src/list.c Sun Nov 09 16:12:07 2025 +0100 @@ -867,6 +867,11 @@ return 1; } + // set the sorted flag when we know it's sorted + if (orig_size == 0 && src->collection.sorted) { + dst->collection.sorted = true; + } + return 0; } @@ -1028,37 +1033,31 @@ other_elem = cxIteratorCurrent(other_iter); d = src->collection.cmpfunc(src_elem, other_elem); } - if (d <= 0) { - // source element is smaller or equal, clone it - void **dst_mem = cxListEmplace(dst); - void *target = cxCollectionStoresPointers(dst) ? NULL : dst_mem; - void* dst_ptr = clone_func(target, src_elem, clone_allocator, data); - if (dst_ptr == NULL) { - cx_list_pop_uninitialized_elements(dst, 1); - return 1; - } - if (cxCollectionStoresPointers(dst)) { - *dst_mem = dst_ptr; - } + void *clone_from; + if (d < 0) { + // source element is smaller clone it + clone_from = src_elem; cxIteratorNext(src_iter); - // if the other element was equal, skip it - if (d == 0) { - cxIteratorNext(other_iter); - } + } else if (d == 0) { + // both elements are equal, clone from the source, skip other + clone_from = src_elem; + cxIteratorNext(src_iter); + cxIteratorNext(other_iter); } else { // the other element is smaller, clone it - void **dst_mem = cxListEmplace(dst); - void *target = cxCollectionStoresPointers(dst) ? NULL : dst_mem; - void* dst_ptr = clone_func(target, other_elem, clone_allocator, data); - if (dst_ptr == NULL) { - cx_list_pop_uninitialized_elements(dst, 1); - return 1; - } - if (cxCollectionStoresPointers(dst)) { - *dst_mem = dst_ptr; - } + clone_from = other_elem; cxIteratorNext(other_iter); } + void **dst_mem = cxListEmplace(dst); + void *target = cxCollectionStoresPointers(dst) ? NULL : dst_mem; + void* dst_ptr = clone_func(target, clone_from, clone_allocator, data); + if (dst_ptr == NULL) { + cx_list_pop_uninitialized_elements(dst, 1); + return 1; + } + if (cxCollectionStoresPointers(dst)) { + *dst_mem = dst_ptr; + } } // if dst was empty, it is now guaranteed to be sorted diff -r ac1baaed2fd7 -r 83146195a1db tests/test_hash_map.c --- a/tests/test_hash_map.c Sat Nov 08 23:45:19 2025 +0100 +++ b/tests/test_hash_map.c Sun Nov 09 16:12:07 2025 +0100 @@ -1155,6 +1155,109 @@ cxMapFree(s2); } +CX_TEST(test_hash_map_simple_clones) { + CxMap *a = cxHashMapCreateSimple(sizeof(int)); + cxMapPut(a, "k1", "v1"); + cxMapPut(a, "k2", "v2"); + cxMapPut(a, "k3", "v3"); + cxMapPut(a, "k4", "v4"); + + CxMap *b = cxHashMapCreateSimple(sizeof(int)); + cxMapPut(b, "k0", "v0"); + cxMapPut(b, "k2", "v2"); + cxMapPut(b, "k5", "v5"); + + CxMap *c = cxHashMapCreateSimple(sizeof(int)); + cxMapPut(c, "k3", "v3"); + cxMapPut(c, "k4", "v4"); + cxMapPut(c, "k5", "v5"); + + + CxHashKey k; + CxList *kl1 = cxArrayListCreateSimple(sizeof(CxHashKey), 4); + cxCollectionCompareFunc(kl1, cx_hash_key_cmp); + k = CX_HASH_KEY("k0"); + cxListAdd(kl1, &k); + k = CX_HASH_KEY("k2"); + cxListAdd(kl1, &k); + k = CX_HASH_KEY("k5"); + cxListAdd(kl1, &k); + + CxList *kl2 = cxArrayListCreateSimple(sizeof(CxHashKey), 4); + cxCollectionCompareFunc(kl2, cx_hash_key_cmp); + k = CX_HASH_KEY("k3"); + cxListAdd(kl2, &k); + k = CX_HASH_KEY("k4"); + cxListAdd(kl2, &k); + k = CX_HASH_KEY("k5"); + cxListAdd(kl2, &k); + + CxMap *d1 = cxHashMapCreateSimple(CX_STORE_POINTERS); + cxDefineAdvancedDestructor(d1, cxFree, (void*)cxDefaultAllocator); + CxMap *d2 = cxHashMapCreateSimple(CX_STORE_POINTERS); + cxDefineAdvancedDestructor(d2, cxFree, (void*)cxDefaultAllocator); + + CX_TEST_DO { + CX_TEST_ASSERT(0 == cxMapCloneSimple(d1, a)); + CX_TEST_ASSERT(!cxMapContains(d1, "k0")); + CX_TEST_ASSERT(cxMapContains(d1, "k1")); + CX_TEST_ASSERT(cxMapContains(d1, "k2")); + CX_TEST_ASSERT(cxMapContains(d1, "k3")); + CX_TEST_ASSERT(cxMapContains(d1, "k4")); + CX_TEST_ASSERT(!cxMapContains(d1, "k5")); + + CX_TEST_ASSERT(0 == cxMapListDifferenceSimple(d2, d1, kl1)); + CX_TEST_ASSERT(!cxMapContains(d2, "k0")); + CX_TEST_ASSERT(cxMapContains(d2, "k1")); + CX_TEST_ASSERT(!cxMapContains(d2, "k2")); + CX_TEST_ASSERT(cxMapContains(d2, "k3")); + CX_TEST_ASSERT(cxMapContains(d2, "k4")); + CX_TEST_ASSERT(!cxMapContains(d2, "k5")); + + cxMapClear(d1); + CX_TEST_ASSERT(0 == cxMapListIntersectionSimple(d1, d2, kl2)); + CX_TEST_ASSERT(!cxMapContains(d1, "k0")); + CX_TEST_ASSERT(!cxMapContains(d1, "k1")); + CX_TEST_ASSERT(!cxMapContains(d1, "k2")); + CX_TEST_ASSERT(cxMapContains(d1, "k3")); + CX_TEST_ASSERT(cxMapContains(d1, "k4")); + + CX_TEST_ASSERT(0 == cxMapUnionSimple(d1, b)); + CX_TEST_ASSERT(cxMapContains(d1, "k0")); + CX_TEST_ASSERT(!cxMapContains(d1, "k1")); + CX_TEST_ASSERT(cxMapContains(d1, "k2")); + CX_TEST_ASSERT(cxMapContains(d1, "k3")); + CX_TEST_ASSERT(cxMapContains(d1, "k4")); + CX_TEST_ASSERT(cxMapContains(d1, "k5")); + + cxMapClear(d2); + CX_TEST_ASSERT(0 == cxMapDifferenceSimple(d2, d1, a)); + CX_TEST_ASSERT(cxMapContains(d2, "k0")); + CX_TEST_ASSERT(!cxMapContains(d2, "k1")); + CX_TEST_ASSERT(!cxMapContains(d2, "k2")); + CX_TEST_ASSERT(!cxMapContains(d2, "k3")); + CX_TEST_ASSERT(!cxMapContains(d2, "k4")); + CX_TEST_ASSERT(cxMapContains(d2, "k5")); + + cxMapClear(d1); + CX_TEST_ASSERT(0 == cxMapIntersectionSimple(d1, d2, c)); + CX_TEST_ASSERT(!cxMapContains(d1, "k0")); + CX_TEST_ASSERT(!cxMapContains(d1, "k1")); + CX_TEST_ASSERT(!cxMapContains(d1, "k2")); + CX_TEST_ASSERT(!cxMapContains(d1, "k3")); + CX_TEST_ASSERT(!cxMapContains(d1, "k4")); + CX_TEST_ASSERT(cxMapContains(d1, "k5")); + } + + cxMapFree(a); + cxMapFree(b); + cxMapFree(c); + cxListFree(kl1); + cxListFree(kl2); + cxMapFree(d1); + cxMapFree(d2); +} + CX_TEST(test_empty_map_size) { CX_TEST_DO { CX_TEST_ASSERT(cxEmptyMap->collection.size == 0); @@ -1520,6 +1623,7 @@ cx_test_register(suite, test_hash_map_union); cx_test_register(suite, test_hash_map_union_ptr); cx_test_register(suite, test_hash_map_union_alloc_fail); + cx_test_register(suite, test_hash_map_simple_clones); cx_test_register(suite, test_empty_map_no_ops); cx_test_register(suite, test_empty_map_size); cx_test_register(suite, test_empty_map_get); diff -r ac1baaed2fd7 -r 83146195a1db tests/test_list.c --- a/tests/test_list.c Sat Nov 08 23:45:19 2025 +0100 +++ b/tests/test_list.c Sun Nov 09 16:12:07 2025 +0100 @@ -2976,6 +2976,83 @@ } } +CX_TEST(test_list_simple_clones) { + + int a[] = {1, 2, 5, 8, 10}; + int b[] = {1, 3, 5, 7, 9, 11}; + int c[] = {2, 4, 6, 8, 10, 12}; + int d[] = {4, 8, 12}; + + CxList *la = cxArrayListCreateSimple(sizeof(int), 8); + cxCollectionCompareFunc(la, cx_cmp_int); + cxListInsertSortedArray(la, a, cx_nmemb(a)); + CxList *lb = cxArrayListCreateSimple(sizeof(int), 8); + cxCollectionCompareFunc(lb, cx_cmp_int); + cxListInsertSortedArray(lb, b, cx_nmemb(b)); + CxList *lc = cxArrayListCreateSimple(sizeof(int), 8); + cxCollectionCompareFunc(lc, cx_cmp_int); + cxListInsertSortedArray(lc, c, cx_nmemb(c)); + CxList *ld = cxArrayListCreateSimple(sizeof(int), 8); + cxCollectionCompareFunc(ld, cx_cmp_int); + cxListInsertSortedArray(ld, d, cx_nmemb(d)); + + CxList *d1 = cxArrayListCreateSimple(CX_STORE_POINTERS, 8); + cxCollectionCompareFunc(d1, cx_cmp_int); + cxDefineAdvancedDestructor(d1, cxFree, (void*) cxDefaultAllocator); + CxList *d2 = cxArrayListCreateSimple(CX_STORE_POINTERS, 8); + cxCollectionCompareFunc(d2, cx_cmp_int); + cxDefineAdvancedDestructor(d2, cxFree, (void*) cxDefaultAllocator); + + CX_TEST_DO { + // clone a into d1 + CX_TEST_ASSERT(0 == cxListCloneSimple(d1, la)); + CX_TEST_ASSERT(0 == cxListCompare(d1, la)); + CX_TEST_ASSERT(cxCollectionSorted(d1)); + + // union of a (in d1) and b + CX_TEST_ASSERT(0 == cxListUnionSimple(d2, d1, lb)); + CX_TEST_ASSERT(cxCollectionSorted(d2)); + CxList *expected_union = cxArrayListCreateSimple(sizeof(int), 8); + { + int expected[] = {1, 2, 3, 5, 7, 8, 9, 10, 11}; + cxListInsertSortedArray(expected_union, expected, cx_nmemb(expected)); + } + CX_TEST_ASSERT(0 == cxListCompare(d2, expected_union)); + cxListFree(expected_union); + + // intersection of (a union b) and c + cxListClear(d1); + CX_TEST_ASSERT(0 == cxListIntersectionSimple(d1, d2, lc)); + CX_TEST_ASSERT(cxCollectionSorted(d1)); + CxList *expected_intersection = cxArrayListCreateSimple(sizeof(int), 8); + { + int expected[] = {2, 8, 10}; + cxListInsertSortedArray(expected_intersection, expected, cx_nmemb(expected)); + } + CX_TEST_ASSERT(0 == cxListCompare(d1, expected_intersection)); + cxListFree(expected_intersection); + + // difference of ((a union b) intersect c) minus d + cxListClear(d2); + CX_TEST_ASSERT(0 == cxListDifferenceSimple(d2, d1, ld)); + CX_TEST_ASSERT(cxCollectionSorted(d2)); + CxList *expected_difference = cxArrayListCreateSimple(sizeof(int), 8); + { + int expected[] = {2, 10}; + cxListInsertSortedArray(expected_difference, expected, cx_nmemb(expected)); + } + CX_TEST_ASSERT(0 == cxListCompare(d2, expected_difference)); + cxListFree(expected_difference); + } + + cxListFree(d1); + cxListFree(d2); + cxListFree(la); + cxListFree(lb); + cxListFree(lc); + cxListFree(ld); +} + CX_TEST(test_list_pointer_list_supports_null) { CxList *list = cxLinkedListCreate(cxDefaultAllocator, cx_cmp_int, CX_STORE_POINTERS); int x = 47; @@ -3443,6 +3520,7 @@ cx_test_register(suite, test_list_intersection_sorted); cx_test_register(suite, test_list_intersection_unsorted_alloc_fail); cx_test_register(suite, test_list_intersection_sorted_alloc_fail); + cx_test_register(suite, test_list_simple_clones); return suite; }