Wed, 01 Jan 2025 14:03:49 +0100
add array iterator over pointer arrays
CHANGELOG | file | annotate | diff | comparison | revisions | |
src/cx/iterator.h | file | annotate | diff | comparison | revisions | |
src/iterator.c | file | annotate | diff | comparison | revisions | |
tests/test_iterator.c | file | annotate | diff | comparison | revisions |
--- a/CHANGELOG Wed Jan 01 13:31:38 2025 +0100 +++ b/CHANGELOG Wed Jan 01 14:03:49 2025 +0100 @@ -7,6 +7,7 @@ * adds locale-independent string to number conversion functions * adds reallocarray() like functions to allocator.h * adds cxIterator() to create iterators over raw C arrays + * adds cxIteratorPtr() to create iterators over raw C pointer arrays * adds cx_array_reallocator() and cx_array_default_reallocator * adds several new array and list functions * adds cxBufferReset()
--- a/src/cx/iterator.h Wed Jan 01 13:31:38 2025 +0100 +++ b/src/cx/iterator.h Wed Jan 01 14:03:49 2025 +0100 @@ -230,11 +230,16 @@ * The \p array can be \c NULL in which case the iterator will be immediately * initialized such that #cxIteratorValid() returns \c false. * + * This iterator yields the addresses of the array elements. + * If you want to iterator over an array of pointers, you can + * use cxIteratorPtr() to create an iterator which directly + * yields the stored pointers. * * @param array a pointer to the array (can be \c NULL) * @param elem_size the size of one array element * @param elem_count the number of elements in the array * @return an iterator for the specified array + * @see cxIteratorPtr() */ cx_attr_nodiscard CxIterator cxIterator( @@ -274,6 +279,46 @@ bool remove_keeps_order ); +/** + * Creates an iterator for the specified plain pointer array. + * + * This iterator assumes that every element in the array is a pointer + * and yields exactly those pointers during iteration (while in contrast + * an iterator created with cxIterator() would return the addresses + * of those pointers within the array). + * + * @param array a pointer to the array (can be \c NULL) + * @param elem_count the number of elements in the array + * @return an iterator for the specified array + * @see cxIterator() + */ +cx_attr_nodiscard +CxIterator cxIteratorPtr( + const void *array, + size_t elem_count +); + +/** + * Creates a mutating iterator for the specified plain pointer array. + * + * This is the mutating variant of cxIteratorPtr(). See also + * cxMutIterator(). + * + * @param array a pointer to the array (can be \c NULL) + * @param elem_count the number of elements in the array + * @param remove_keeps_order \c true if the order of elements must be preserved + * when removing an element + * @return an iterator for the specified array + * @see cxMutIterator() + * @see cxIteratorPtr() + */ +cx_attr_nodiscard +CxIterator cxMutIteratorPtr( + void *array, + size_t elem_count, + bool remove_keeps_order +); + #ifdef __cplusplus } // extern "C" #endif
--- a/src/iterator.c Wed Jan 01 13:31:38 2025 +0100 +++ b/src/iterator.c Wed Jan 01 14:03:49 2025 +0100 @@ -40,6 +40,11 @@ return iter->elem_handle; } +static void *cx_iter_current_ptr(const void *it) { + const struct cx_iterator_s *iter = it; + return *(void**)iter->elem_handle; +} + static void cx_iter_next_fast(void *it) { struct cx_iterator_s *iter = it; if (iter->base.remove) { @@ -110,3 +115,22 @@ iter.base.mutating = false; return iter; } + +CxIterator cxMutIteratorPtr( + void *array, + size_t elem_count, + bool remove_keeps_order +) { + CxIterator iter = cxMutIterator(array, sizeof(void*), elem_count, remove_keeps_order); + iter.base.current = cx_iter_current_ptr; + return iter; +} + +CxIterator cxIteratorPtr( + const void *array, + size_t elem_count +) { + CxIterator iter = cxMutIteratorPtr((void*) array, elem_count, false); + iter.base.mutating = false; + return iter; +}
--- a/tests/test_iterator.c Wed Jan 01 13:31:38 2025 +0100 +++ b/tests/test_iterator.c Wed Jan 01 14:03:49 2025 +0100 @@ -65,13 +65,13 @@ CxIterator iter = cxIterator(array, sizeof(unsigned), size); CX_TEST_DO { + CX_TEST_ASSERT(iter.elem_size == sizeof(unsigned)); + CX_TEST_ASSERT(iter.elem_count == size); + CX_TEST_ASSERT(iter.src_handle.c == array); unsigned expected = 0; cx_foreach(unsigned *, e, iter) { CX_TEST_ASSERT(iter.index == expected); CX_TEST_ASSERT(*e == expected); - CX_TEST_ASSERT(iter.elem_size == sizeof(unsigned)); - CX_TEST_ASSERT(iter.elem_count == size); - CX_TEST_ASSERT(iter.src_handle.c == array); CX_TEST_ASSERT(iter.elem_handle == &array[expected]); expected++; } @@ -79,6 +79,31 @@ } } +CX_TEST(test_iterator_iterate_pointers) { + unsigned array[20]; + unsigned* ptr_array[20]; + size_t size = cx_nmemb(array); + for (unsigned i = 0 ; i < size ; i++) { + array[i] = 3*i; + ptr_array[i] = &array[i]; + } + + CxIterator iter = cxIteratorPtr(ptr_array, size); + CX_TEST_DO { + CX_TEST_ASSERT(iter.elem_size == sizeof(void*)); + CX_TEST_ASSERT(iter.elem_count == size); + CX_TEST_ASSERT(iter.src_handle.c == ptr_array); + unsigned idx = 0; + cx_foreach(unsigned *, e, iter) { + CX_TEST_ASSERT(iter.index == idx); + CX_TEST_ASSERT(*e == array[idx]); + CX_TEST_ASSERT(iter.elem_handle == &ptr_array[idx]); + idx++; + } + CX_TEST_ASSERT(idx == size); + } +} + CX_TEST(test_iterator_with_slow_remove) { unsigned array[20]; size_t size = cx_nmemb(array); @@ -170,6 +195,7 @@ cx_test_register(suite, test_iterator_create); cx_test_register(suite, test_iterator_iterate); + cx_test_register(suite, test_iterator_iterate_pointers); cx_test_register(suite, test_iterator_with_slow_remove); cx_test_register(suite, test_iterator_with_fast_remove);