src/kv_list.c

changeset 1386
748d0d40881e
parent 1384
a2cfbff39e5d
--- a/src/kv_list.c	Sun Sep 21 18:42:18 2025 +0200
+++ b/src/kv_list.c	Sun Sep 21 19:31:30 2025 +0200
@@ -246,14 +246,31 @@
     kv_list->list_methods->reverse(list);
 }
 
+static void cx_kvl_list_iter_next(void *it) {
+    struct cx_iterator_s *iter = it;
+    if (iter->base.remove) {
+        // remove the assigned key from the map before calling the actual function
+        cx_kv_list *kv_list = iter->src_handle.m;
+        cx_kv_list_update_destructors(kv_list);
+        char *node = iter->elem_handle;
+        CxHashKey *key = cx_kv_list_loc_key(kv_list, node + kv_list->list.loc_data);
+        if (key->hash != 0) {
+            kv_list->map_methods->remove(&kv_list->map->map_base.base, *key, NULL);
+        }
+    }
+    iter->base.next_impl(it);
+}
+
 static struct cx_iterator_s cx_kvl_iterator(
         const struct cx_list_s *list,
         size_t index,
         bool backward
 ) {
     const cx_kv_list *kv_list = (const cx_kv_list*)list;
-    // TODO: cannot really forward, because mutating iterators must be able to remove the element
-    return kv_list->list_methods->iterator(list, index, backward);
+    struct cx_iterator_s iter = kv_list->list_methods->iterator(list, index, backward);
+    iter.base.next_impl = iter.base.next;
+    iter.base.next = cx_kvl_list_iter_next;
+    return iter;
 }
 
 static void cx_kvl_map_deallocate(struct cx_map_s *map) {
@@ -379,16 +396,37 @@
         key = cx_kv_list_loc_key(kv_list, next + kv_list->list.loc_data);
         if (key->hash != 0) break;
     }
+
+    // remove previous element if requested
+    if (iter->base.remove) {
+        iter->base.remove = false;
+        cx_kv_list_update_destructors(kv_list);
+        char *elem = iter->elem;
+        char *elem_data = elem + kv_list->list.loc_data;
+        CxHashKey *elem_key = cx_kv_list_loc_key(kv_list, elem_data);
+        // key is guaranteed to exist because iterator only iterates over elems with a key
+        kv_list->map_methods->remove(&kv_list->map->map_base.base, *elem_key, NULL);
+        cx_invoke_advanced_destructor(&kv_list->list.base, elem_data);
+        cx_linked_list_remove(
+            &kv_list->list.begin,
+            &kv_list->list.end,
+            kv_list->list.loc_prev,
+            kv_list->list.loc_next,
+            elem
+        );
+        cxFree(kv_list->list.base.collection.allocator, elem);
+        kv_list->list.base.collection.size--;
+        iter->index--;
+        iter->elem_count--;
+    }
+
+    // advance to the next element, if any
     if (next == NULL) {
         iter->index = kv_list->list.base.collection.size;
         iter->elem = NULL;
         iter->entry = (CxMapEntry){NULL, NULL};
         return;
     }
-
-    // TODO: implement removal
-
-    // advance to the next element
     iter->index++;
     iter->elem = next;
     iter->entry.key = key;

mercurial