Tue, 29 Oct 2024 18:14:02 +0100
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 {