removes cumbersome array accessor macros feature/array

Tue, 06 Aug 2019 16:26:46 +0200

author
Mike Becker <universe@uap-core.de>
date
Tue, 06 Aug 2019 16:26:46 +0200
branch
feature/array
changeset 342
8f0a3c00d1d2
parent 341
b9715d7317c1
child 343
c09da4ee177f

removes cumbersome array accessor macros

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	Thu Jul 11 10:11:43 2019 +0200
+++ b/src/array.c	Tue Aug 06 16:26:46 2019 +0200
@@ -223,7 +223,7 @@
         return;
     }
   
-    // we need memory for one element
+    /* we need memory for one element */
     void *value = malloc(array->elemsize);
     
     while (start <= mid && rightstart <= end) { 
@@ -231,16 +231,16 @@
                 ucx_array_at(*array, rightstart), data) <= 0) { 
             start++; 
         } else {
-            // save the value from the right
+            /* save the value from the right */
             memcpy(value, ucx_array_at(*array, rightstart), array->elemsize);
                         
-            // shift all left elements one element to the right
+            /* shift all left elements one element to the right */
             size_t shiftcount = rightstart-start;
             void *startptr = ucx_array_at(*array, start);
             void *dest = ucx_array_at(*array, start+1);
             memmove(dest, startptr, shiftcount*array->elemsize);
             
-            // bring the first value from the right to the left
+            /* bring the first value from the right to the left */
             memcpy(startptr, value, array->elemsize);
   
             start++; 
@@ -249,7 +249,7 @@
         }
     }
     
-    // free the temporary memory
+    /* free the temporary memory */
     free(value);
 } 
   
