add the feature to remove items during iteration

Sat, 22 Jan 2022 18:49:06 +0100

author
Mike Becker <universe@uap-core.de>
date
Sat, 22 Jan 2022 18:49:06 +0100
changeset 495
2856c74e18ba
parent 494
6ce8cfa10a96
child 496
1a07e24801a9

add the feature to remove items during iteration

src/cx/iterator.h file | annotate | diff | comparison | revisions
src/cx/list.h file | annotate | diff | comparison | revisions
src/linked_list.c file | annotate | diff | comparison | revisions
test/test_list.c file | annotate | diff | comparison | revisions
--- a/src/cx/iterator.h	Sat Jan 22 17:15:14 2022 +0100
+++ b/src/cx/iterator.h	Sat Jan 22 18:49:06 2022 +0100
@@ -57,16 +57,6 @@
  */
 struct cx_iterator_s {
     /**
-     * If the iterator is position-aware, contains the index of the element in the underlying collection.
-     * Otherwise, this field is usually uninitialized.
-     */
-    size_t index;
-    /**
-     * Internal data.
-     */
-    void *data;
-
-    /**
      * True iff the iterator points to valid data.
      */
     bool (*valid)(CxIterator const *) __attribute__ ((__nonnull__));
@@ -80,6 +70,29 @@
      * Advances the iterator.
      */
     void (*next)(CxIterator *) __attribute__ ((__nonnull__));
+
+    /**
+     * Handle for the current element, if required.
+     */
+    void *elem_handle;
+
+    /**
+     * Handle for the source collection, if any.
+     */
+    void *src_handle;
+
+    /**
+     * If the iterator is position-aware, contains the index of the element in the underlying collection.
+     * Otherwise, this field is usually uninitialized.
+     */
+    size_t index;
+
+    /**
+     * Users may set this to true, if the current element shall be removed from the underlying collection
+     * when the iterator advances.
+     * Has no effect on iterators that are not based on a collection.
+     */
+    bool remove;
 };
 
 /**
--- a/src/cx/list.h	Sat Jan 22 17:15:14 2022 +0100
+++ b/src/cx/list.h	Sat Jan 22 18:49:06 2022 +0100
@@ -125,7 +125,7 @@
      * Returns an iterator pointing to the specified index.
      */
     CxIterator (*iterator)(
-            cx_list_s const *list,
+            cx_list_s *list,
             size_t index
     );
 } cx_list_class;
--- a/src/linked_list.c	Sat Jan 22 17:15:14 2022 +0100
+++ b/src/linked_list.c	Sat Jan 22 18:49:06 2022 +0100
@@ -641,40 +641,53 @@
 }
 
 static bool cx_ll_iter_valid(CxIterator const *iter) {
-    return iter->data != NULL;
+    return iter->elem_handle != NULL;
 }
 
 static void cx_ll_iter_next(CxIterator *iter) {
-    iter->index++;
-    cx_linked_list_node *node = iter->data;
-    iter->data = node->next;
+    if (iter->remove) {
+        iter->remove = false;
+        cx_linked_list *ll = iter->src_handle;
+        cx_linked_list_node *node = iter->elem_handle;
+        iter->elem_handle = node->next;
+        cx_linked_list_remove((void **) &ll->begin, (void **) &ll->end,
+                              CX_LL_LOC_PREV, CX_LL_LOC_NEXT, node);
+        ll->base.size--;
+        cxFree(ll->base.allocator, node);
+    } else {
+        iter->index++;
+        cx_linked_list_node *node = iter->elem_handle;
+        iter->elem_handle = node->next;
+    }
 }
 
 static void *cx_ll_iter_current(CxIterator const *iter) {
-    cx_linked_list_node *node = iter->data;
+    cx_linked_list_node *node = iter->elem_handle;
     return node->payload;
 }
 
 static void *cx_pll_iter_current(CxIterator const *iter) {
-    cx_linked_list_node *node = iter->data;
+    cx_linked_list_node *node = iter->elem_handle;
     return *(void **) node->payload;
 }
 
 static CxIterator cx_ll_iterator(
-        cx_list_s const *list,
+        cx_list_s *list,
         size_t index
 ) {
     CxIterator iter;
     iter.index = index;
-    iter.data = cx_ll_node_at((cx_linked_list const *) list, index);
+    iter.src_handle = list;
+    iter.elem_handle = cx_ll_node_at((cx_linked_list const *) list, index);
     iter.valid = cx_ll_iter_valid;
     iter.current = cx_ll_iter_current;
     iter.next = cx_ll_iter_next;
+    iter.remove = false;
     return iter;
 }
 
 static CxIterator cx_pll_iterator(
-        cx_list_s const *list,
+        cx_list_s *list,
         size_t index
 ) {
     CxIterator iter = cx_ll_iterator(list, index);
--- a/test/test_list.c	Sat Jan 22 17:15:14 2022 +0100
+++ b/test/test_list.c	Sat Jan 22 18:49:06 2022 +0100
@@ -762,12 +762,19 @@
 void test_hl_linked_list_iterator_impl(CxList list) {
     int i = 0;
     for (CxIterator iter = cxListBegin(list); cxIteratorValid(&iter); cxIteratorNext(&iter)) {
-        CU_ASSERT_EQUAL(iter.index, (size_t) i)
+        CU_ASSERT_EQUAL(iter.index, (size_t) (i + 1) / 2)
         int *x = cxIteratorCurrent(&iter);
         CU_ASSERT_EQUAL(*x, i)
+        if (i % 2 == 1) iter.remove = true;
         i++;
     }
     CU_ASSERT_EQUAL(i, 10)
+    CU_ASSERT_EQUAL_FATAL(list->size, 5)
+    CU_ASSERT_EQUAL(*(int *) cxListAt(list, 0), 0)
+    CU_ASSERT_EQUAL(*(int *) cxListAt(list, 1), 2)
+    CU_ASSERT_EQUAL(*(int *) cxListAt(list, 2), 4)
+    CU_ASSERT_EQUAL(*(int *) cxListAt(list, 3), 6)
+    CU_ASSERT_EQUAL(*(int *) cxListAt(list, 4), 8)
     cxLinkedListDestroy(list);
     CU_ASSERT_TRUE(cxTestingAllocatorVerify())
 }

mercurial