Mon, 22 Sep 2025 19:22:23 +0200
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));