#219 array list: implement add and at

Wed, 16 Nov 2022 22:27:46 +0100

author
Mike Becker <universe@uap-core.de>
date
Wed, 16 Nov 2022 22:27:46 +0100
changeset 610
de5d3ee6435f
parent 609
6ae8146d9f62
child 611
77efa5163ae5

#219 array list: implement add and at

Add uses the low level cx_array_copy function which is
now also implemented, but not tested by individual unit
tests.

src/array_list.c file | annotate | diff | comparison | revisions
src/cx/array_list.h file | annotate | diff | comparison | revisions
test/test_list.cpp file | annotate | diff | comparison | revisions
--- a/src/array_list.c	Sun Nov 13 13:29:15 2022 +0100
+++ b/src/array_list.c	Wed Nov 16 22:27:46 2022 +0100
@@ -27,20 +27,91 @@
  */
 
 #include "cx/array_list.h"
+#include <assert.h>
+#include <string.h>
 
 /* LOW LEVEL ARRAY LIST FUNCTIONS */
 
+enum cx_array_coppy_result cx_array_copy(
+        void **target,
+        size_t *size,
+        size_t *capacity,
+        size_t index,
+        void const *src,
+        size_t elem_size,
+        size_t elem_count,
+        struct cx_array_reallocator_s *reallocator
+) {
+    /* assert pointers */
+    assert(target != NULL);
+    assert(size != NULL);
+    assert(src != NULL);
 
+    /* determine capacity */
+    size_t cap = capacity == NULL ? *size : *capacity;
+
+    /* check if resize is required */
+    size_t newsize = index + elem_count;
+    bool needrealloc = newsize > cap;
+
+    /* reallocate if possible */
+    if (needrealloc) {
+        /* a reallocator and a capacity variable must be available */
+        if (reallocator == NULL || capacity == NULL) {
+            return CX_ARRAY_COPY_REALLOC_NOT_SUPPORTED;
+        }
+
+        /* increase capacity linearly */
+        cap += 16;
+
+        /* perform reallocation */
+        void *newmem = reallocator->realloc(
+                *target, cap, elem_size, reallocator
+        );
+        if (newmem == NULL) {
+            return CX_ARRAY_COPY_REALLOC_FAILED;
+        }
+
+        /* store new pointer and capacity */
+        *target = newmem;
+        *capacity = cap;
+    }
+
+    /* determine target pointer */
+    char *start = *target;
+    start += index * elem_size;
+
+    /* copy elements and set new size */
+    memcpy(start, src, elem_count * elem_size);
+    *size = newsize;
+
+    /* return successfully */
+    return CX_ARRAY_COPY_SUCCESS;
+}
 
 /* HIGH LEVEL ARRAY LIST FUNCTIONS */
 
 typedef struct {
     struct cx_list_s base;
     void *data;
+    struct cx_array_reallocator_s reallocator;
 } cx_array_list;
 
+static void *cx_arl_realloc(
+        void *array,
+        size_t capacity,
+        size_t elem_size,
+        struct cx_array_reallocator_s *alloc
+) {
+    /* retrieve the pointer to the list allocator */
+    CxAllocator const *al = alloc->ptr1;
+
+    /* use the list allocator to reallocate the memory */
+    return cxRealloc(al, array, capacity * elem_size);
+}
+
 static void cx_arl_destructor(struct cx_list_s *list) {
-    cx_array_list *arl = (cx_array_list*) list;
+    cx_array_list *arl = (cx_array_list *) list;
     cxFree(list->allocator, arl->data);
 }
 
@@ -48,7 +119,17 @@
         struct cx_list_s *list,
         void const *elem
 ) {
-    return 1;
+    cx_array_list *arl = (cx_array_list *) list;
+    return cx_array_copy(
+            &arl->data,
+            &list->size,
+            &list->capacity,
+            list->size,
+            elem,
+            list->itemsize,
+            1,
+            &arl->reallocator
+    );
 }
 
 static int cx_arl_insert(
@@ -74,11 +155,17 @@
     return 1;
 }
 
-static void * cx_arl_at(
+static void *cx_arl_at(
         struct cx_list_s const *list,
         size_t index
 ) {
-    return NULL;
+    if (index < list->size) {
+        cx_array_list const *arl = (cx_array_list const *) list;
+        char *space = arl->data;
+        return space + index * list->itemsize;
+    } else {
+        return NULL;
+    }
 }
 
 static size_t cx_arl_find(
@@ -147,5 +234,9 @@
     list->base.itemsize = item_size;
     list->base.capacity = initial_capacity;
 
+    /* configure the reallocator */
+    list->reallocator.realloc = cx_arl_realloc;
+    list->reallocator.ptr1 = (void *) allocator;
+
     return (CxList *) list;
 }
--- a/src/cx/array_list.h	Sun Nov 13 13:29:15 2022 +0100
+++ b/src/cx/array_list.h	Wed Nov 16 22:27:46 2022 +0100
@@ -89,6 +89,15 @@
 };
 
 /**
+ * Return codes for cx_array_copy().
+ */
+enum cx_array_coppy_result {
+    CX_ARRAY_COPY_SUCCESS,
+    CX_ARRAY_COPY_REALLOC_NOT_SUPPORTED,
+    CX_ARRAY_COPY_REALLOC_FAILED,
+};
+
+/**
  * Copies elements from one array to another.
  *
  * The elements are copied to the \p target array at the specified \p index,
@@ -110,9 +119,9 @@
  * @param elem_count the number of elements to copy
  * @param reallocator the array re-allocator to use, or \c NULL
  * if re-allocation shall not happen
- * @return zero on success, non-zero on failure
+ * @return zero on success, non-zero error code on failure
  */
-int cx_array_copy(
+enum cx_array_coppy_result cx_array_copy(
         void **target,
         size_t *size,
         size_t *capacity,
@@ -120,7 +129,7 @@
         void const *src,
         size_t elem_size,
         size_t elem_count,
-        struct cx_array_reallocator_s const *reallocator
+        struct cx_array_reallocator_s *reallocator
 ) __attribute__((__nonnull__(1, 2, 5)));
 
 /**
--- a/test/test_list.cpp	Sun Nov 13 13:29:15 2022 +0100
+++ b/test/test_list.cpp	Wed Nov 16 22:27:46 2022 +0100
@@ -827,7 +827,6 @@
 }
 
 TEST_F(ArrayList, cxListAdd) {
-    ASSERT_EQ(1,0); // TODO: remove when implemented
     CxList *list = autofree(cxArrayListCreate(&testingAllocator, cx_cmp_int, sizeof(int), 8));
     verifyAdd(list, false);
 }
@@ -867,7 +866,6 @@
 }
 
 TEST_F(ArrayList, cxListAt) {
-    ASSERT_EQ(1,0); // TODO: remove when implemented
     verifyAt(arrayListFromTestData());
 }
 

mercurial