--- a/src/ucx/array.h	Thu Jul 11 10:11:43 2019 +0200
+++ b/src/ucx/array.h	Tue Aug 06 16:26:46 2019 +0200
@@ -199,64 +199,6 @@
 void *ucx_array_at(UcxArray array, size_t index);
 
 /**
- * Returns an element of the specified type by value.
- * 
- * This expression can also be assigned to.
- * 
- * If <code>sizeof(type)</code> does not equal the array's element size, the
- * behavior is undefined.
- * If the index is out of bounds, the behavior is undefined.
- * 
- * @param type the type of the element
- * @param array the array to retrieve the element from
- * @param index index of the element to return
- * @return the requested element
- * @see ucx_array_at()
- */
-#define ucx_array_at_typed(type, array, index) (((type*)((array).data))[index])
-
-/**
- * Shorthand for ucx_array_at_typed().
- */
-#define ucx_array_at_int(arr, i) ucx_array_at_typed(int, arr, i)
-
-/**
- * Shorthand for ucx_array_at_typed().
- */
-#define ucx_array_at_short(arr, i) ucx_array_at_typed(short, arr, i)
-
-/**
- * Shorthand for ucx_array_at_typed().
- */
-#define ucx_array_at_longint(arr, i) ucx_array_at_typed(long int, arr, i)
-
-/**
- * Shorthand for ucx_array_at_typed().
- */
-#define ucx_array_at_uint(arr, i) ucx_array_at_typed(unsigned int, arr, i)
-
-/**
- * Shorthand for ucx_array_at_typed().
- */
-#define ucx_array_at_ushort(arr, i) ucx_array_at_typed(unsigned short, arr, i)
-
-/**
- * Shorthand for ucx_array_at_typed().
- */
-#define ucx_array_at_ulongint(arr, i) \
-    ucx_array_at_typed(unsigned long int, arr, i)
-
-/**
- * Shorthand for ucx_array_get_typed().
- */
-#define ucx_array_get_float(arr, i) ucx_array_get_typed(float, arr, i)
-
-/**
- * Shorthand for ucx_array_get_typed().
- */
-#define ucx_array_get_double(arr, i) ucx_array_get_typed(double, arr, i)
-
-/**
  * Returns the index of an element containing the specified data.
  *
  * This function uses a cmp_func() to compare the data of each list element
@@ -290,9 +232,14 @@
 int ucx_array_contains(UcxArray array, void *elem, cmp_func cmpfnc, void *data);
 
 /**
- * Sorts a UcxArray with an almost in-place merge sort.
+ * Sorts a UcxArray with the best available sort algorithm.
  * 
- * This function uses additional memory for exactly one element.
+ * If present, qsort_s() will be used. Otherwise, if no additional data is
+ * specified, qsort() is used as a fall back.
+ * 
+ * If qsort_s() is not available and <code>data</code> is not <code>NULL</code>,
+ * a custom almost in-place merge sort algorithm is used, which uses additional
+ * memory for exactly one element.
  * 
  * @param array the array to sort
  * @param cmpfnc the function that shall be used to compare the element data
--- a/test/array_tests.c	Thu Jul 11 10:11:43 2019 +0200
+++ b/test/array_tests.c	Tue Aug 06 16:26:46 2019 +0200
@@ -58,28 +58,32 @@
 
 UCX_TEST(test_ucx_array_append) {
     UcxArray array = ucx_array_new(16, sizeof(int));
+    int *elements;
     
     int x = 42;
     ucx_array_append(&array, &x);
     UCX_TEST_BEGIN
     
-    UCX_TEST_ASSERT(ucx_array_at_int(array, 0) == 42, "failed");
+    elements = array.data;
+    UCX_TEST_ASSERT(elements[0] == 42, "failed");
     
     x = 13;
     ucx_array_append(&array, &x);
     
+    elements = array.data;
     UCX_TEST_ASSERT(array.size == 2, "incorrect size after append");
-    UCX_TEST_ASSERT(ucx_array_at_int(array, 1) == 13, "failed");
-    UCX_TEST_ASSERT(ucx_array_at_int(array, 0) == 42,
+    UCX_TEST_ASSERT(elements[1] == 13, "failed");
+    UCX_TEST_ASSERT(elements[0] == 42,
             "append corrupted previously inserted data");
     
     ucx_array_append(&array, NULL);
     
+    elements = array.data;
     UCX_TEST_ASSERT(array.size == 3, "incorrect size after NULL append");
-    UCX_TEST_ASSERT(ucx_array_at_int(array, 2) == 0, "element is not zeroed");
-    UCX_TEST_ASSERT(ucx_array_at_int(array, 0) == 42,
+    UCX_TEST_ASSERT(elements[2] == 0, "element is not zeroed");
+    UCX_TEST_ASSERT(elements[0] == 42,
             "NULL append corrupted previously inserted data");
-    UCX_TEST_ASSERT(ucx_array_at_int(array, 1) == 13,
+    UCX_TEST_ASSERT(elements[1] == 13,
             "NULL append corrupted previously inserted data");
     
     UCX_TEST_END
@@ -88,29 +92,33 @@
 }
 
 UCX_TEST(test_ucx_array_prepend) {
+    int *elems;
     UcxArray array = ucx_array_new(16, sizeof(int));
     
     int x = 42;
     ucx_array_prepend(&array, &x);
     UCX_TEST_BEGIN
     
-    UCX_TEST_ASSERT(ucx_array_at_int(array, 0) == 42, "failed");
+    elems = array.data;
+    UCX_TEST_ASSERT(elems[0] == 42, "failed");
     
     x = 13;
     ucx_array_prepend(&array, &x);
     
+    elems = array.data;
     UCX_TEST_ASSERT(array.size == 2, "incorrect size after prepend");
-    UCX_TEST_ASSERT(ucx_array_at_int(array, 0) == 13, "failed");
-    UCX_TEST_ASSERT(ucx_array_at_int(array, 1) == 42,
+    UCX_TEST_ASSERT(elems[0] == 13, "failed");
+    UCX_TEST_ASSERT(elems[1] == 42,
             "prepend corrupted previously inserted data");
     
     ucx_array_prepend(&array, NULL);
     
+    elems = array.data;
     UCX_TEST_ASSERT(array.size == 3, "incorrect size after NULL prepend");
-    UCX_TEST_ASSERT(ucx_array_at_int(array, 0) == 0, "element is not zeroed");
-    UCX_TEST_ASSERT(ucx_array_at_int(array, 1) == 13,
+    UCX_TEST_ASSERT(elems[0] == 0, "element is not zeroed");
+    UCX_TEST_ASSERT(elems[1] == 13,
             "NULL prepend corrupted previously inserted data");
-    UCX_TEST_ASSERT(ucx_array_at_int(array, 2) == 42,
+    UCX_TEST_ASSERT(elems[2] == 42,
             "NULL prepend corrupted previously inserted data");
     
     UCX_TEST_END
@@ -119,27 +127,33 @@
 }
 
 UCX_TEST(test_ucx_array_set) {
+    int *elems;
     UcxArray array = ucx_array_new(16, sizeof(int));
     
+    
     int x = 42;
 
     UCX_TEST_BEGIN
 
     ucx_array_set(&array, 7, &x);
-    UCX_TEST_ASSERT(ucx_array_at_int(array, 7) == 42, "failed");
+    
+    elems = array.data;
+    UCX_TEST_ASSERT(elems[7] == 42, "failed");
     UCX_TEST_ASSERT(array.size >= 8, "array not resized on set");
     UCX_TEST_ASSERT(array.capacity == 16, "capacity changed unnecessarily");
     
     x = 13;
     ucx_array_set(&array, 27, &x);
     
-    UCX_TEST_ASSERT(ucx_array_at_int(array, 27) == 13, "failed");
+    elems = array.data;
+    UCX_TEST_ASSERT(elems[27] == 13, "failed");
     UCX_TEST_ASSERT(array.size == 28, "array not resized on set");
     UCX_TEST_ASSERT(array.capacity == 28, "capacity not grown");
     
     ucx_array_set(&array, 7, NULL);
     
-    UCX_TEST_ASSERT(ucx_array_at_int(array, 7) == 0, "not zeroed on NULL set");
+    elems = array.data;
+    UCX_TEST_ASSERT(elems[7] == 0, "not zeroed on NULL set");
     
     UCX_TEST_END
     
@@ -152,30 +166,37 @@
     UcxArray a3 = ucx_array_new(16, sizeof(long int));
     UcxArray a4 = ucx_array_new(16, sizeof(int));
     
+    int *intelems;
+    long int *longintelems;
+    
     a1.size = 5;
-    ucx_array_at_int(a1, 0) = 47;
-    ucx_array_at_int(a1, 1) = 11;
-    ucx_array_at_int(a1, 2) = 0;
-    ucx_array_at_int(a1, 3) = 8;
-    ucx_array_at_int(a1, 4) = 15;
+    intelems = a1.data;
+    intelems[0] = 47;
+    intelems[1] = 11;
+    intelems[2] = 0;
+    intelems[3] = 8;
+    intelems[4] = 15;
     a2.size = 5;
-    ucx_array_at_int(a2, 0) = 47;
-    ucx_array_at_int(a2, 1) = 11;
-    ucx_array_at_int(a2, 2) = 0;
-    ucx_array_at_int(a2, 3) = 8;
-    ucx_array_at_int(a2, 4) = 15;
+    intelems = a2.data;
+    intelems[0] = 47;
+    intelems[1] = 11;
+    intelems[2] = 0;
+    intelems[3] = 8;
+    intelems[4] = 15;
     a3.size = 5;
-    ucx_array_at_longint(a3, 0) = 47;
-    ucx_array_at_longint(a3, 1) = 11;
-    ucx_array_at_longint(a3, 2) = 0;
-    ucx_array_at_longint(a3, 3) = 8;
-    ucx_array_at_longint(a3, 4) = 15;
+    longintelems = a3.data;
+    longintelems[0] = 47;
+    longintelems[1] = 11;
+    longintelems[2] = 0;
+    longintelems[3] = 8;
+    longintelems[4] = 15;
     a4.size = 5;
-    ucx_array_at_int(a4, 0) = 47;
-    ucx_array_at_int(a4, 1) = 11;
-    ucx_array_at_int(a4, 2) = -6;
-    ucx_array_at_int(a4, 3) = 8;
-    ucx_array_at_int(a4, 4) = 15;
+    intelems = a4.data;
+    intelems[0] = 47;
+    intelems[1] = 11;
+    intelems[2] = -6;
+    intelems[3] = 8;
+    intelems[4] = 15;
     
     UCX_TEST_BEGIN
     
@@ -202,24 +223,28 @@
 UCX_TEST(test_ucx_array_concat) {
     UcxArray a1 = ucx_array_new(16, sizeof(int));
     UcxArray a2 = ucx_array_new(16, sizeof(int));
+    int *elems;
     
     a1.size = 2;
-    ucx_array_at_int(a1, 0) = 47;
-    ucx_array_at_int(a1, 1) = 11;
+    elems = a1.data;
+    elems[0] = 47;
+    elems[1] = 11;
     a2.size = 3;
-    ucx_array_at_int(a2, 0) = 0;
-    ucx_array_at_int(a2, 1) = 8;
-    ucx_array_at_int(a2, 2) = 15;
+    elems = a2.data;
+    elems[0] = 0;
+    elems[1] = 8;
+    elems[2] = 15;
     
     UCX_TEST_BEGIN
     
     UCX_TEST_ASSERT(!ucx_array_concat(&a1, &a2), "failed");
     UCX_TEST_ASSERT(a1.size == 5, "failed");
-    UCX_TEST_ASSERT(ucx_array_at_int(a1, 0) == 47, "failed");
-    UCX_TEST_ASSERT(ucx_array_at_int(a1, 1) == 11, "failed");
-    UCX_TEST_ASSERT(ucx_array_at_int(a1, 2) == 0, "failed");
-    UCX_TEST_ASSERT(ucx_array_at_int(a1, 3) == 8, "failed");
-    UCX_TEST_ASSERT(ucx_array_at_int(a1, 4) == 15, "failed");
+    elems = a1.data;
+    UCX_TEST_ASSERT(elems[0] == 47, "failed");
+    UCX_TEST_ASSERT(elems[1] == 11, "failed");
+    UCX_TEST_ASSERT(elems[2] == 0, "failed");
+    UCX_TEST_ASSERT(elems[3] == 8, "failed");
+    UCX_TEST_ASSERT(elems[4] == 15, "failed");
     
     a1.elemsize *= 2;
     UCX_TEST_ASSERT(ucx_array_concat(&a1, &a2),
@@ -232,40 +257,17 @@
     ucx_array_free(&a2);    
 }
 
-UCX_TEST(test_ucx_array_at) {
-    UcxArray array = ucx_array_new(16, sizeof(int));
-    
-    int x = 42;
-    ucx_array_append(&array, &x);
-    x = 13;
-    ucx_array_append(&array, &x);
-    x = 5;
-    ucx_array_append(&array, &x);
-    
-    UCX_TEST_BEGIN
-    
-    UCX_TEST_ASSERT(ucx_array_at_int(array, 1) == 13, "failed");
-    ucx_array_at_int(array, 1) = 80;
-    UCX_TEST_ASSERT(ucx_array_at_int(array, 1) == 80, "assignment failed");
-    
-    
-    UCX_TEST_ASSERT(ucx_array_at_int(array, 0) == 42, "corrupted data");
-    UCX_TEST_ASSERT(ucx_array_at_int(array, 2) == 5, "corrupted data");
-    
-    UCX_TEST_END
-    
-    ucx_array_free(&array);
-}
-
 UCX_TEST(test_ucx_array_find) {
     UcxArray array = ucx_array_new(16, sizeof(int));
+    int *elems;
     
     array.size = 5;
-    ucx_array_at_int(array, 0) = 47;
-    ucx_array_at_int(array, 1) = 11;
-    ucx_array_at_int(array, 2) = 0;
-    ucx_array_at_int(array, 3) = 8;
-    ucx_array_at_int(array, 4) = 15;
+    elems = array.data;
+    elems[0] = 47;
+    elems[1] = 11;
+    elems[2] = 0;
+    elems[3] = 8;
+    elems[4] = 15;
     
     int x = 8;
     int y = 90;
@@ -288,13 +290,15 @@
 
 UCX_TEST(test_ucx_array_contains) {
     UcxArray array = ucx_array_new(16, sizeof(int));
+    int *elems;
     
     array.size = 5;
-    ucx_array_at_int(array, 0) = 47;
-    ucx_array_at_int(array, 1) = 11;
-    ucx_array_at_int(array, 2) = 0;
-    ucx_array_at_int(array, 3) = 8;
-    ucx_array_at_int(array, 4) = 15;
+    elems = array.data;
+    elems[0] = 47;
+    elems[1] = 11;
+    elems[2] = 0;
+    elems[3] = 8;
+    elems[4] = 15;
     
     int x = 8;
     int y = 90;
@@ -317,30 +321,34 @@
 
 UCX_TEST(test_ucx_array_remove) {
     UcxArray array = ucx_array_new(16, sizeof(int));
+    int *elems;
     
     array.size = 5;
-    ucx_array_at_int(array, 0) = 47;
-    ucx_array_at_int(array, 1) = 11;
-    ucx_array_at_int(array, 2) = 0;
-    ucx_array_at_int(array, 3) = 8;
-    ucx_array_at_int(array, 4) = 15;
+    elems = array.data;
+    elems[0] = 47;
+    elems[1] = 11;
+    elems[2] = 0;
+    elems[3] = 8;
+    elems[4] = 15;
         
     UCX_TEST_BEGIN
     
     ucx_array_remove(&array, 2);
+    elems = array.data;
     UCX_TEST_ASSERT(
-            ucx_array_at_int(array, 0) == 47 &&
-            ucx_array_at_int(array, 1) == 11 &&
-            ucx_array_at_int(array, 2) == 8 &&
-            ucx_array_at_int(array, 3) == 15,
+            elems[0] == 47 &&
+            elems[1] == 11 &&
+            elems[2] == 8 &&
+            elems[3] == 15,
             "wrong contents after remove");
     UCX_TEST_ASSERT(array.size == 4, "wrong size after remove");
     
     ucx_array_remove_fast(&array, 1);
+    elems = array.data;
     UCX_TEST_ASSERT(
-            ucx_array_at_int(array, 0) == 47 &&
-            ucx_array_at_int(array, 1) == 15 &&
-            ucx_array_at_int(array, 2) == 8,
+            elems[0] == 47 &&
+            elems[1] == 15 &&
+            elems[2] == 8,
             "wrong contents after fast remove");
     UCX_TEST_ASSERT(array.size == 3, "wrong size after fast remove");
     
@@ -349,15 +357,16 @@
 }
 
 UCX_TEST(test_ucx_array_clone) {
-   
     UcxArray array = ucx_array_new(16, sizeof(int));
+    int *elems;
     
     array.size = 5;
-    ucx_array_at_int(array, 0) = 47;
-    ucx_array_at_int(array, 1) = 11;
-    ucx_array_at_int(array, 2) = 0;
-    ucx_array_at_int(array, 3) = 8;
-    ucx_array_at_int(array, 4) = 15;
+    elems = array.data;
+    elems[0] = 47;
+    elems[1] = 11;
+    elems[2] = 0;
+    elems[3] = 8;
+    elems[4] = 15;
     
     UcxArray copy = ucx_array_clone(array);
     UCX_TEST_BEGIN
@@ -375,22 +384,39 @@
     ucx_array_free(&copy);
 }
 
+static int ucx_cmp_int_reverse(const void* x, const void* y, void* data) {
+    return -ucx_cmp_int(x,y,data);
+}
+
 UCX_TEST(test_ucx_array_sort) {
-    UcxArray array = ucx_array_new(16, sizeof(int));
+    int *elems;
+
+    UcxArray array = ucx_array_new(16, sizeof(int));    
     array.size = 5;
-    ucx_array_at_int(array, 0) = 47;
-    ucx_array_at_int(array, 1) = 11;
-    ucx_array_at_int(array, 2) = 0;
-    ucx_array_at_int(array, 3) = 8;
-    ucx_array_at_int(array, 4) = 15;
+    elems = array.data;
+    elems[0] = 47;
+    elems[1] = 11;
+    elems[2] = 0;
+    elems[3] = 8;
+    elems[4] = 15;
     
     UcxArray expected = ucx_array_new(16, sizeof(int));
     expected.size = 5;
-    ucx_array_at_int(expected, 0) = 0;
-    ucx_array_at_int(expected, 1) = 8;
-    ucx_array_at_int(expected, 2) = 11;
-    ucx_array_at_int(expected, 3) = 15;
-    ucx_array_at_int(expected, 4) = 47;
+    elems = expected.data;
+    elems[0] = 0;
+    elems[1] = 8;
+    elems[2] = 11;
+    elems[3] = 15;
+    elems[4] = 47;
+    
+    UcxArray expectedrev = ucx_array_new(16, sizeof(int));
+    expectedrev.size = 5;
+    elems = expectedrev.data;
+    elems[0] = 47;
+    elems[1] = 15;
+    elems[2] = 11;
+    elems[3] = 8;
+    elems[4] = 0;
     
 
     UCX_TEST_BEGIN
@@ -399,16 +425,20 @@
     UCX_TEST_ASSERT(ucx_array_equals(array, expected, NULL, NULL), "failed");
     UCX_TEST_ASSERT(array.size == 5, "size corrupted");
     UCX_TEST_ASSERT(array.data == original_ptr, "shall not reallocate");
-                
+    
+    ucx_array_sort(array, ucx_cmp_int_reverse, NULL);
+    UCX_TEST_ASSERT(ucx_array_equals(array, expectedrev, NULL, NULL), "failed");
+
     ucx_array_reserve(&array, 32);
     ucx_array_reserve(&expected, 32);
     array.size = expected.size = 32;
     for (size_t i = 0 ; i < 32 ; i++) {
-        ucx_array_at_int(array, i) = ((i%2==0)?-1:1) * ((int) i);
-        ucx_array_at_int(expected, i) = (-30+2*i) - (i > 15 ? 1 : 0);
+        ((int*)array.data)[i]= ((i%2==0)?-1:1) * ((int) i);
+        ((int*)expected.data)[i] = (-30+2*i) - (i > 15 ? 1 : 0);
     }
     
-    ucx_array_sort(array, ucx_cmp_int, NULL);
+    /* dummy third argument to trigger a possible fallback for qsort_s */
+    ucx_array_sort(array, ucx_cmp_int, array.data);
     UCX_TEST_ASSERT(ucx_array_equals(array, expected, NULL, NULL),
             "failed for bigger arrays");
     UCX_TEST_END
