Wed, 23 Nov 2022 22:40:55 +0100
#224 add cxListAddArray()
This also replaces cxLinkedListFromArray().
src/array_list.c | file | annotate | diff | comparison | revisions | |
src/cx/linked_list.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.cpp | file | annotate | diff | comparison | revisions |
--- a/src/array_list.c Sun Nov 20 21:08:36 2022 +0100 +++ b/src/array_list.c Wed Nov 23 22:40:55 2022 +0100 @@ -185,6 +185,29 @@ ); } +static size_t cx_arl_add_array( + struct cx_list_s *list, + void const *array, + size_t n +) { + cx_array_list *arl = (cx_array_list *) list; + if (CX_ARRAY_COPY_SUCCESS == cx_array_copy( + &arl->data, + &list->size, + &list->capacity, + list->size, + array, + list->itemsize, + n, + &arl->reallocator + )) { + return n; + } else { + // array list implementation is "all or nothing" + return 0; + } +} + static int cx_arl_insert( struct cx_list_s *list, size_t index, @@ -385,6 +408,7 @@ static cx_list_class cx_array_list_class = { cx_arl_destructor, cx_arl_add, + cx_arl_add_array, cx_arl_insert, cx_arl_insert_iter, cx_arl_remove,
--- a/src/cx/linked_list.h Sun Nov 20 21:08:36 2022 +0100 +++ b/src/cx/linked_list.h Wed Nov 23 22:40:55 2022 +0100 @@ -80,27 +80,6 @@ ) __attribute__((__nonnull__)); /** - * Creates a linked list using the data from an array. - * - * @remark Elements added to the list are copied, therefore a possible destructor - * MUST NOT free the memory pointed to by its argument. - * - * @param allocator the allocator for allocating the list nodes - * @param comparator the comparator for the elements - * @param item_size the size of one item in the array - * @param num_items the number of items - * @param array the array data - * @return the created list - */ -CxList *cxLinkedListFromArray( - CxAllocator const *allocator, - CxListComparator comparator, - size_t item_size, - size_t num_items, - void const *array -) __attribute__((__nonnull__)); - -/** * Finds the node at a certain index. * * This function can be used to start at an arbitrary position within the list.
--- a/src/cx/list.h Sun Nov 20 21:08:36 2022 +0100 +++ b/src/cx/list.h Wed Nov 23 22:40:55 2022 +0100 @@ -130,6 +130,15 @@ ); /** + * Member function for adding multiple elements. + */ + size_t (*add_array)( + struct cx_list_s *list, + void const *array, + size_t n + ); + + /** * Member function for inserting an element. */ int (*insert)( @@ -209,6 +218,7 @@ * @param list the list * @param elem a pointer to the element to add * @return zero on success, non-zero on memory allocation failure + * @see cxListAddArray() */ __attribute__((__nonnull__)) static inline int cxListAdd( @@ -219,6 +229,28 @@ } /** + * Adds multiple items to the end of the list. + * + * This method is more efficient than invoking cxListAdd() multiple times. + * + * If there is not enough memory to add all elements, the returned value is + * less than \p n. + * + * @param list the list + * @param array a pointer to the elements to add + * @param n the number of elements to add + * @return the number of added elements + */ +__attribute__((__nonnull__)) +static inline size_t cxListAddArray( + CxList *list, + void const *array, + size_t n +) { + return list->cl->add_array(list, array, n); +} + +/** * Inserts an item at the specified index. * * If \p index equals the list \c size, this is effectively cxListAdd().
--- a/src/linked_list.c Sun Nov 20 21:08:36 2022 +0100 +++ b/src/linked_list.c Wed Nov 23 22:40:55 2022 +0100 @@ -540,6 +540,20 @@ return cx_ll_insert(list, list->size, elem); } +static size_t cx_ll_add_array( + struct cx_list_s *list, + void const *array, + size_t n +) { + // TODO: redirect to cx_ll_insert_array + cx_for_n (i, n) { + if (cx_ll_add(list, ((char const *) array) + i * list->itemsize)) { + return i; + } + } + return n; +} + static int cx_pll_insert( struct cx_list_s *list, size_t index, @@ -727,6 +741,7 @@ static cx_list_class cx_linked_list_class = { cx_ll_destructor, cx_ll_add, + cx_ll_add_array, cx_ll_insert, cx_ll_insert_iter, cx_ll_remove, @@ -741,6 +756,7 @@ static cx_list_class cx_pointer_linked_list_class = { cx_ll_destructor, cx_pll_add, + cx_ll_add_array, cx_pll_insert, cx_pll_insert_iter, cx_ll_remove, @@ -786,22 +802,3 @@ return (CxList *) list; } - -CxList *cxLinkedListFromArray( - CxAllocator const *allocator, - CxListComparator comparator, - size_t item_size, - size_t num_items, - void const *array -) { - CxList *list = cxLinkedListCreate(allocator, comparator, item_size); - if (list == NULL) return NULL; - cx_for_n (i, num_items) { - if (0 != cxListAdd(list, ((const unsigned char *) array) + i * item_size)) { - cx_ll_destructor(list); - cxFree(allocator, list); - return NULL; - } - } - return list; -}
--- a/test/test_list.cpp Sun Nov 20 21:08:36 2022 +0100 +++ b/test/test_list.cpp Wed Nov 23 22:40:55 2022 +0100 @@ -569,28 +569,21 @@ } auto linkedListFromTestData() const -> CxList * { - // TODO: replace with cxListAddArray - return autofree( - cxLinkedListFromArray( - &testingAllocator, - cx_cmp_int, - sizeof(int), - testdata_len, - testdata.data.data() - ) - ); + auto list = autofree(cxLinkedListCreate(&testingAllocator, cx_cmp_int, sizeof(int))); + cxListAddArray(list, testdata.data.data(), testdata_len); + return list; } auto pointerLinkedListFromTestData() const -> CxList * { auto list = autofree(cxPointerLinkedListCreate(&testingAllocator, cx_cmp_int)); + // note: cannot use cxListAddArray() because we don't have a list of pointers cx_for_n(i, testdata_len) cxListAdd(list, &testdata.data[i]); return list; } auto arrayListFromTestData() const -> CxList * { auto list = autofree(cxArrayListCreate(&testingAllocator, cx_cmp_int, sizeof(int), testdata_len)); - // TODO: replace with cxListAddArray - cx_for_n(i, testdata_len) cxListAdd(list, &testdata.data[i]); + cxListAddArray(list, testdata.data.data(), testdata_len); return list; } @@ -796,18 +789,6 @@ verifyCreate(list); } -TEST_F(LinkedList, cxLinkedListFromArray) { - CxList *expected = autofree(cxLinkedListCreate(&testingAllocator, cx_cmp_int, sizeof(int))); - cx_for_n (i, testdata_len) cxListAdd(expected, &testdata.data[i]); - CxList *list = autofree(cxLinkedListFromArray(&testingAllocator, cx_cmp_int, sizeof(int), - testdata_len, testdata.data.data())); - ASSERT_NE(list, nullptr); - EXPECT_EQ(list->itemsize, sizeof(int)); - EXPECT_EQ(list->capacity, (size_t) -1); - EXPECT_EQ(list->size, testdata_len); - EXPECT_EQ(cxListCompare(list, expected), 0); -} - TEST_F(ArrayList, cxArrayListCreate) { CxList *list = autofree(cxArrayListCreate(&testingAllocator, cx_cmp_int, sizeof(int), 8)); ASSERT_NE(list, nullptr); @@ -905,13 +886,15 @@ TEST_F(LinkedList, InsertViaIterator) { int fivenums[] = {0, 1, 2, 3, 4, 5}; - CxList *list = autofree(cxLinkedListFromArray(&testingAllocator, cx_cmp_int, sizeof(int), 5, fivenums)); + CxList *list = autofree(cxLinkedListCreate(&testingAllocator, cx_cmp_int, sizeof(int))); + cxListAddArray(list, fivenums, 5); verifyInsertViaIterator(list); } TEST_F(PointerLinkedList, InsertViaIterator) { int fivenums[] = {0, 1, 2, 3, 4, 5}; CxList *list = autofree(cxPointerLinkedListCreate(&testingAllocator, cx_cmp_int)); + // note: don't use cxListAddArray() here, because we don't have a list of pointers cx_for_n (i, 5) cxListAdd(list, &fivenums[i]); verifyInsertViaIterator(list); } @@ -919,8 +902,7 @@ TEST_F(ArrayList, InsertViaIterator) { int fivenums[] = {0, 1, 2, 3, 4, 5}; CxList *list = autofree(cxArrayListCreate(&testingAllocator, cx_cmp_int, sizeof(int), 4)); - // TODO: replace with cxListAddArray - cx_for_n (i, 5) cxListAdd(list, &fivenums[i]); + cxListAddArray(list, fivenums, 5); verifyInsertViaIterator(list); }