# HG changeset patch # User Mike Becker # Date 1569348960 -7200 # Node ID d315a068235ac3b401ffea90674776c54049bc31 # Parent 7fd13b9f8f602627b2baf21dc8ed84c29c5c9844 adds array utility functions for user defined arrays diff -r 7fd13b9f8f60 -r d315a068235a src/array.c --- a/src/array.c Sat Aug 10 11:12:49 2019 +0200 +++ b/src/array.c Tue Sep 24 20:16:00 2019 +0200 @@ -35,6 +35,7 @@ #include #include +#include #ifndef UCX_ARRAY_DISABLE_QSORT #ifdef __GLIBC__ @@ -67,6 +68,51 @@ } } +int ucx_array_util_set_a(UcxAllocator* alloc, void** array, size_t* capacity, + size_t elmsize, size_t index, ...) { + + if(!alloc || !capacity || !array) { + errno = EINVAL; + return 1; + } + + size_t newcapacity = *capacity; + while(index >= newcapacity) { + if(ucx_szmul(newcapacity, 2, &newcapacity)) { + errno = EOVERFLOW; + return 1; + } + } + + size_t memlen, offset; + if(ucx_szmul(newcapacity, elmsize, &memlen)) { + errno = EOVERFLOW; + return 1; + } + /* we don't need to check index*elmsize - it is smaller than memlen */ + + + void* newptr = alrealloc(alloc, *array, memlen); + if(newptr == NULL) { + errno = ENOMEM; /* we cannot assume that every allocator sets this */ + return 1; + } + *array = newptr; + *capacity = newcapacity; + + + char* dest = *array; + dest += elmsize*index; + + va_list ap; + va_start(ap, index); + int elem = va_arg(ap, int); + memcpy(dest, &elem, elmsize); + va_end(ap); + + return 0; +} + UcxArray ucx_array_new(size_t capacity, size_t elemsize) { return ucx_array_new_a(capacity, elemsize, ucx_default_allocator()); } diff -r 7fd13b9f8f60 -r d315a068235a src/ucx/array.h --- a/src/ucx/array.h Sat Aug 10 11:12:49 2019 +0200 +++ b/src/ucx/array.h Tue Sep 24 20:16:00 2019 +0200 @@ -69,6 +69,77 @@ UcxAllocator* allocator; } UcxArray; +/** + * Sets an element in an arbitrary user defined array. + * + * If the capacity is insufficient, the array is automatically reallocated and + * the possibly new pointer is stored in the array argument. + * + * On reallocation the capacity of the array is doubled until it is sufficient. + * The new capacity is stored back to capacity. + * + * @param array a pointer to location of the array pointer + * @param capacity a pointer to the capacity + * @param elmsize the size of each element + * @param idx the index of the element to set + * @param data the element data + * @return zero on success or non-zero on error (errno will be set) + */ +#define ucx_array_util_set(array, capacity, elmsize, idx, data) \ + ucx_array_util_set_a(ucx_default_allocator(), (void**)(array), capacity, \ + elmsize, idx, data) + +/** + * Convenience macro for ucx_array_util_set() which automatically computes + * sizeof(data). + * + * @param array a pointer to location of the array pointer + * @param capacity a pointer to the capacity + * @param idx the index of the element to set + * @param data the element data + * @return zero on success or non-zero on error (errno will be set) + * @see ucx_array_util_set() + */ +#define UCX_ARRAY_UTIL_SET(array, capacity, idx, data) \ + ucx_array_util_set_a(ucx_default_allocator(), (void**)(array), capacity, \ + sizeof(data), idx, data) + +/** + * Sets an element in an arbitrary user defined array. + * + * If the capacity is insufficient, the array is automatically reallocated + * using the specified allocator and the possibly new pointer is stored in + * the array argument. + * + * On reallocation the capacity of the array is doubled until it is sufficient. + * The new capacity is stored back to capacity. + * + * @param alloc the allocator that shall be used to reallocate the array + * @param array a pointer to location of the array pointer + * @param capacity a pointer to the capacity + * @param elmsize the size of each element + * @param idx the index of the element to set + * @param ... the element data + * @return zero on success or non-zero on error (errno will be set) + */ +int ucx_array_util_set_a(UcxAllocator* alloc, void** array, size_t* capacity, + size_t elmsize, size_t idx, ...); + + +/** + * Convenience macro for ucx_array_util_set_a() which automatically computes + * sizeof(data). + * + * @param alloc the allocator that shall be used to reallocate the array + * @param array a pointer to location of the array pointer + * @param capacity a pointer to the capacity + * @param idx the index of the element to set + * @param data the element data + * @return zero on success or non-zero on error (errno will be set) + * @see ucx_array_util_set_a() + */ +#define UCX_ARRAY_UTIL_SET_A(alloc, array, capacity, idx, data) \ + ucx_array_util_set_a(alloc, capacity, sizeof(data), idx, data) /** * Creates a new UCX array with the given capacity and element size. diff -r 7fd13b9f8f60 -r d315a068235a test/array_tests.c --- a/test/array_tests.c Sat Aug 10 11:12:49 2019 +0200 +++ b/test/array_tests.c Tue Sep 24 20:16:00 2019 +0200 @@ -622,3 +622,26 @@ UCX_TEST_END ucx_array_destroy(&array); } + +UCX_TEST(test_ucx_array_util_set) { + size_t capacity = 16; + int* array = malloc(sizeof(int)*capacity); + + UCX_TEST_BEGIN + + UCX_ARRAY_UTIL_SET(&array, &capacity, 7, 42); + + UCX_TEST_ASSERT(array[7] == 42, "failed"); + UCX_TEST_ASSERT(capacity == 16, "capacity changed unnecessarily"); + + UCX_ARRAY_UTIL_SET(&array, &capacity, 37, 13); + UCX_ARRAY_UTIL_SET(&array, &capacity, 38, 37); + + UCX_TEST_ASSERT(array[37] == 13, "failed"); + UCX_TEST_ASSERT(array[38] == 37, "failed"); + UCX_TEST_ASSERT(capacity == 64, "capacity not grown"); + + UCX_TEST_END + + free(array); +} diff -r 7fd13b9f8f60 -r d315a068235a test/array_tests.h --- a/test/array_tests.h Sat Aug 10 11:12:49 2019 +0200 +++ b/test/array_tests.h Tue Sep 24 20:16:00 2019 +0200 @@ -56,6 +56,7 @@ UCX_TEST(test_ucx_array_shrink); UCX_TEST(test_ucx_array_resize); UCX_TEST(test_ucx_array_reserve); +UCX_TEST(test_ucx_array_util_set); #ifdef __cplusplus } diff -r 7fd13b9f8f60 -r d315a068235a test/main.c --- a/test/main.c Sat Aug 10 11:12:49 2019 +0200 +++ b/test/main.c Tue Sep 24 20:16:00 2019 +0200 @@ -163,6 +163,7 @@ ucx_test_register(suite, test_ucx_array_shrink); ucx_test_register(suite, test_ucx_array_resize); ucx_test_register(suite, test_ucx_array_reserve); + ucx_test_register(suite, test_ucx_array_util_set); /* UcxList Tests */ ucx_test_register(suite, test_ucx_list_append);