implement support for registering destructors to a kv-list using its map aspect

Wed, 03 Sep 2025 22:52:20 +0200

author
Mike Becker <universe@uap-core.de>
date
Wed, 03 Sep 2025 22:52:20 +0200
changeset 1361
cdc3242a9b33
parent 1360
8b29d732f97b
child 1362
d886626a9526

implement support for registering destructors to a kv-list using its map aspect

relates to #461

src/kv_list.c file | annotate | diff | comparison | revisions
tests/test_kv_list.c file | annotate | diff | comparison | revisions
--- a/src/kv_list.c	Tue Sep 02 21:12:51 2025 +0200
+++ b/src/kv_list.c	Wed Sep 03 22:52:20 2025 +0200
@@ -214,7 +214,19 @@
     // check if the outside caller want's us to return or to destroy the element
     if (targetbuf == NULL) {
         // destroy the element
+        // invoke all destructors from both the list and the map aspect
+        // (usually the user will only use one of the aspects anyway and if not, it's documented)
         cx_invoke_destructor(&kv_list->list.list_base, node_data);
+        // note that we cannot use the macro, because it will use the wrong store_pointer information
+        CxMap *map_aspect = &kv_list->map->map_base.base;
+        if (map_aspect->collection.simple_destructor) {
+            map_aspect->collection.simple_destructor(
+                kv_list->list.list_base.collection.store_pointer ? *(void**)node_data : node_data);
+        }
+        if (map_aspect->collection.advanced_destructor) {
+            map_aspect->collection.advanced_destructor(map_aspect->collection.destructor_data,
+                kv_list->list.list_base.collection.store_pointer ? *(void**)node_data : node_data);
+        }
     } else {
         // copy the element to the target buffer
         memcpy(targetbuf, node_data, kv_list->list.list_base.collection.elem_size);
--- a/tests/test_kv_list.c	Tue Sep 02 21:12:51 2025 +0200
+++ b/tests/test_kv_list.c	Wed Sep 03 22:52:20 2025 +0200
@@ -42,6 +42,33 @@
     cxListFree(list);
 }
 
+CX_TEST(test_kv_list_free_as_map) {
+    CxTestingAllocator talloc;
+    cx_testing_allocator_init(&talloc);
+    CX_TEST_DO {
+        CxList *list = cxKvListCreate(&talloc.base, NULL, 1);
+        cxListAddArray(list, "test", 4);
+        CxMap *map = cxKvListAsMap(list);
+        cxMapFree(map);
+        CX_TEST_ASSERT(cx_testing_allocator_verify(&talloc));
+    }
+    cx_testing_allocator_destroy(&talloc);
+}
+
+CX_TEST(test_kv_list_free_as_list) {
+    CxTestingAllocator talloc;
+    cx_testing_allocator_init(&talloc);
+    CX_TEST_DO {
+        CxMap *map = cxKvListCreateAsMap(&talloc.base, NULL, sizeof(int));
+        int x = 5;
+        cxMapPut(map, "test", &x);
+        CxList *list = cxKvListAsList(map);
+        cxListFree(list);
+        CX_TEST_ASSERT(cx_testing_allocator_verify(&talloc));
+    }
+    cx_testing_allocator_destroy(&talloc);
+}
+
 CX_TEST(test_kv_list_map_put) {
     CxList *list = cxKvListCreateSimple(sizeof(int));
     int x;
@@ -92,12 +119,52 @@
     cxListFree(list);
 }
 
+static int kv_list_test_destr_val;
+static void kv_list_test_destr(void *data) {
+    kv_list_test_destr_val = *(int*)data;
+}
+
+CX_TEST(test_kv_list_map_remove_destr_in_list) {
+    CxList *list = cxKvListCreateSimple(sizeof(int));
+    int x;
+    CX_TEST_DO {
+        x = 0xabcd;
+        CX_TEST_ASSERT(0 == cxListAdd(list, &x));
+        cxKvListSetKey(list, 0, "xyz");
+
+        cxDefineDestructor(list, kv_list_test_destr);
+        kv_list_test_destr_val = 0;
+        CX_TEST_ASSERT(0 == cxListRemove(list, 0));
+        CX_TEST_ASSERT(kv_list_test_destr_val == 0xabcd);
+    }
+    cxListFree(list);
+}
+
+CX_TEST(test_kv_list_map_remove_destr_in_map) {
+    CxMap *map = cxKvListCreateAsMapSimple(sizeof(int));
+    int x;
+    CX_TEST_DO {
+        x = 0xabcd;
+        CX_TEST_ASSERT(0 == cxMapPut(map, "xyz", &x));
+
+        cxDefineDestructor(map, kv_list_test_destr);
+        kv_list_test_destr_val = 0;
+        CX_TEST_ASSERT(0 == cxMapRemove(map, "xyz"));
+        CX_TEST_ASSERT(kv_list_test_destr_val == 0xabcd);
+    }
+    cxMapFree(map);
+}
+
 CxTestSuite *cx_test_suite_kv_list_specifics(void) {
     CxTestSuite *suite = cx_test_suite_new("kv_list specifics");
 
     cx_test_register(suite, test_kv_list_map_as_list);
+    cx_test_register(suite, test_kv_list_free_as_map);
+    cx_test_register(suite, test_kv_list_free_as_list);
     cx_test_register(suite, test_kv_list_map_put);
     cx_test_register(suite, test_kv_list_map_remove);
+    cx_test_register(suite, test_kv_list_map_remove_destr_in_list);
+    cx_test_register(suite, test_kv_list_map_remove_destr_in_map);
 
     return suite;
 }

mercurial