implement cx_kvl_map_remove() default tip

Tue, 02 Sep 2025 21:12:51 +0200

author
Mike Becker <universe@uap-core.de>
date
Tue, 02 Sep 2025 21:12:51 +0200
changeset 1360
8b29d732f97b
parent 1359
fd7bbda93c7f

implement cx_kvl_map_remove()

relates to #461

src/kv_list.c file | annotate | diff | comparison | revisions
src/linked_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 20:26:10 2025 +0200
+++ b/src/kv_list.c	Tue Sep 02 21:12:51 2025 +0200
@@ -30,6 +30,8 @@
 #include "cx/hash_map.h"
 #include "cx/linked_list.h"
 
+#include <string.h>
+
 typedef struct cx_kv_list_s cx_kv_list;
 
 struct cx_kv_list_map_s {
@@ -200,8 +202,43 @@
 
 int cx_kvl_map_remove(CxMap *map, CxHashKey key, void *targetbuf) {
     cx_kv_list *kv_list = ((struct cx_kv_list_map_s*)map)->list;
-    // TODO: also remove the item from the list
-    return kv_list->map_methods->remove(map, key, targetbuf);
+    void *node_data;
+    if (kv_list->map_methods->remove(map, key, &node_data)) {
+        return 1;
+    }
+    // we cannot just call a list method (because we don't have the index)
+    // and tbh. we also don't want to (because it's not performant when we
+    // can have the node ptr directly instead)
+    // therefore, we re-implement the logic ourselves
+
+    // check if the outside caller want's us to return or to destroy the element
+    if (targetbuf == NULL) {
+        // destroy the element
+        cx_invoke_destructor(&kv_list->list.list_base, node_data);
+    } else {
+        // copy the element to the target buffer
+        memcpy(targetbuf, node_data, kv_list->list.list_base.collection.elem_size);
+    }
+
+    // calculate the address of the node
+    void *node_ptr = (char*)node_data - 2*sizeof(void*);
+
+    // unlink the node
+    cx_linked_list_remove(
+        &kv_list->list.begin,
+        &kv_list->list.end,
+        0,
+        sizeof(void*),
+        node_ptr
+    );
+
+    // decrement the list's size
+    kv_list->list.list_base.collection.size--;
+
+    // deallocate the node
+    cxFree(kv_list->list.list_base.collection.allocator, node_ptr);
+
+    return 0;
 }
 
 CxMapIterator cx_kvl_map_iterator(const CxMap *map, enum cx_map_iterator_type type) {
--- a/src/linked_list.c	Tue Sep 02 20:26:10 2025 +0200
+++ b/src/linked_list.c	Tue Sep 02 21:12:51 2025 +0200
@@ -565,6 +565,7 @@
 // HIGH LEVEL LINKED LIST IMPLEMENTATION
 
 typedef struct cx_linked_list_node cx_linked_list_node;
+// IMPORTANT: the layout must stay exactly like this, because kv_list.c uses that!
 struct cx_linked_list_node {
     cx_linked_list_node *prev;
     cx_linked_list_node *next;
--- a/tests/test_kv_list.c	Tue Sep 02 20:26:10 2025 +0200
+++ b/tests/test_kv_list.c	Tue Sep 02 21:12:51 2025 +0200
@@ -86,6 +86,8 @@
 
         CX_TEST_ASSERT(cxListSize(list) == 1);
         CX_TEST_ASSERT(*(int*)cxListAt(list, 0) == 37);
+
+        CX_TEST_ASSERT(0 != cxMapRemove(map, "xyz"));
     }
     cxListFree(list);
 }

mercurial