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
     1.1 --- a/src/cx/iterator.h	Sat Jan 22 17:15:14 2022 +0100
     1.2 +++ b/src/cx/iterator.h	Sat Jan 22 18:49:06 2022 +0100
     1.3 @@ -57,16 +57,6 @@
     1.4   */
     1.5  struct cx_iterator_s {
     1.6      /**
     1.7 -     * If the iterator is position-aware, contains the index of the element in the underlying collection.
     1.8 -     * Otherwise, this field is usually uninitialized.
     1.9 -     */
    1.10 -    size_t index;
    1.11 -    /**
    1.12 -     * Internal data.
    1.13 -     */
    1.14 -    void *data;
    1.15 -
    1.16 -    /**
    1.17       * True iff the iterator points to valid data.
    1.18       */
    1.19      bool (*valid)(CxIterator const *) __attribute__ ((__nonnull__));
    1.20 @@ -80,6 +70,29 @@
    1.21       * Advances the iterator.
    1.22       */
    1.23      void (*next)(CxIterator *) __attribute__ ((__nonnull__));
    1.24 +
    1.25 +    /**
    1.26 +     * Handle for the current element, if required.
    1.27 +     */
    1.28 +    void *elem_handle;
    1.29 +
    1.30 +    /**
    1.31 +     * Handle for the source collection, if any.
    1.32 +     */
    1.33 +    void *src_handle;
    1.34 +
    1.35 +    /**
    1.36 +     * If the iterator is position-aware, contains the index of the element in the underlying collection.
    1.37 +     * Otherwise, this field is usually uninitialized.
    1.38 +     */
    1.39 +    size_t index;
    1.40 +
    1.41 +    /**
    1.42 +     * Users may set this to true, if the current element shall be removed from the underlying collection
    1.43 +     * when the iterator advances.
    1.44 +     * Has no effect on iterators that are not based on a collection.
    1.45 +     */
    1.46 +    bool remove;
    1.47  };
    1.48  
    1.49  /**
     2.1 --- a/src/cx/list.h	Sat Jan 22 17:15:14 2022 +0100
     2.2 +++ b/src/cx/list.h	Sat Jan 22 18:49:06 2022 +0100
     2.3 @@ -125,7 +125,7 @@
     2.4       * Returns an iterator pointing to the specified index.
     2.5       */
     2.6      CxIterator (*iterator)(
     2.7 -            cx_list_s const *list,
     2.8 +            cx_list_s *list,
     2.9              size_t index
    2.10      );
    2.11  } cx_list_class;
     3.1 --- a/src/linked_list.c	Sat Jan 22 17:15:14 2022 +0100
     3.2 +++ b/src/linked_list.c	Sat Jan 22 18:49:06 2022 +0100
     3.3 @@ -641,40 +641,53 @@
     3.4  }
     3.5  
     3.6  static bool cx_ll_iter_valid(CxIterator const *iter) {
     3.7 -    return iter->data != NULL;
     3.8 +    return iter->elem_handle != NULL;
     3.9  }
    3.10  
    3.11  static void cx_ll_iter_next(CxIterator *iter) {
    3.12 -    iter->index++;
    3.13 -    cx_linked_list_node *node = iter->data;
    3.14 -    iter->data = node->next;
    3.15 +    if (iter->remove) {
    3.16 +        iter->remove = false;
    3.17 +        cx_linked_list *ll = iter->src_handle;
    3.18 +        cx_linked_list_node *node = iter->elem_handle;
    3.19 +        iter->elem_handle = node->next;
    3.20 +        cx_linked_list_remove((void **) &ll->begin, (void **) &ll->end,
    3.21 +                              CX_LL_LOC_PREV, CX_LL_LOC_NEXT, node);
    3.22 +        ll->base.size--;
    3.23 +        cxFree(ll->base.allocator, node);
    3.24 +    } else {
    3.25 +        iter->index++;
    3.26 +        cx_linked_list_node *node = iter->elem_handle;
    3.27 +        iter->elem_handle = node->next;
    3.28 +    }
    3.29  }
    3.30  
    3.31  static void *cx_ll_iter_current(CxIterator const *iter) {
    3.32 -    cx_linked_list_node *node = iter->data;
    3.33 +    cx_linked_list_node *node = iter->elem_handle;
    3.34      return node->payload;
    3.35  }
    3.36  
    3.37  static void *cx_pll_iter_current(CxIterator const *iter) {
    3.38 -    cx_linked_list_node *node = iter->data;
    3.39 +    cx_linked_list_node *node = iter->elem_handle;
    3.40      return *(void **) node->payload;
    3.41  }
    3.42  
    3.43  static CxIterator cx_ll_iterator(
    3.44 -        cx_list_s const *list,
    3.45 +        cx_list_s *list,
    3.46          size_t index
    3.47  ) {
    3.48      CxIterator iter;
    3.49      iter.index = index;
    3.50 -    iter.data = cx_ll_node_at((cx_linked_list const *) list, index);
    3.51 +    iter.src_handle = list;
    3.52 +    iter.elem_handle = cx_ll_node_at((cx_linked_list const *) list, index);
    3.53      iter.valid = cx_ll_iter_valid;
    3.54      iter.current = cx_ll_iter_current;
    3.55      iter.next = cx_ll_iter_next;
    3.56 +    iter.remove = false;
    3.57      return iter;
    3.58  }
    3.59  
    3.60  static CxIterator cx_pll_iterator(
    3.61 -        cx_list_s const *list,
    3.62 +        cx_list_s *list,
    3.63          size_t index
    3.64  ) {
    3.65      CxIterator iter = cx_ll_iterator(list, index);
     4.1 --- a/test/test_list.c	Sat Jan 22 17:15:14 2022 +0100
     4.2 +++ b/test/test_list.c	Sat Jan 22 18:49:06 2022 +0100
     4.3 @@ -762,12 +762,19 @@
     4.4  void test_hl_linked_list_iterator_impl(CxList list) {
     4.5      int i = 0;
     4.6      for (CxIterator iter = cxListBegin(list); cxIteratorValid(&iter); cxIteratorNext(&iter)) {
     4.7 -        CU_ASSERT_EQUAL(iter.index, (size_t) i)
     4.8 +        CU_ASSERT_EQUAL(iter.index, (size_t) (i + 1) / 2)
     4.9          int *x = cxIteratorCurrent(&iter);
    4.10          CU_ASSERT_EQUAL(*x, i)
    4.11 +        if (i % 2 == 1) iter.remove = true;
    4.12          i++;
    4.13      }
    4.14      CU_ASSERT_EQUAL(i, 10)
    4.15 +    CU_ASSERT_EQUAL_FATAL(list->size, 5)
    4.16 +    CU_ASSERT_EQUAL(*(int *) cxListAt(list, 0), 0)
    4.17 +    CU_ASSERT_EQUAL(*(int *) cxListAt(list, 1), 2)
    4.18 +    CU_ASSERT_EQUAL(*(int *) cxListAt(list, 2), 4)
    4.19 +    CU_ASSERT_EQUAL(*(int *) cxListAt(list, 3), 6)
    4.20 +    CU_ASSERT_EQUAL(*(int *) cxListAt(list, 4), 8)
    4.21      cxLinkedListDestroy(list);
    4.22      CU_ASSERT_TRUE(cxTestingAllocatorVerify())
    4.23  }

mercurial