adds array utility functions for user defined arrays feature/array

Tue, 24 Sep 2019 20:16:00 +0200

author
Mike Becker <universe@uap-core.de>
date
Tue, 24 Sep 2019 20:16:00 +0200
branch
feature/array
changeset 355
d315a068235a
parent 354
7fd13b9f8f60
child 356
77efe51c6c9a

adds array utility functions for user defined arrays

src/array.c file | annotate | diff | comparison | revisions
src/ucx/array.h file | annotate | diff | comparison | revisions
test/array_tests.c file | annotate | diff | comparison | revisions
test/array_tests.h file | annotate | diff | comparison | revisions
test/main.c file | annotate | diff | comparison | revisions
--- 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 <string.h>
 #include <stdlib.h>
+#include <errno.h>
 
 #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());
 }
--- 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 <code>array</code> argument.
+ * 
+ * On reallocation the capacity of the array is doubled until it is sufficient.
+ * The new capacity is stored back to <code>capacity</code>.
+ *  
+ * @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
+ * <code>sizeof(data)</code>.
+ * 
+ * @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 <code>array</code> argument.
+ * 
+ * On reallocation the capacity of the array is doubled until it is sufficient.
+ * The new capacity is stored back to <code>capacity</code>. 
+ * 
+ * @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
+ * <code>sizeof(data)</code>.
+ * 
+ * @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.
--- 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);
+}
--- 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
 }
--- 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);

mercurial