the elem_count member of an iterator was not updated after removing an element flagged by cxIteratorFlagRemoval() - fixes #728 default tip

Mon, 22 Sep 2025 19:22:23 +0200

author
Mike Becker <universe@uap-core.de>
date
Mon, 22 Sep 2025 19:22:23 +0200
changeset 1387
9bdd053820b7
parent 1386
748d0d40881e

the elem_count member of an iterator was not updated after removing an element flagged by cxIteratorFlagRemoval() - fixes #728

CHANGELOG file | annotate | diff | comparison | revisions
src/array_list.c file | annotate | diff | comparison | revisions
src/hash_map.c file | annotate | diff | comparison | revisions
src/linked_list.c file | annotate | diff | comparison | revisions
tests/test_hash_map.c file | annotate | diff | comparison | revisions
tests/test_list.c file | annotate | diff | comparison | revisions
--- a/CHANGELOG	Sun Sep 21 19:31:30 2025 +0200
+++ b/CHANGELOG	Mon Sep 22 19:22:23 2025 +0200
@@ -27,6 +27,7 @@
  * fixes critical memory overflow in the stack-based array reallocator (this unfortunately breaks the function signature)
  * fixes mempool implementation not supporting NULL as argument for realloc
  * fixes mempool implementation not supporting zero as size for realloc
+ * fixes that the elem_count member of an iterator was not updated after removing an element flagged by cxIteratorFlagRemoval()
  * fixes that starting an iteration in a non-root node incorrectly continues iteration with the siblings of that node
  * fixes unnecessary allocations in cx_strcat() family of functions
  * fixes errno value after failing cxBufferSeek() to be consistently EINVAL
--- a/src/array_list.c	Sun Sep 21 19:31:30 2025 +0200
+++ b/src/array_list.c	Mon Sep 22 19:22:23 2025 +0200
@@ -942,6 +942,7 @@
     if (iter->base.remove) {
         iter->base.remove = false;
         cx_arl_remove(iter->src_handle.m, iter->index, 1, NULL);
+        iter->elem_count--;
     } else {
         iter->index++;
         iter->elem_handle =
@@ -956,6 +957,7 @@
     if (iter->base.remove) {
         iter->base.remove = false;
         cx_arl_remove(iter->src_handle.m, iter->index, 1, NULL);
+        iter->elem_count--;
     }
     iter->index--;
     if (iter->index < list->base.collection.size) {
--- a/src/hash_map.c	Sun Sep 21 19:31:30 2025 +0200
+++ b/src/hash_map.c	Mon Sep 22 19:22:23 2025 +0200
@@ -318,6 +318,7 @@
 
         // unlink
         cx_hash_map_unlink(hmap, iter->slot, prev, elm);
+        iter->elem_count--;
 
         // advance
         elm = next;
--- a/src/linked_list.c	Sun Sep 21 19:31:30 2025 +0200
+++ b/src/linked_list.c	Mon Sep 22 19:22:23 2025 +0200
@@ -987,6 +987,7 @@
         cx_linked_list_remove(&ll->begin, &ll->end,
                               ll->loc_prev, ll->loc_next, node);
         list->collection.size--;
+        iter->elem_count--;
         cxFree(list->collection.allocator, node);
     } else {
         const cx_linked_list *ll = iter->src_handle.c;
@@ -1009,6 +1010,7 @@
         cx_linked_list_remove(&ll->begin, &ll->end,
                               ll->loc_prev, ll->loc_next, node);
         list->collection.size--;
+        iter->elem_count--;
         cxFree(list->collection.allocator, node);
     } else {
         const cx_linked_list *ll = iter->src_handle.c;
--- a/tests/test_hash_map.c	Sun Sep 21 19:31:30 2025 +0200
+++ b/tests/test_hash_map.c	Mon Sep 22 19:22:23 2025 +0200
@@ -305,7 +305,8 @@
         cx_foreach(CxMapEntry*, entry, iter) {
             if (((const char *)entry->key->data)[4] % 2 == 1) cxIteratorFlagRemoval(iter);
         }
-        CX_TEST_ASSERT(map->collection.size == 3);
+        CX_TEST_ASSERT(cxMapSize(map) == 3);
+        CX_TEST_ASSERT(iter.elem_count == 3);
         CX_TEST_ASSERT(iter.index == map->collection.size);
 
         CX_TEST_ASSERT(cxMapGet(map, "key 1") == NULL);
@@ -403,15 +404,21 @@
     v1[0] = 'y'; // mark v1 and check that destr is not called for previous val
     {
         CxMapIterator iter = cxMapMutIteratorKeys(map);
+        CX_TEST_ASSERT(iter.elem_count == 4);
+        CX_TEST_ASSERT(cxMapSize(map) == 4);
         cx_foreach(CxHashKey*, key, iter) {
             if (((char*)key->data)[4] == '1') cxIteratorFlagRemoval(iter);
         }
+        CX_TEST_ASSERT(iter.elem_count == 3);
+        CX_TEST_ASSERT(cxMapSize(map) == 3);
     }
     {
         CxMapIterator iter = cxMapMutIteratorValues(map);
         cx_foreach(struct test_destr_struct*, v, iter) {
             if (v->str[4] == '5') cxIteratorFlagRemoval(iter);
         }
+        CX_TEST_ASSERT(iter.elem_count == 2);
+        CX_TEST_ASSERT(cxMapSize(map) == 2);
     }
 
     CX_TEST_ASSERT(0 == strcmp(v1, "yK"));
--- a/tests/test_list.c	Sun Sep 21 19:31:30 2025 +0200
+++ b/tests/test_list.c	Mon Sep 22 19:22:23 2025 +0200
@@ -1955,6 +1955,7 @@
     }
     CX_TEST_ASSERT(i == 0);
     CX_TEST_ASSERT(cxListSize(list) == len / 2);
+    CX_TEST_ASSERT(mut_iter.elem_count == len / 2);
     for (size_t k = 0; k < len / 2; k++) {
         CX_TEST_ASSERT(*(int *) cxListAt(list, k) == testdata[k * 2]);
     }
@@ -2096,12 +2097,14 @@
     CX_TEST_ASSERT(testdata_len - destr_test_ctr == cxListSize(list));
 
     CxIterator iter = cxListMutIteratorAt(list, 7);
+    CX_TEST_ASSERT(iter.elem_count == testdata_len - 2);
     cxIteratorNext(iter);
     CX_TEST_ASSERT(2 == destr_test_ctr);
     CX_TEST_ASSERT(testdata[48] == destr_last_value + off);
     CX_TEST_ASSERT(testdata_len - destr_test_ctr == cxListSize(list));
     cxIteratorFlagRemoval(iter);
     cxIteratorNext(iter);
+    CX_TEST_ASSERT(iter.elem_count == testdata_len - 3);
     CX_TEST_ASSERT(3 == destr_test_ctr);
     CX_TEST_ASSERT(testdata[8] == destr_last_value + off);
     CX_TEST_ASSERT(testdata_len - destr_test_ctr == cxListSize(list));
@@ -2113,6 +2116,7 @@
     CX_TEST_ASSERT(testdata_len - destr_test_ctr == cxListSize(list));
     cxIteratorFlagRemoval(iter);
     cxIteratorNext(iter);
+    CX_TEST_ASSERT(iter.elem_count == testdata_len - 4);
     CX_TEST_ASSERT(4 == destr_test_ctr);
     CX_TEST_ASSERT(testdata[4] == destr_last_value + off);
     CX_TEST_ASSERT(testdata_len - destr_test_ctr == cxListSize(list));

mercurial