@@ -418,10 +448,12 @@
 }
 
 UCX_TEST(test_ucx_array_autogrow) {
+    int *elems;
     UcxArray array = ucx_array_new(4, sizeof(int));
     array.size = 3;
-    ucx_array_at_int(array, 0) = 47;
-    ucx_array_at_int(array, 1) = 11;
+    elems = array.data;
+    elems[0] = 47;
+    elems[1] = 11;
     int x = 5;
     
     UCX_TEST_BEGIN
@@ -432,10 +464,10 @@
     UCX_TEST_ASSERT(array.capacity == 4 && array.data == oldptr,
             "array should not grow too early");
     ucx_array_append(&array, &x);
+    elems = array.data;
     UCX_TEST_ASSERT(array.capacity == 8, "array did not grow");
     UCX_TEST_ASSERT(array.size == 5, "incorrect size after grow");
-    UCX_TEST_ASSERT(ucx_array_at_int(array, 3) == 5 &&
-        ucx_array_at_int(array, 3) == 5, "corrupt data");
+    UCX_TEST_ASSERT(elems[3] == 5 && elems[4] == 5, "corrupt data");
     
     UCX_TEST_END
     ucx_array_free(&array);
--- a/test/array_tests.h	Thu Jul 11 10:11:43 2019 +0200
+++ b/test/array_tests.h	Tue Aug 06 16:26:46 2019 +0200
@@ -38,7 +38,6 @@
 
 UCX_TEST(test_ucx_array_free);
 UCX_TEST(test_ucx_array_new);
-UCX_TEST(test_ucx_array_at);
 UCX_TEST(test_ucx_array_append);
 UCX_TEST(test_ucx_array_prepend);
 UCX_TEST(test_ucx_array_set);
--- a/test/main.c	Thu Jul 11 10:11:43 2019 +0200
+++ b/test/main.c	Tue Aug 06 16:26:46 2019 +0200
@@ -145,7 +145,6 @@
         /* UcxArray Tests */
         ucx_test_register(suite, test_ucx_array_free);
         ucx_test_register(suite, test_ucx_array_new);
-        ucx_test_register(suite, test_ucx_array_at);
         ucx_test_register(suite, test_ucx_array_append);
         ucx_test_register(suite, test_ucx_array_prepend);
         ucx_test_register(suite, test_ucx_array_set);

mercurial