Sat, 22 Jan 2022 18:49:06 +0100
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()) }