src/array_list.c

changeset 999
84fc42b04d3b
parent 998
bb196054f3fd
child 1018
c773da859bad
--- a/src/array_list.c	Mon Dec 02 20:58:17 2024 +0100
+++ b/src/array_list.c	Thu Dec 05 01:51:47 2024 +0100
@@ -89,6 +89,96 @@
 
 // LOW LEVEL ARRAY LIST FUNCTIONS
 
+int cx_array_reserve(
+        void **array,
+        void *size,
+        void *capacity,
+        unsigned width,
+        size_t elem_size,
+        size_t elem_count,
+        CxArrayReallocator *reallocator
+) {
+    // assert pointers
+    assert(array != NULL);
+    assert(size != NULL);
+    assert(capacity != NULL);
+    assert(reallocator != NULL);
+
+    // determine size and capacity
+    size_t oldcap;
+    size_t oldsize;
+    size_t max_size;
+    if (width == 0 || width == __WORDSIZE) {
+        oldcap = *(size_t*) capacity;
+        oldsize = *(size_t*) size;
+        max_size = SIZE_MAX;
+    } else if (width == 16) {
+        oldcap = *(uint16_t*) capacity;
+        oldsize = *(uint16_t*) size;
+        max_size = UINT16_MAX;
+    } else if (width == 8) {
+        oldcap = *(uint8_t*) capacity;
+        oldsize = *(uint8_t*) size;
+        max_size = UINT8_MAX;
+    }
+#if __WORDSIZE == 64
+    else if (width == 32) {
+        oldcap = *(uint32_t*) capacity;
+        oldsize = *(uint32_t*) size;
+        max_size = UINT32_MAX;
+    }
+#endif
+    else {
+        errno = EINVAL;
+        return 1;
+    }
+
+    // assert that the array is allocated when it has capacity
+    assert(*array != NULL || oldcap == 0);
+
+    // determine new capacity
+    size_t newcap = oldsize + elem_count;
+
+    // check for overflow
+    if (newcap > max_size) {
+        errno = EOVERFLOW;
+        return 1;
+    }
+
+    // reallocate if possible
+    if (newcap > oldcap) {
+        // calculate new capacity (next number divisible by 16)
+        newcap = newcap - (newcap % 16) + 16;
+
+        // perform reallocation
+        void *newmem = reallocator->realloc(
+                *array, newcap, elem_size, reallocator
+        );
+        if (newmem == NULL) {
+            return 1;
+        }
+
+        // store new pointer
+        *array = newmem;
+
+        // store new capacity
+        if (width == 0 || width == __WORDSIZE) {
+            *(size_t*) capacity = newcap;
+        } else if (width == 16) {
+            *(uint16_t*) capacity = newcap;
+        } else if (width == 8) {
+            *(uint8_t*) capacity = newcap;
+        }
+#if __WORDSIZE == 64
+        else if (width == 32) {
+            *(uint32_t*) capacity = newcap;
+        }
+#endif
+    }
+
+    return 0;
+}
+
 int cx_array_copy(
         void **target,
         void *size,

mercurial