--- a/src/array_list.c Thu Nov 28 20:59:11 2024 +0100 +++ b/src/array_list.c Mon Dec 02 20:58:17 2024 +0100 @@ -30,6 +30,7 @@ #include "cx/compare.h" #include <assert.h> #include <string.h> +#include <errno.h> // Default array reallocator @@ -90,8 +91,9 @@ int cx_array_copy( void **target, - size_t *size, - size_t *capacity, + void *size, + void *capacity, + unsigned width, size_t index, const void *src, size_t elem_size, @@ -105,29 +107,64 @@ assert(src != NULL); assert(reallocator != NULL); - // determine capacity - size_t cap = *capacity; - assert(*target != NULL || cap == 0); + // 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(*target != NULL || oldcap == 0); // check if resize is required size_t minsize = index + elem_count; - size_t newsize = *size < minsize ? minsize : *size; + size_t newsize = oldsize < minsize ? minsize : oldsize; + + // check for overflow + if (newsize > max_size) { + errno = EOVERFLOW; + return 1; + } // reallocate if possible - if (newsize > cap) { + size_t newcap = oldcap; + if (newsize > oldcap) { // check, if we need to repair the src pointer uintptr_t targetaddr = (uintptr_t) *target; uintptr_t srcaddr = (uintptr_t) src; bool repairsrc = targetaddr <= srcaddr - && srcaddr < targetaddr + cap * elem_size; + && srcaddr < targetaddr + oldcap * elem_size; // calculate new capacity (next number divisible by 16) - cap = newsize - (newsize % 16) + 16; - assert(cap > newsize); + newcap = newsize - (newsize % 16) + 16; + assert(newcap > newsize); // perform reallocation void *newmem = reallocator->realloc( - *target, cap, elem_size, reallocator + *target, newcap, elem_size, reallocator ); if (newmem == NULL) { return 1; @@ -138,9 +175,8 @@ src = ((char *) newmem) + (srcaddr - targetaddr); } - // store new pointer and capacity + // store new pointer *target = newmem; - *capacity = cap; } // determine target pointer @@ -149,7 +185,26 @@ // copy elements and set new size memmove(start, src, elem_count * elem_size); - *size = newsize; + + // if any of size or capacity changed, store them back + if (newsize != oldsize || newcap != oldcap) { + if (width == 0 || width == __WORDSIZE) { + *(size_t*) capacity = newcap; + *(size_t*) size = newsize; + } else if (width == 16) { + *(uint16_t*) capacity = newcap; + *(uint16_t*) size = newsize; + } else if (width == 8) { + *(uint8_t*) capacity = newcap; + *(uint8_t*) size = newsize; + } +#if __WORDSIZE == 64 + else if (width == 32) { + *(uint32_t*) capacity = newcap; + *(uint32_t*) size = newsize; + } +#endif + } // return successfully return 0; @@ -458,6 +513,7 @@ &arl->data, &list->collection.size, &arl->capacity, + 0, start_of_moved, first_to_move, list->collection.elem_size, @@ -478,6 +534,7 @@ &arl->data, &list->collection.size, &arl->capacity, + 0, index, array, list->collection.elem_size, @@ -602,6 +659,7 @@ &arl->data, &list->collection.size, &arl->capacity, + 0, index, ((char *) arl->data) + (index + remove) * list->collection.elem_size, list->collection.elem_size,