diff -r 70ce877c838a -r 6b3d52dd176e src/kv_list.c --- 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) {