add function to create array reallocator that can move arrays from stack to heap

Tue, 29 Oct 2024 18:14:02 +0100

author
Mike Becker <universe@uap-core.de>
date
Tue, 29 Oct 2024 18:14:02 +0100
changeset 953
581ad4fd01e9
parent 952
dc53362bc5a7
child 954
a1d87e8fff6d

add function to create array reallocator that can move arrays from stack to heap

resolves #465

CHANGELOG file | annotate | diff | comparison | revisions
src/array_list.c file | annotate | diff | comparison | revisions
src/cx/array_list.h file | annotate | diff | comparison | revisions
--- a/CHANGELOG	Tue Oct 29 16:53:00 2024 +0100
+++ b/CHANGELOG	Tue Oct 29 18:14:02 2024 +0100
@@ -3,7 +3,7 @@
  * adds properties.h
  * adds tree.h
  * adds cxIterator() to create iterators over raw C arrays
- * adds cx_array_default_reallocator
+ * adds cx_array_reallocator() and cx_array_default_reallocator
  * adds several new array and list functions
  * adds cxBufferReset()
  * adds cx_cmp_ptr()
--- a/src/array_list.c	Tue Oct 29 16:53:00 2024 +0100
+++ b/src/array_list.c	Tue Oct 29 18:14:02 2024 +0100
@@ -37,16 +37,54 @@
         void *array,
         size_t capacity,
         size_t elem_size,
-        __attribute__((__unused__)) struct cx_array_reallocator_s *alloc
+        __attribute__((__unused__)) CxArrayReallocator *alloc
 ) {
     return realloc(array, capacity * elem_size);
 }
 
-struct cx_array_reallocator_s cx_array_default_reallocator_impl = {
+CxArrayReallocator cx_array_default_reallocator_impl = {
         cx_array_default_realloc, NULL, NULL, 0, 0
 };
 
-struct cx_array_reallocator_s *cx_array_default_reallocator = &cx_array_default_reallocator_impl;
+CxArrayReallocator *cx_array_default_reallocator = &cx_array_default_reallocator_impl;
+
+// Stack-aware array reallocator
+
+static void *cx_array_advanced_realloc(
+        void *array,
+        size_t capacity,
+        size_t elem_size,
+        __attribute__((__unused__)) CxArrayReallocator *alloc
+) {
+    // retrieve the pointer to the actual allocator
+    const CxAllocator *al = alloc->ptr1;
+
+    // check if the array is still located on the stack
+    void *newmem;
+    if (array == alloc->ptr2) {
+        newmem = cxMalloc(al, capacity * elem_size);
+        if (newmem != NULL) {
+            memcpy(newmem, array, capacity * elem_size);
+        }
+    } else {
+        newmem = cxRealloc(al, array, capacity * elem_size);
+    }
+    return newmem;
+}
+
+struct cx_array_reallocator_s cx_array_reallocator(
+        const struct cx_allocator_s *allocator,
+        const void *stackmem
+) {
+    if (allocator == NULL) {
+        allocator = cxDefaultAllocator;
+    }
+    return (struct cx_array_reallocator_s) {
+            cx_array_advanced_realloc,
+            (void*) allocator, (void*) stackmem,
+            0, 0
+    };
+}
 
 // LOW LEVEL ARRAY LIST FUNCTIONS
 
@@ -58,7 +96,7 @@
         const void *src,
         size_t elem_size,
         size_t elem_count,
-        struct cx_array_reallocator_s *reallocator
+        CxArrayReallocator *reallocator
 ) {
     // assert pointers
     assert(target != NULL);
@@ -128,7 +166,7 @@
         const void *sorted_data,
         size_t elem_size,
         size_t elem_count,
-        struct cx_array_reallocator_s *reallocator
+        CxArrayReallocator *reallocator
 ) {
     // assert pointers
     assert(target != NULL);
@@ -337,22 +375,9 @@
     struct cx_list_s base;
     void *data;
     size_t capacity;
-    struct cx_array_reallocator_s reallocator;
+    CxArrayReallocator 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
-    const CxAllocator *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;
 
@@ -783,8 +808,7 @@
     }
 
     // configure the reallocator
-    list->reallocator.realloc = cx_arl_realloc;
-    list->reallocator.ptr1 = (void *) allocator;
+    list->reallocator = cx_array_reallocator(allocator, NULL);
 
     return (CxList *) list;
 }
--- a/src/cx/array_list.h	Tue Oct 29 16:53:00 2024 +0100
+++ b/src/cx/array_list.h	Tue Oct 29 18:14:02 2024 +0100
@@ -120,11 +120,36 @@
 };
 
 /**
+ * Typedef for the array reallocator struct.
+ */
+typedef struct cx_array_reallocator_s CxArrayReallocator;
+
+/**
  * A default stdlib-based array reallocator.
  */
 extern struct cx_array_reallocator_s *cx_array_default_reallocator;
 
 /**
+ * Creates a new array reallocator.
+ *
+ * When \p allocator is \c NULL, the stdlib default allocator will be used.
+ *
+ * When \p stackmem is not \c NULL, the reallocator is supposed to be used
+ * \em only for the specific array that is initially located at \p stackmem.
+ * When reallocation is needed, the reallocator checks, if the array is
+ * still located at \p stackmem and copies the contents to the heap.
+ *
+ * @param allocator the allocator this reallocator shall be based on
+ * @param stackmem the address of the array when the array is initially located
+ * on the stack
+ * @return an array reallocator
+ */
+struct cx_array_reallocator_s cx_array_reallocator(
+        const struct cx_allocator_s *allocator,
+        const void *stackmem
+);
+
+/**
  * Return codes for array functions.
  */
 enum cx_array_result {

mercurial