src/kv_list.c

changeset 1367
6b3d52dd176e
parent 1365
e4135791687e
child 1368
19025ca34caa
--- a/src/kv_list.c	Mon Sep 08 22:48:48 2025 +0200
+++ b/src/kv_list.c	Tue Sep 09 22:30:18 2025 +0200
@@ -40,15 +40,8 @@
     cx_kv_list *list;
 };
 
-/** The list aspect (must have the same layout as the normal linked list). */
-struct cx_kv_list_list_s {
-    struct cx_list_s list_base;
-    void *begin;
-    void *end;
-};
-
 struct cx_kv_list_s {
-    struct cx_kv_list_list_s list;
+    struct cx_linked_list_s list;
     /** The lookup map - stores pointers to the nodes. */
     struct cx_kv_list_map_s *map;
     const cx_list_class *list_methods;
@@ -82,7 +75,7 @@
     const cx_kv_list *kv_list = list_ptr;
     // the elem called with a map destructor is a pointer to the node
     // we need to deref the elem accordingly
-    void *elem = kv_list->list.list_base.collection.store_pointer ? *(void**)node_data : node_data;
+    void *elem = kv_list->list.base.collection.store_pointer ? *(void**)node_data : node_data;
     if (kv_list->list_destr) {
         kv_list->list_destr(elem);
     }
@@ -100,15 +93,15 @@
 static void cx_kv_list_update_destructors(cx_kv_list *list) {
     // we copy the destructors to our custom fields and register
     // an own destructor function which invokes all these
-    if (list->list.list_base.collection.simple_destructor != NULL) {
-        list->list_destr = list->list.list_base.collection.simple_destructor;
-        list->list.list_base.collection.simple_destructor = NULL;
+    if (list->list.base.collection.simple_destructor != NULL) {
+        list->list_destr = list->list.base.collection.simple_destructor;
+        list->list.base.collection.simple_destructor = NULL;
     }
-    if (list->list.list_base.collection.advanced_destructor != cx_kv_list_destructor_wrapper_list) {
-        list->list_destr2 = list->list.list_base.collection.advanced_destructor;
-        list->list_destr_data = list->list.list_base.collection.destructor_data;
-        list->list.list_base.collection.advanced_destructor = cx_kv_list_destructor_wrapper_list;
-        list->list.list_base.collection.destructor_data = list;
+    if (list->list.base.collection.advanced_destructor != cx_kv_list_destructor_wrapper_list) {
+        list->list_destr2 = list->list.base.collection.advanced_destructor;
+        list->list_destr_data = list->list.base.collection.destructor_data;
+        list->list.base.collection.advanced_destructor = cx_kv_list_destructor_wrapper_list;
+        list->list.base.collection.destructor_data = list;
     }
     if (list->map->map_base.base.collection.simple_destructor != NULL) {
         list->map_destr = list->map->map_base.base.collection.simple_destructor;
@@ -126,8 +119,10 @@
     cx_kv_list *kv_list = (cx_kv_list*)list;
     // patch the destructors
     cx_kv_list_update_destructors(kv_list);
-    // free the map first
+    // free the map first, but skip the destructors of the map
+    cxDefineAdvancedDestructor(&kv_list->map->map_base.base, NULL, NULL);
     kv_list->map_methods->deallocate(&kv_list->map->map_base.base);
+    // then free the list, now the destructors may be called
     kv_list->list_methods->deallocate(list);
 }
 
@@ -196,7 +191,7 @@
     // clear the list
     kv_list->list_methods->clear(list);
     // then clear the map
-    cxMapClear(&kv_list->map->map_base.base);
+    kv_list->map_methods->clear(&kv_list->map->map_base.base);
 }
 
 static int cx_kvl_swap(
@@ -250,7 +245,7 @@
 static void cx_kvl_map_deallocate(struct cx_map_s *map) {
     cx_kv_list *kv_list = ((struct cx_kv_list_map_s*)map)->list;
     kv_list->map_methods->deallocate(map);
-    kv_list->list_methods->deallocate(&kv_list->list.list_base);
+    kv_list->list_methods->deallocate(&kv_list->list.base);
 }
 
 static void cx_kvl_map_clear(struct cx_map_s *map) {
@@ -263,10 +258,10 @@
 static void *cx_kvl_map_put(CxMap *map, CxHashKey key, void *value) {
     cx_kv_list *kv_list = ((struct cx_kv_list_map_s*)map)->list;
     // insert the data into the list first (assume that insertion destroys the sorted property)
-    kv_list->list.list_base.collection.sorted = false;
+    kv_list->list.base.collection.sorted = false;
     // TODO: use the same trick as above to increase the element size temporarily to add the key to the data
     void *node_data = kv_list->list_methods->insert_element(
-        &kv_list->list.list_base, kv_list->list.list_base.collection.size, value);
+        &kv_list->list.base, kv_list->list.base.collection.size, value);
     if (node_data == NULL) return NULL; // LCOV_EXCL_LINE
     // then insert the key into the map, referring to the node data
     // TODO: check if we still get a correct pointer when the list is storing pointers
@@ -294,29 +289,29 @@
     if (targetbuf == NULL) {
         // patch the destructors and invoke them through the wrapper
         cx_kv_list_update_destructors(kv_list);
-        cx_invoke_advanced_destructor(&kv_list->list.list_base, node_data);
+        cx_invoke_advanced_destructor(&kv_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);
+        memcpy(targetbuf, node_data, kv_list->list.base.collection.elem_size);
     }
 
     // calculate the address of the node
-    void *node_ptr = (char*)node_data - 2*sizeof(void*);
+    void *node_ptr = (char*)node_data - kv_list->list.loc_data;
 
     // unlink the node
     cx_linked_list_remove(
         &kv_list->list.begin,
         &kv_list->list.end,
-        0,
-        sizeof(void*),
+        kv_list->list.loc_prev,
+        kv_list->list.loc_next,
         node_ptr
     );
 
     // decrement the list's size
-    kv_list->list.list_base.collection.size--;
+    kv_list->list.base.collection.size--;
 
     // deallocate the node
-    cxFree(kv_list->list.list_base.collection.allocator, node_ptr);
+    cxFree(kv_list->list.base.collection.allocator, node_ptr);
 
     return 0;
 }
@@ -364,6 +359,8 @@
     // create a normal linked list and a normal hash map, first
     CxList *list = cxLinkedListCreate(allocator, comparator, elem_size);
     if (list == NULL) return NULL; // LCOV_EXCL_LINE
+    cx_linked_list *ll = (cx_linked_list*)list;
+    ll->extra_data_len = sizeof(CxHashKey);
     CxMap *map = cxHashMapCreate(allocator, CX_STORE_POINTERS, 0);
     if (map == NULL) { // LCOV_EXCL_START
         cxListFree(list);
@@ -421,7 +418,7 @@
 }
 
 CxList *cxKvListAsList(CxMap *map) {
-    return &((struct cx_kv_list_map_s*)map)->list->list.list_base;
+    return &((struct cx_kv_list_map_s*)map)->list->list.base;
 }
 
 CxMap *cxKvListAsMap(CxList *list) {
@@ -429,7 +426,16 @@
 }
 
 int cx_kv_list_set_key(CxList *list, size_t index, CxHashKey key) {
-    return -1;
+    cx_kv_list *kv_list = (cx_kv_list*)list;
+    char *node_data = kv_list->list_methods->at(list, index);
+    char *loc_key = node_data + list->collection.elem_size;
+    memcpy(loc_key, &key, sizeof(key));
+
+    // TODO: what happens when we are _replacing_ an existing key?
+    kv_list->map_methods->put(&kv_list->map->map_base.base, key, node_data);
+    // TODO: what happens if the map cocks up and returns NULL?
+
+    return 0;
 }
 
 int cx_kv_list_remove_key(CxList *list, size_t index, CxHashKey key) {

mercurial