Wed, 03 Sep 2025 22:52:20 +0200
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; }