Mon, 15 Dec 2025 19:00:51 +0100
complete refactoring of low-level array list functions - relates to #619
now only the documentation needs to be updated
| src/array_list.c | file | annotate | diff | comparison | revisions | |
| src/cx/array_list.h | file | annotate | diff | comparison | revisions | |
| src/json.c | file | annotate | diff | comparison | revisions | |
| tests/test_list.c | file | annotate | diff | comparison | revisions |
--- a/src/array_list.c Sun Dec 14 23:17:48 2025 +0100 +++ b/src/array_list.c Mon Dec 15 19:00:51 2025 +0100 @@ -58,86 +58,25 @@ return cap - (cap % alignment) + alignment; } -// Default array reallocator - -static void *cx_array_default_realloc( - void *array, - cx_attr_unused size_t old_capacity, - size_t new_capacity, - size_t elem_size, - cx_attr_unused CxArrayReallocator *alloc -) { - size_t n; - // LCOV_EXCL_START - if (cx_szmul(new_capacity, elem_size, &n)) { - errno = EOVERFLOW; - return NULL; - } // LCOV_EXCL_STOP - return cxReallocDefault(array, n); -} - -CxArrayReallocator cx_array_default_reallocator_impl = { - cx_array_default_realloc, NULL, NULL -}; - -CxArrayReallocator *cx_array_default_reallocator = &cx_array_default_reallocator_impl; - -// Stack-aware array reallocator - -static void *cx_array_advanced_realloc( - void *array, - size_t old_capacity, - size_t new_capacity, - size_t elem_size, - cx_attr_unused CxArrayReallocator *alloc -) { - // check for overflow - size_t n; - // LCOV_EXCL_START - if (cx_szmul(new_capacity, elem_size, &n)) { - errno = EOVERFLOW; - return NULL; - } // LCOV_EXCL_STOP - - // retrieve the pointer to the actual allocator - const CxAllocator *al = alloc->allocator; - - // check if the array is still located on the stack - void *newmem; - if (array == alloc->stack_ptr) { - newmem = cxMalloc(al, n); - if (newmem != NULL && array != NULL) { - memcpy(newmem, array, old_capacity*elem_size); - } - } else { - newmem = cxRealloc(al, array, n); - } - return newmem; -} - -struct cx_array_reallocator_s cx_array_reallocator( - const struct cx_allocator_s *allocator, - const void *stack_ptr -) { - if (allocator == NULL) { - allocator = cxDefaultAllocator; - } - return (struct cx_array_reallocator_s) { - cx_array_advanced_realloc, - allocator, stack_ptr, - }; -} - int cx_array_init_(const CxAllocator *allocator, CxArray *array, size_t elem_size, size_t capacity) { memset(array, 0, sizeof(CxArray)); return cx_array_reserve_(allocator, array, elem_size, capacity); } +void cx_array_init_fixed_(CxArray *array, const void *data, size_t capacity, size_t size) { + array->data = (void*) data; + array->capacity = capacity; + array->size = size; +} + int cx_array_reserve_(const CxAllocator *allocator, CxArray *array, size_t elem_size, size_t capacity) { if (cxReallocateArray(allocator, &array->data, capacity, elem_size)) { return -1; // LCOV_EXCL_LINE } array->capacity = capacity; + if (array->size > capacity) { + array->size = capacity; + } return 0; } @@ -152,22 +91,7 @@ return 0; } -int cx_array_add_(const CxAllocator *allocator, CxArray *array, size_t elem_size, void *element) { - if (array->size >= array->capacity) { - size_t newcap = cx_array_grow_capacity(array->capacity, array->capacity + 1); - if (cxReallocateArray(allocator, &array->data, newcap, elem_size)) { - return -1; - } - array->capacity = newcap; - } - char *dst = array->data; - dst += elem_size * array->size; - memcpy(dst, element, elem_size); - array->size++; - return 0; -} - -int cx_array_insert_array_(const CxAllocator *allocator, CxArray *array, +int cx_array_insert_(const CxAllocator *allocator, CxArray *array, size_t elem_size, size_t index, const void *other, size_t n) { // out of bounds and special case check if (index > array->size) return -1; @@ -183,224 +107,74 @@ } // determine insert position - char *arl_data = array->data; - char *insert_pos = arl_data + index * elem_size; + char *dst = array->data; + dst += index * elem_size; // do we need to move some elements? if (index < array->size) { size_t elems_to_move = array->size - index; - char *target = insert_pos + n * elem_size; - memmove(target, insert_pos, elems_to_move * elem_size); + char *target = dst + n * elem_size; + memmove(target, dst, elems_to_move * elem_size); } // place the new elements, if any // otherwise, this function just reserved the memory (a.k.a emplace) if (other != NULL) { - memcpy(insert_pos, other, n * elem_size); + memcpy(dst, other, n * elem_size); } array->size += n; return 0; } -CxIterator cx_array_iterator_(CxArray *array, size_t elem_size) { - return cxIterator(array->data, elem_size, array->size); -} - -CxIterator cx_array_iterator_ptr_(CxArray *array) { - return cxIteratorPtr(array->data, array->size); -} - -void cx_array_free_(const CxAllocator *allocator, CxArray *array) { - cxFree(allocator, array->data); - array->data = NULL; - array->size = array->capacity = 0; -} - -int cx_array_copy( - void **target, - void *size, - void *capacity, - unsigned width, - size_t index, - const void *src, +int cx_array_insert_sorted_( + const CxAllocator *allocator, + CxArray *array, size_t elem_size, - size_t elem_count, - CxArrayReallocator *reallocator -) { - // assert pointers - assert(target != NULL); - assert(size != NULL); - assert(capacity != NULL); - assert(src != NULL); - - // default reallocator - if (reallocator == NULL) { - reallocator = cx_array_default_reallocator; - } - - // determine size and capacity - size_t oldcap; - size_t oldsize; - size_t max_size; - if (width == 0 || width == sizeof(size_t)) { - oldcap = *(size_t*) capacity; - oldsize = *(size_t*) size; - max_size = SIZE_MAX; - } else if (width == sizeof(uint16_t)) { - oldcap = *(uint16_t*) capacity; - oldsize = *(uint16_t*) size; - max_size = UINT16_MAX; - } else if (width == sizeof(uint8_t)) { - oldcap = *(uint8_t*) capacity; - oldsize = *(uint8_t*) size; - max_size = UINT8_MAX; - } -#if CX_WORDSIZE == 64 - else if (width == sizeof(uint32_t)) { - 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 for overflow - if (index > max_size || elem_count > max_size - index) { - errno = EOVERFLOW; - return 1; - } - - // check if resize is required - const size_t minsize = index + elem_count; - const size_t newsize = oldsize < minsize ? minsize : oldsize; - - // reallocate if necessary - const size_t newcap = cx_array_grow_capacity(oldcap, newsize); - if (newcap > 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 + oldcap * elem_size; - - // perform reallocation - void *newmem = reallocator->realloc( - *target, oldcap, newcap, elem_size, reallocator - ); - if (newmem == NULL) { - return 1; // LCOV_EXCL_LINE - } - - // repair src pointer, if necessary - if (repairsrc) { - src = ((char *) newmem) + (srcaddr - targetaddr); - } - - // store new pointer - *target = newmem; - } - - // determine target pointer - char *start = *target; - start += index * elem_size; - - // copy elements and set new size - // note: no overflow check here, b/c we cannot get here w/o allocation - memmove(start, src, elem_count * elem_size); - - // if any of size or capacity changed, store them back - if (newsize != oldsize || newcap != oldcap) { - if (width == 0 || width == sizeof(size_t)) { - *(size_t*) capacity = newcap; - *(size_t*) size = newsize; - } else if (width == sizeof(uint16_t)) { - *(uint16_t*) capacity = (uint16_t) newcap; - *(uint16_t*) size = (uint16_t) newsize; - } else if (width == sizeof(uint8_t)) { - *(uint8_t*) capacity = (uint8_t) newcap; - *(uint8_t*) size = (uint8_t) newsize; - } -#if CX_WORDSIZE == 64 - else if (width == sizeof(uint32_t)) { - *(uint32_t*) capacity = (uint32_t) newcap; - *(uint32_t*) size = (uint32_t) newsize; - } -#endif - } - - // return successfully - return 0; -} - -static int cx_array_insert_sorted_impl( - void **target, - size_t *size, - size_t *capacity, cx_compare_func cmp_func, const void *sorted_data, - size_t elem_size, - size_t elem_count, - CxArrayReallocator *reallocator, + size_t n, bool allow_duplicates ) { // assert pointers - assert(target != NULL); - assert(size != NULL); - assert(capacity != NULL); + assert(allocator != NULL); + assert(array != NULL); assert(cmp_func != NULL); assert(sorted_data != NULL); - // default reallocator - if (reallocator == NULL) { - reallocator = cx_array_default_reallocator; - } - // corner case - if (elem_count == 0) return 0; + if (n == 0) return 0; // overflow check // LCOV_EXCL_START - if (elem_count > SIZE_MAX - *size) { + if (n > SIZE_MAX - array->size) { errno = EOVERFLOW; return 1; } // LCOV_EXCL_STOP // store some counts - const size_t old_size = *size; - const size_t old_capacity = *capacity; + const size_t old_size = array->size; + const size_t old_capacity = array->capacity; // the necessary capacity is the worst case assumption, including duplicates - const size_t needed_capacity = cx_array_grow_capacity(old_capacity, old_size + elem_count); + const size_t needed_capacity = cx_array_grow_capacity(old_capacity, old_size + n); // if we need more than we have, try a reallocation if (needed_capacity > old_capacity) { - void *new_mem = reallocator->realloc( - *target, old_capacity, needed_capacity, elem_size, reallocator - ); - if (new_mem == NULL) { - // give it up right away, there is no contract - // that requires us to insert as much as we can - return 1; // LCOV_EXCL_LINE + if (cxReallocateArray(allocator, &array->data, needed_capacity, elem_size)) { + return -1; // LCOV_EXCL_LINE } - *target = new_mem; - *capacity = needed_capacity; + array->capacity = needed_capacity; } // now we have guaranteed that we can insert everything - size_t new_size = old_size + elem_count; - *size = new_size; + size_t new_size = old_size + n; + array->size = new_size; // declare the source and destination indices/pointers size_t si = 0, di = 0; const char *src = sorted_data; - char *dest = *target; + char *dest = array->data; // find the first insertion point di = cx_array_binary_search_sup(dest, old_size, elem_size, src, cmp_func); @@ -410,12 +184,12 @@ // we will call it the "buffer" for parked elements size_t buf_size = old_size - di; size_t bi = new_size - buf_size; - char *bptr = ((char *) *target) + bi * elem_size; + char *bptr = ((char *) array->data) + bi * elem_size; memmove(bptr, dest, buf_size * elem_size); // while there are both source and buffered elements left, // copy them interleaving - while (si < elem_count && bi < new_size) { + while (si < n && bi < new_size) { // determine how many source elements can be inserted. // the first element that shall not be inserted is the smallest element // that is strictly larger than the first buffered element @@ -430,7 +204,7 @@ // than any element in the source and the infimum exists. size_t copy_len, bytes_copied; copy_len = cx_array_binary_search_inf( - src, elem_count - si, elem_size, bptr, cmp_func + src, n - si, elem_size, bptr, cmp_func ); copy_len++; @@ -454,7 +228,7 @@ skip_len++; copy_len--; } - char *last = dest == *target ? NULL : dest - elem_size; + char *last = dest == array->data ? NULL : dest - elem_size; // then iterate through the source chunk // and skip all duplicates with the last element in the array size_t more_skipped = 0; @@ -478,12 +252,12 @@ si += skip_len; skip_len += more_skipped; // reduce the actual size by the number of skipped elements - *size -= skip_len; + array->size -= skip_len; } } // when all source elements are in place, we are done - if (si >= elem_count) break; + if (si >= n) break; // determine how many buffered elements need to be restored copy_len = cx_array_binary_search_sup( @@ -504,22 +278,22 @@ } // still source elements left? - if (si < elem_count) { + if (si < n) { if (allow_duplicates) { // duplicates allowed or nothing inserted yet: simply copy everything - memcpy(dest, src, elem_size * (elem_count - si)); + memcpy(dest, src, elem_size * (n - si)); } else { // we must check the remaining source elements one by one // to skip the duplicates. // Note that no source element can equal the last element in the // destination, because that would have created an insertion point // and a buffer, s.t. the above loop already handled the duplicates - while (si < elem_count) { + while (si < n) { // find a chain of elements that can be copied size_t copy_len = 1, skip_len = 0; { const char *left_src = src; - while (si + copy_len + skip_len < elem_count) { + while (si + copy_len + skip_len < n) { const char *right_src = left_src + elem_size; int d = cmp_func(left_src, right_src); if (d < 0) { @@ -544,13 +318,13 @@ src += bytes_copied + skip_len * elem_size; si += copy_len + skip_len; di += copy_len; - *size -= skip_len; + array->size -= skip_len; } } } // buffered elements need to be moved when we skipped duplicates - size_t total_skipped = new_size - *size; + size_t total_skipped = new_size - array->size; if (bi < new_size && total_skipped > 0) { // move the remaining buffer to the end of the array memmove(dest, bptr, elem_size * (new_size - bi)); @@ -559,34 +333,21 @@ return 0; } -int cx_array_insert_sorted( - void **target, - size_t *size, - size_t *capacity, - cx_compare_func cmp_func, - const void *sorted_data, - size_t elem_size, - size_t elem_count, - CxArrayReallocator *reallocator -) { - return cx_array_insert_sorted_impl(target, size, capacity, - cmp_func, sorted_data, elem_size, elem_count, reallocator, true); +CxIterator cx_array_iterator_(CxArray *array, size_t elem_size) { + return cxIterator(array->data, elem_size, array->size); } -int cx_array_insert_unique( - void **target, - size_t *size, - size_t *capacity, - cx_compare_func cmp_func, - const void *sorted_data, - size_t elem_size, - size_t elem_count, - CxArrayReallocator *reallocator -) { - return cx_array_insert_sorted_impl(target, size, capacity, - cmp_func, sorted_data, elem_size, elem_count, reallocator, false); +CxIterator cx_array_iterator_ptr_(CxArray *array) { + return cxIteratorPtr(array->data, array->size); } +void cx_array_free_(const CxAllocator *allocator, CxArray *array) { + cxFree(allocator, array->data); + array->data = NULL; + array->size = array->capacity = 0; +} + + // implementation that finds ANY index static size_t cx_array_binary_search_inf_impl( const void *arr, @@ -762,7 +523,6 @@ struct cx_list_s base; void *data; size_t capacity; - CxArrayReallocator reallocator; } cx_array_list; static void cx_arl_destructor(struct cx_list_s *list) { @@ -797,8 +557,8 @@ CxArray wrap = { arl->data, list->collection.size, arl->capacity }; - if (cx_array_insert_array_(list->collection.allocator, &wrap, - list->collection.elem_size, index, array, n)) { + if (cx_array_insert_(list->collection.allocator, &wrap, + list->collection.elem_size, index, array, n)) { return 0; } arl->data = wrap.data; @@ -807,29 +567,41 @@ return n; } +static size_t cx_arl_insert_sorted_impl( + struct cx_list_s *list, + const void *sorted_data, + size_t n, + bool allow_duplicates +) { + cx_array_list *arl = (cx_array_list *) list; + CxArray wrap = { + arl->data, list->collection.size, arl->capacity + }; + + if (cx_array_insert_sorted_( + list->collection.allocator, + &wrap, + list->collection.elem_size, + list->collection.cmpfunc, + sorted_data, + n, + allow_duplicates + )) { + // array list implementation is "all or nothing" + return 0; // LCOV_EXCL_LINE + } + arl->data = wrap.data; + arl->capacity = wrap.capacity; + list->collection.size = wrap.size; + return n; +} + static size_t cx_arl_insert_sorted( struct cx_list_s *list, const void *sorted_data, size_t n ) { - // get a correctly typed pointer to the list - cx_array_list *arl = (cx_array_list *) list; - - if (cx_array_insert_sorted( - &arl->data, - &list->collection.size, - &arl->capacity, - list->collection.cmpfunc, - sorted_data, - list->collection.elem_size, - n, - &arl->reallocator - )) { - // array list implementation is "all or nothing" - return 0; // LCOV_EXCL_LINE - } else { - return n; - } + return cx_arl_insert_sorted_impl(list, sorted_data, n, true); } static size_t cx_arl_insert_unique( @@ -837,24 +609,7 @@ const void *sorted_data, size_t n ) { - // get a correctly typed pointer to the list - cx_array_list *arl = (cx_array_list *) list; - - if (cx_array_insert_unique( - &arl->data, - &list->collection.size, - &arl->capacity, - list->collection.cmpfunc, - sorted_data, - list->collection.elem_size, - n, - &arl->reallocator - )) { - // array list implementation is "all or nothing" - return 0; // LCOV_EXCL_LINE - } else { - return n; - } + return cx_arl_insert_sorted_impl(list, sorted_data, n, false); } static void *cx_arl_insert_element( @@ -933,24 +688,21 @@ ); } + // calculate how many elements would need to be moved + size_t remaining = list->collection.size - index - remove; + // short-circuit removal of last elements - if (index + remove == list->collection.size) { + if (remaining == 0) { list->collection.size -= remove; return remove; } // just move the elements to the left - cx_array_copy( - &arl->data, - &list->collection.size, - &arl->capacity, - 0, - index, - ((char *) arl->data) + (index + remove) * list->collection.elem_size, - list->collection.elem_size, - list->collection.size - index - remove, - &arl->reallocator - ); + char *first_remaining = arl->data; + first_remaining += (index + remove) * list->collection.elem_size; + char *dst_move = arl->data; + dst_move += index * list->collection.elem_size; + memmove(dst_move, first_remaining, remaining * list->collection.elem_size); // decrease the size list->collection.size -= remove; @@ -1195,8 +947,5 @@ return NULL; } // LCOV_EXCL_STOP - // configure the reallocator - list->reallocator = cx_array_reallocator(allocator, NULL); - return (CxList *) list; }
--- a/src/cx/array_list.h Sun Dec 14 23:17:48 2025 +0100 +++ b/src/cx/array_list.h Mon Dec 15 19:00:51 2025 +0100 @@ -65,46 +65,77 @@ cx_attr_nonnull CX_EXPORT int cx_array_init_(const CxAllocator *allocator, CxArray *array, size_t elem_size, size_t capacity); -#define cx_array_init(array, capacity) cx_array_init_(cxDefaultAllocator, (CxArray*)&(array), sizeof((array).data[0]), capacity) +#define cx_array_init_a(allocator, array, capacity) cx_array_init_(allocator, (CxArray*)&(array), sizeof((array).data[0]), capacity) + +#define cx_array_init(array, capacity) cx_array_init_a(cxDefaultAllocator, array, capacity) -#define cx_array_init_a(allocator, array, capacity) cx_array_init_(allocator, (CxArray*)&(array), sizeof((array).data[0]), capacity) +cx_attr_nonnull +CX_EXPORT void cx_array_init_fixed_(CxArray *array, const void *data, size_t capacity, size_t size); + +#define cx_array_init_fixed(array, fixed_size_array, num_initialized) cx_array_init_fixed_((CxArray*)&(array), fixed_size_array, cx_nmemb(fixed_size_array), num_initialized) cx_attr_nonnull CX_EXPORT int cx_array_reserve_(const CxAllocator *allocator, CxArray *array, size_t elem_size, size_t capacity); -#define cx_array_reserve(array, capacity) cx_array_reserve_(cxDefaultAllocator, (CxArray*)&(array), sizeof((array).data[0]), capacity) +#define cx_array_reserve_a(allocator, array, capacity) cx_array_reserve_(allocator, (CxArray*)&(array), sizeof((array).data[0]), capacity) -#define cx_array_reserve_a(allocator, array, capacity) cx_array_reserve_(allocator, (CxArray*)&(array), sizeof((array).data[0]), capacity) +#define cx_array_reserve(array, capacity) cx_array_reserve_a(cxDefaultAllocator, array, capacity) cx_attr_nonnull CX_EXPORT int cx_array_move_to_new_(const CxAllocator *allocator, CxArray *array, size_t elem_size, size_t capacity); -#define cx_array_move_to_new(array, capacity) cx_array_move_to_new_(cxDefaultAllocator, (CxArray*)&(array), sizeof((array).data[0]), capacity) - #define cx_array_move_to_new_a(allocator, array, capacity) cx_array_move_to_new_(allocator, (CxArray*)&(array), sizeof((array).data[0]), capacity) -cx_attr_nonnull -CX_EXPORT int cx_array_add_(const CxAllocator *allocator, CxArray *array, size_t elem_size, void *element); - -#define cx_array_add(array, element) cx_array_add_(cxDefaultAllocator, (CxArray*)&(array), sizeof((array).data[0]), element) - -#define cx_array_add_a(allocator, array, element) cx_array_add_(allocator, (CxArray*)&(array), sizeof((array).data[0]), element) +#define cx_array_move_to_new(array, capacity) cx_array_move_to_new_a(cxDefaultAllocator, array, capacity) cx_attr_nonnull_arg(1, 2) -CX_EXPORT int cx_array_insert_array_(const CxAllocator *allocator, CxArray *array, +CX_EXPORT int cx_array_insert_(const CxAllocator *allocator, CxArray *array, size_t elem_size, size_t index, const void *other, size_t n); -#define cx_array_insert_array(array, index, other, n) \ - cx_array_insert_array_(cxDefaultAllocator, (CxArray*)&(array), sizeof((array).data[0]), index, other, n) +#define cx_array_add_a(allocator, array, element) \ + cx_array_insert_(allocator, (CxArray*)&(array), sizeof((array).data[0]), (array).size, element, 1) + +#define cx_array_add(array, element) cx_array_add_a(cxDefaultAllocator, array, element) + +#define cx_array_insert_a(allocator, array, index, element) \ + cx_array_insert_(allocator, (CxArray*)&(array), sizeof((array).data[0]), index, element, 1) + +#define cx_array_insert(array, index, element) cx_array_insert_a(cxDefaultAllocator, array, index, element) #define cx_array_insert_array_a(allocator, array, index, other, n) \ - cx_array_insert_array_(allocator, (CxArray*)&(array), sizeof((array).data[0]), index, other, n) + cx_array_insert_(allocator, (CxArray*)&(array), sizeof((array).data[0]), index, other, n) -#define cx_array_add_array(array, other, n) \ - cx_array_insert_array_(cxDefaultAllocator, (CxArray*)&(array), sizeof((array).data[0]), (array).size, other, n) +#define cx_array_insert_array(array, index, other, n) cx_array_insert_array_a(cxDefaultAllocator, array, index, other, n) #define cx_array_add_array_a(allocator, array, other, n) \ - cx_array_insert_array_(allocator, (CxArray*)&(array), sizeof((array).data[0]), (array).size, other, n) + cx_array_insert_(allocator, (CxArray*)&(array), sizeof((array).data[0]), (array).size, other, n) + +#define cx_array_add_array(array, other, n) cx_array_add_array_a(cxDefaultAllocator, array, other, n) + +cx_attr_nonnull +CX_EXPORT int cx_array_insert_sorted_(const CxAllocator *allocator, CxArray *array, + size_t elem_size, cx_compare_func cmp_func, const void *sorted_data, size_t n, + bool allow_duplicates); + +#define cx_array_insert_sorted_a(allocator, array, cmp_func, element) \ + cx_array_insert_sorted_(allocator, (CxArray*)&(array), sizeof((array).data[0]), cmp_func, element, 1, true) + +#define cx_array_insert_sorted(array, cmp_func, element) cx_array_insert_sorted_a(cxDefaultAllocator, array, cmp_func, element) + +#define cx_array_insert_sorted_array_a(allocator, array, cmp_func, sorted_data, n) \ + cx_array_insert_sorted_(allocator, (CxArray*)&(array), sizeof((array).data[0]), cmp_func, sorted_data, n, true) + +#define cx_array_insert_sorted_array(array, cmp_func, sorted_data, n) cx_array_insert_sorted_array_a(cxDefaultAllocator, array, cmp_func, sorted_data, n) + +#define cx_array_insert_unique_a(allocator, array, cmp_func, element) \ + cx_array_insert_sorted_(allocator, (CxArray*)&(array), sizeof((array).data[0]), cmp_func, element, 1, false) + +#define cx_array_insert_unique(array, cmp_func, element) cx_array_insert_unique_a(cxDefaultAllocator, array, cmp_func, element) + +#define cx_array_insert_unique_array_a(allocator, array, cmp_func, sorted_data, n) \ + cx_array_insert_sorted_(allocator, (CxArray*)&(array), sizeof((array).data[0]), cmp_func, sorted_data, n, false) + +#define cx_array_insert_unique_array(array, cmp_func, sorted_data, n) cx_array_insert_unique_array_a(cxDefaultAllocator, array, cmp_func, sorted_data, n) cx_attr_nodiscard cx_attr_nonnull CX_EXPORT CxIterator cx_array_iterator_(CxArray *array, size_t elem_size); @@ -123,496 +154,7 @@ #define cx_array_free_a(allocator, array) cx_array_free_(allocator, (CxArray*)&(array)) -/** - * Declares variables for an array that can be used with the convenience macros. - * - * @par Examples - * @code - * // integer array with at most 255 elements - * CX_ARRAY_DECLARE_SIZED(int, myarray, uint8_t) - * - * // array of MyObject* pointers where size and capacity are stored as unsigned int - * CX_ARRAY_DECLARE_SIZED(MyObject*, objects, unsigned int) - * - * // initializing code - * cx_array_initialize(myarray, 16); // reserve space for 16 - * cx_array_initialize(objects, 100); // reserve space for 100 - * @endcode - * - * @param type the type of the data - * @param name the name of the array - * @param size_type the type of the size (should be uint8_t, uint16_t, uint32_t, or size_t) - * - * @see cx_array_initialize() - * @see cx_array_simple_copy() - * @see cx_array_simple_add_sorted() - * @see cx_array_simple_insert_sorted() - */ -#define CX_ARRAY_DECLARE_SIZED(type, name, size_type) \ - type * name; \ - /** Array size. */ size_type name##_size; \ - /** Array capacity. */ size_type name##_capacity -/** - * Declares variables for an array that can be used with the convenience macros. - * - * The size and capacity variables will have type @c size_t. - * Use #CX_ARRAY_DECLARE_SIZED() to specify a different type. - * - * @par Examples - * @code - * // int array - * CX_ARRAY_DECLARE(int, myarray) - * - * // initializing code - * cx_array_initialize(myarray, 32); // reserve space for 32 - * @endcode - * - * @param type the type of the data - * @param name the name of the array - * - * @see cx_array_initialize() - * @see cx_array_simple_copy() - * @see cx_array_simple_add_sorted() - * @see cx_array_simple_insert_sorted() - */ -#define CX_ARRAY_DECLARE(type, name) CX_ARRAY_DECLARE_SIZED(type, name, size_t) - -/** - * Initializes an array with the given capacity. - * - * The type of the capacity depends on the type used during declaration. - * - * @par Examples - * @code - * CX_ARRAY_DECLARE_SIZED(int, arr1, uint8_t) - * CX_ARRAY_DECLARE(int, arr2) // size and capacity are implicitly size_t - * - * // initializing code - * cx_array_initialize(arr1, 500); // error: maximum for uint8_t is 255 - * cx_array_initialize(arr2, 500); // OK - * @endcode - * - * - * The memory for the array is allocated with the cxDefaultAllocator. - * - * @param array the name of the array - * @param capacity the initial capacity - * @see cx_array_initialize_a() - * @see CX_ARRAY_DECLARE_SIZED() - * @see CX_ARRAY_DECLARE() - */ -#define cx_array_initialize(array, capacity) \ - array##_capacity = capacity; \ - array##_size = 0; \ - array = cxMallocDefault(sizeof(array[0]) * capacity) - -/** - * Initializes an array with the given capacity using the specified allocator. - * - * @par Example - * @code - * CX_ARRAY_DECLARE(int, myarray) - * - * - * const CxAllocator *al = // ... - * cx_array_initialize_a(al, myarray, 128); - * // ... - * cxFree(al, myarray); // remember to free with the same allocator - * @endcode - * - * @param allocator (@c CxAllocator*) the allocator - * @param array the name of the array - * @param capacity the initial capacity - * @see cx_array_initialize() - * @see CX_ARRAY_DECLARE_SIZED() - * @see CX_ARRAY_DECLARE() - */ -#define cx_array_initialize_a(allocator, array, capacity) \ - array##_capacity = capacity; \ - array##_size = 0; \ - array = cxMalloc(allocator, sizeof(array[0]) * capacity) - -/** - * Defines a reallocation mechanism for arrays. - * You can create your own, use cx_array_reallocator(), or - * use the #cx_array_default_reallocator. - */ -struct cx_array_reallocator_s { - /** - * Reallocates space for the given array. - * - * Implementations are not required to free the original array. - * This allows reallocation of static or stack memory by allocating heap memory - * and copying the array contents; namely when @c stack_ptr in this struct - * is not @c NULL and @p array equals @c stack_ptr. - * - * @param array the array to reallocate - * @param old_capacity the old number of elements - * @param new_capacity the new number of elements - * @param elem_size the size of each element - * @param alloc a reference to this allocator - * @return a pointer to the reallocated memory or @c NULL on failure - */ - void *(*realloc)( void *array, size_t old_capacity, size_t new_capacity, - size_t elem_size, struct cx_array_reallocator_s *alloc); - - /** - * The allocator that shall be used for the reallocations. - */ - const CxAllocator *allocator; - /** - * Optional pointer to stack memory - * if the array is originally located on the stack. - */ - const void *stack_ptr; -}; - -/** - * Typedef for the array reallocator struct. - */ -typedef struct cx_array_reallocator_s CxArrayReallocator; - -/** - * A default array reallocator that is based on the cxDefaultAllocator. - */ -CX_EXPORT extern CxArrayReallocator *cx_array_default_reallocator; - -/** - * Creates a new array reallocator. - * - * When @p allocator is @c NULL, the cxDefaultAllocator will be used. - * - * When @p stack_ptr is not @c NULL, the reallocator is supposed to be used - * @em only for the specific array initially located at @p stack_ptr. - * When reallocation is needed, the reallocator checks if the array is - * still located at @p stack_ptr and copies the contents to the heap. - * - * @note Invoking this function with both arguments being @c NULL will return a - * reallocator that behaves like #cx_array_default_reallocator. - * - * @param allocator the allocator this reallocator shall be based on - * @param stack_ptr the address of the array when the array is initially located - * on the stack or shall not reallocate in place - * @return an array reallocator - */ -CX_EXPORT CxArrayReallocator cx_array_reallocator( - const struct cx_allocator_s *allocator, const void *stack_ptr); -/** - * Copies elements from one array to another. - * - * The elements are copied to the @p target array at the specified @p index, - * overwriting possible elements. The @p index does not need to be in range of - * the current array @p size. If the new index plus the number of elements added - * extends the array's size, the remaining @p capacity is used. - * - * If the @p capacity is also insufficient to hold the new data, a reallocation - * attempt is made with the specified @p reallocator. - * You can create your own reallocator by hand, use #cx_array_default_reallocator, - * or use the convenience function cx_array_reallocator() to create a custom reallocator. - * - * The @p width in bytes refers to the size and capacity. - * Both must have the same width. - * Supported are 0, 1, 2, and 4, as well as 8 if running on a 64-bit - * architecture. If set to zero, the native word width is used. - * - * @note When this function does reallocate the array, it may allocate more - * space than required to avoid further allocations in the near future. - * - * @param target a pointer to the target array - * @param size a pointer to the size of the target array - * @param capacity a pointer to the capacity of the target array - * @param width the width in bytes for the @p size and @p capacity or zero for default - * @param index the index where the copied elements shall be placed - * @param src the source array - * @param elem_size the size of one element - * @param elem_count the number of elements to copy - * @param reallocator the array reallocator to use - * (@c NULL defaults to #cx_array_default_reallocator) - * @retval zero success - * @retval non-zero failure - * @see cx_array_reallocator() - */ -cx_attr_nonnull_arg(1, 2, 3, 6) -CX_EXPORT int cx_array_copy(void **target, void *size, void *capacity, unsigned width, - size_t index, const void *src, size_t elem_size, size_t elem_count, - CxArrayReallocator *reallocator); - -/** - * Convenience macro that uses cx_array_copy() with a default layout and - * the specified reallocator. - * - * @param reallocator (@c CxArrayReallocator*) the array reallocator to use - * @param array the name of the array (NOT a pointer or alias to the array) - * @param index (@c size_t) the index where the copied elements shall be placed - * @param src (@c void*) the source array - * @param count (@c size_t) the number of elements to copy - * @retval zero success - * @retval non-zero failure - * @see CX_ARRAY_DECLARE() - * @see cx_array_simple_copy() - */ -#define cx_array_simple_copy_a(reallocator, array, index, src, count) \ - cx_array_copy((void**)&(array), &(array##_size), &(array##_capacity), \ - sizeof(array##_size), index, src, sizeof((array)[0]), count, \ - reallocator) - -/** - * Convenience macro that uses cx_array_copy() with a default layout and - * the default reallocator. - * - * @param array the name of the array (NOT a pointer or alias to the array) - * @param index (@c size_t) the index where the copied elements shall be placed - * @param src (@c void*) the source array - * @param count (@c size_t) the number of elements to copy - * @retval zero success - * @retval non-zero failure - * @see CX_ARRAY_DECLARE() - * @see cx_array_simple_copy_a() - */ -#define cx_array_simple_copy(array, index, src, count) \ - cx_array_simple_copy_a(NULL, array, index, src, count) - -/** - * Inserts a sorted array into another sorted array. - * - * If either the target or the source array is not already sorted with respect - * to the specified @p cmp_func, the behavior is undefined. - * - * If the capacity is insufficient to hold the new data, a reallocation - * attempt is made. - * You can create your own reallocator by hand, use #cx_array_default_reallocator, - * or use the convenience function cx_array_reallocator() to create a custom reallocator. - * - * @param target a pointer to the target array - * @param size a pointer to the size of the target array - * @param capacity a pointer to the capacity of the target array - * @param cmp_func the compare function for the elements - * @param src the source array - * @param elem_size the size of one element - * @param elem_count the number of elements to insert - * @param reallocator the array reallocator to use - * (@c NULL defaults to #cx_array_default_reallocator) - * @retval zero success - * @retval non-zero failure - */ -cx_attr_nonnull_arg(1, 2, 3, 5) -CX_EXPORT int cx_array_insert_sorted(void **target, size_t *size, size_t *capacity, - cx_compare_func cmp_func, const void *src, size_t elem_size, size_t elem_count, - CxArrayReallocator *reallocator); - -/** - * Inserts an element into a sorted array. - * - * If the target array is not already sorted with respect - * to the specified @p cmp_func, the behavior is undefined. - * - * If the capacity is not enough to hold the new data, a reallocation - * attempt is made. - * - * The \@ SIZE_TYPE is flexible and can be any unsigned integer type. - * It is important, however, that @p size and @p capacity are pointers to - * variables of the same type. - * - * @param target (@c void**) a pointer to the target array - * @param size (@c SIZE_TYPE*) a pointer to the size of the target array - * @param capacity (@c SIZE_TYPE*) a pointer to the capacity of the target array - * @param elem_size (@c size_t) the size of one element - * @param elem (@c void*) a pointer to the element to add - * @param cmp_func (@c cx_cmp_func) the compare function for the elements - * @param reallocator (@c CxArrayReallocator*) the array reallocator to use - * @retval zero success - * @retval non-zero failure - */ -#define cx_array_add_sorted(target, size, capacity, elem_size, elem, cmp_func, reallocator) \ - cx_array_insert_sorted((void**)(target), size, capacity, cmp_func, elem, elem_size, 1, reallocator) - -/** - * Convenience macro for cx_array_add_sorted() with a default - * layout and the specified reallocator. - * - * @param reallocator (@c CxArrayReallocator*) the array reallocator to use - * @param array the name of the array (NOT a pointer or alias to the array) - * @param elem the element to add (NOT a pointer, address is automatically taken) - * @param cmp_func (@c cx_cmp_func) the compare function for the elements - * @retval zero success - * @retval non-zero failure - * @see CX_ARRAY_DECLARE() - * @see cx_array_simple_add_sorted() - */ -#define cx_array_simple_add_sorted_a(reallocator, array, elem, cmp_func) \ - cx_array_add_sorted(&array, &(array##_size), &(array##_capacity), \ - sizeof((array)[0]), &(elem), cmp_func, reallocator) - -/** - * Convenience macro for cx_array_add_sorted() with a default - * layout and the default reallocator. - * - * @param array the name of the array (NOT a pointer or alias to the array) - * @param elem the element to add (NOT a pointer, address is automatically taken) - * @param cmp_func (@c cx_cmp_func) the compare function for the elements - * @retval zero success - * @retval non-zero failure - * @see CX_ARRAY_DECLARE() - * @see cx_array_simple_add_sorted_a() - */ -#define cx_array_simple_add_sorted(array, elem, cmp_func) \ - cx_array_simple_add_sorted_a(NULL, array, elem, cmp_func) - -/** - * Convenience macro for cx_array_insert_sorted() with a default - * layout and the specified reallocator. - * - * @param reallocator (@c CxArrayReallocator*) the array reallocator to use - * @param array the name of the array (NOT a pointer or alias to the array) - * @param src (@c void*) pointer to the source array - * @param n (@c size_t) number of elements in the source array - * @param cmp_func (@c cx_cmp_func) the compare function for the elements - * @retval zero success - * @retval non-zero failure - * @see CX_ARRAY_DECLARE() - * @see cx_array_simple_insert_sorted() - */ -#define cx_array_simple_insert_sorted_a(reallocator, array, src, n, cmp_func) \ - cx_array_insert_sorted((void**)(&array), &(array##_size), &(array##_capacity), \ - cmp_func, src, sizeof((array)[0]), n, reallocator) - -/** - * Convenience macro for cx_array_insert_sorted() with a default - * layout and the default reallocator. - * - * @param array the name of the array (NOT a pointer or alias to the array) - * @param src (@c void*) pointer to the source array - * @param n (@c size_t) number of elements in the source array - * @param cmp_func (@c cx_cmp_func) the compare function for the elements - * @retval zero success - * @retval non-zero failure - * @see CX_ARRAY_DECLARE() - * @see cx_array_simple_insert_sorted_a() - */ -#define cx_array_simple_insert_sorted(array, src, n, cmp_func) \ - cx_array_simple_insert_sorted_a(NULL, array, src, n, cmp_func) - - -/** - * Inserts a sorted array into another sorted array, avoiding duplicates. - * - * If either the target or the source array is not already sorted with respect - * to the specified @p cmp_func, the behavior is undefined. - * - * If the capacity is insufficient to hold the new data, a reallocation - * attempt is made. - * You can create your own reallocator by hand, use #cx_array_default_reallocator, - * or use the convenience function cx_array_reallocator() to create a custom reallocator. - * - * @param target a pointer to the target array - * @param size a pointer to the size of the target array - * @param capacity a pointer to the capacity of the target array - * @param cmp_func the compare function for the elements - * @param src the source array - * @param elem_size the size of one element - * @param elem_count the number of elements to insert - * @param reallocator the array reallocator to use - * (@c NULL defaults to #cx_array_default_reallocator) - * @retval zero success - * @retval non-zero failure - */ -cx_attr_nonnull_arg(1, 2, 3, 5) -CX_EXPORT int cx_array_insert_unique(void **target, size_t *size, size_t *capacity, - cx_compare_func cmp_func, const void *src, size_t elem_size, size_t elem_count, - CxArrayReallocator *reallocator); - -/** - * Inserts an element into a sorted array if it does not exist. - * - * If the target array is not already sorted with respect - * to the specified @p cmp_func, the behavior is undefined. - * - * If the capacity is insufficient to hold the new data, a reallocation - * attempt is made. - * - * The \@ SIZE_TYPE is flexible and can be any unsigned integer type. - * It is important, however, that @p size and @p capacity are pointers to - * variables of the same type. - * - * @param target (@c void**) a pointer to the target array - * @param size (@c SIZE_TYPE*) a pointer to the size of the target array - * @param capacity (@c SIZE_TYPE*) a pointer to the capacity of the target array - * @param elem_size (@c size_t) the size of one element - * @param elem (@c void*) a pointer to the element to add - * @param cmp_func (@c cx_cmp_func) the compare function for the elements - * @param reallocator (@c CxArrayReallocator*) the array reallocator to use - * @retval zero success (also when the element was already present) - * @retval non-zero failure - */ -#define cx_array_add_unique(target, size, capacity, elem_size, elem, cmp_func, reallocator) \ - cx_array_insert_unique((void**)(target), size, capacity, cmp_func, elem, elem_size, 1, reallocator) - -/** - * Convenience macro for cx_array_add_unique() with a default - * layout and the specified reallocator. - * - * @param reallocator (@c CxArrayReallocator*) the array reallocator to use - * @param array the name of the array (NOT a pointer or alias to the array) - * @param elem the element to add (NOT a pointer, address is automatically taken) - * @param cmp_func (@c cx_cmp_func) the compare function for the elements - * @retval zero success - * @retval non-zero failure - * @see CX_ARRAY_DECLARE() - * @see cx_array_simple_add_unique() - */ -#define cx_array_simple_add_unique_a(reallocator, array, elem, cmp_func) \ - cx_array_add_unique(&array, &(array##_size), &(array##_capacity), \ - sizeof((array)[0]), &(elem), cmp_func, reallocator) - -/** - * Convenience macro for cx_array_add_unique() with a default - * layout and the default reallocator. - * - * @param array the name of the array (NOT a pointer or alias to the array) - * @param elem the element to add (NOT a pointer, address is automatically taken) - * @param cmp_func (@c cx_cmp_func) the compare function for the elements - * @retval zero success - * @retval non-zero failure - * @see CX_ARRAY_DECLARE() - * @see cx_array_simple_add_unique_a() - */ -#define cx_array_simple_add_unique(array, elem, cmp_func) \ - cx_array_simple_add_unique_a(NULL, array, elem, cmp_func) - -/** - * Convenience macro for cx_array_insert_unique() with a default - * layout and the specified reallocator. - * - * @param reallocator (@c CxArrayReallocator*) the array reallocator to use - * @param array the name of the array (NOT a pointer or alias to the array) - * @param src (@c void*) pointer to the source array - * @param n (@c size_t) number of elements in the source array - * @param cmp_func (@c cx_cmp_func) the compare function for the elements - * @retval zero success - * @retval non-zero failure - * @see CX_ARRAY_DECLARE() - * @see cx_array_simple_insert_unique() - */ -#define cx_array_simple_insert_unique_a(reallocator, array, src, n, cmp_func) \ - cx_array_insert_unique((void**)(&array), &(array##_size), &(array##_capacity), \ - cmp_func, src, sizeof((array)[0]), n, reallocator) - -/** - * Convenience macro for cx_array_insert_unique() with a default - * layout and the default reallocator. - * - * @param array the name of the array (NOT a pointer or alias to the array) - * @param src (@c void*) pointer to the source array - * @param n (@c size_t) number of elements in the source array - * @param cmp_func (@c cx_cmp_func) the compare function for the elements - * @retval zero success - * @retval non-zero failure - * @see CX_ARRAY_DECLARE() - * @see cx_array_simple_insert_unique_a() - */ -#define cx_array_simple_insert_unique(array, src, n, cmp_func) \ - cx_array_simple_insert_unique_a(NULL, array, src, n, cmp_func) /** * Searches the largest lower bound in a sorted array.
--- a/src/json.c Sun Dec 14 23:17:48 2025 +0100 +++ b/src/json.c Mon Dec 15 19:00:51 2025 +0100 @@ -549,13 +549,9 @@ memset(json, 0, sizeof(CxJson)); json->allocator = allocator; - json->states.data = json->states_internal; - json->states.capacity = cx_nmemb(json->states_internal); + cx_array_init_fixed(json->states, json->states_internal, 1); json->states.data[0] = JP_STATE_VALUE_BEGIN; - json->states.size = 1; - - json->vbuf.data = json->vbuf_internal; - json->vbuf.capacity = cx_nmemb(json->vbuf_internal); + cx_array_init_fixed(json->vbuf, json->vbuf_internal, 0); } void cxJsonDestroy(CxJson *json) {
--- a/tests/test_list.c Sun Dec 14 23:17:48 2025 +0100 +++ b/tests/test_list.c Mon Dec 15 19:00:51 2025 +0100 @@ -46,7 +46,6 @@ arr.data[3] = 7; arr.data[4] = 11; arr.size = 3; - arr.capacity = 5; int elem = 8, elem2 = 47; int result; CX_TEST_DO { @@ -75,26 +74,62 @@ cx_array_free(arr); } -CX_TEST(test_array_copy_overlap) { - CX_ARRAY_DECLARE_SIZED(char, arr, uint8_t); - cx_array_initialize(arr, 16); - strcpy(arr, "Hello, World!"); +CX_TEST(test_array_reserve) { + CX_ARRAY(int, arr); + cx_array_init(arr, 5); + arr.data[0] = 2; + arr.data[1] = 3; + arr.data[2] = 5; + arr.size = 3; CX_TEST_DO { - errno = 0; - int result = cx_array_simple_copy(arr, 7, arr, 14); - CX_TEST_ASSERT(result == 0); - CX_TEST_ASSERT(errno == 0); - CX_TEST_ASSERT(arr_size == 21); - CX_TEST_ASSERT(arr_capacity == 32); - CX_TEST_ASSERT(0 == memcmp(arr, "Hello, Hello, World!\0", 21)); + // extend + CX_TEST_ASSERT(0 == cx_array_reserve(arr, 8)); + CX_TEST_ASSERT(arr.size == 3); + CX_TEST_ASSERT(arr.capacity == 8); + CX_TEST_ASSERT(arr.data[0] == 2); + CX_TEST_ASSERT(arr.data[1] == 3); + CX_TEST_ASSERT(arr.data[2] == 5); + + // shrink + CX_TEST_ASSERT(0 == cx_array_reserve(arr, 2)); + CX_TEST_ASSERT(arr.size == 2); + CX_TEST_ASSERT(arr.capacity == 2); + CX_TEST_ASSERT(arr.data[0] == 2); + CX_TEST_ASSERT(arr.data[1] == 3); } - cxFreeDefault(arr); + cx_array_free(arr); } -CX_TEST(test_array_reserve) { +CX_TEST(test_array_move_to_new) { + CX_ARRAY(int, arr); + int fixed[5] = {2, 4, 6}; + cx_array_init_fixed(arr, fixed, 3); CX_TEST_DO { - // TODO: create new test for the new API + CX_TEST_ASSERT(arr.data == fixed); + CX_TEST_ASSERT(arr.size == 3); + CX_TEST_ASSERT(arr.capacity == 5); + + CX_TEST_ASSERT(0 == cx_array_move_to_new(arr, 8)); + + CX_TEST_ASSERT(arr.data != fixed); + CX_TEST_ASSERT(arr.size == 3); + CX_TEST_ASSERT(arr.capacity == 8); + CX_TEST_ASSERT(arr.data[0] == 2); + CX_TEST_ASSERT(arr.data[1] == 4); + CX_TEST_ASSERT(arr.data[2] == 6); + + for (int x = 8 ; x <= 18 ; x+=2) { + cx_array_add(arr, &x); + } + + CX_TEST_ASSERT(arr.size == 9); + CX_TEST_ASSERT(arr.capacity >= 9); + + for (int x = 1 ; x <= 9 ; x++) { + CX_TEST_ASSERT(arr.data[x-1] == 2*x); + } } + cx_array_free(arr); } CX_TEST(test_array_insert_sorted) { @@ -115,50 +150,50 @@ 70, 71, 71, 72, 75, 75, 75, 77, 78, 80, 90, 90, 120, 130 }; - CX_ARRAY_DECLARE(int, array); - cx_array_initialize(array, 4); + CX_ARRAY(int, array); + cx_array_init(array, 4); CX_TEST_DO { - CX_TEST_ASSERT(0 == cx_array_simple_add_sorted(array, d1, cx_cmp_int)); - CX_TEST_ASSERT(array_size == 1); - CX_TEST_ASSERT(array_capacity == 4); - CX_TEST_ASSERT(0 == cx_array_simple_add_sorted(array, d2, cx_cmp_int)); - CX_TEST_ASSERT(array_size == 2); - CX_TEST_ASSERT(array_capacity == 4); - CX_TEST_ASSERT(0 == cx_array_simple_add_sorted(array, d3, cx_cmp_int)); - CX_TEST_ASSERT(array_size == 3); - CX_TEST_ASSERT(array_capacity == 4); - CX_TEST_ASSERT(0 == cx_array_simple_add_sorted(array, d4, cx_cmp_int)); - CX_TEST_ASSERT(array_size == 4); - CX_TEST_ASSERT(array_capacity == 4); - CX_TEST_ASSERT(0 == cx_array_simple_add_sorted(array, d5, cx_cmp_int)); - CX_TEST_ASSERT(array_size == 5); - CX_TEST_ASSERT(array_capacity >= 5); - CX_TEST_ASSERT(0 == cx_array_simple_insert_sorted(array, d6a, 6, cx_cmp_int)); - CX_TEST_ASSERT(array_size == 11); - CX_TEST_ASSERT(array_capacity >= 11); - CX_TEST_ASSERT(0 == cx_array_simple_insert_sorted(array, d7a, 6, cx_cmp_int)); - CX_TEST_ASSERT(array_size == 17); - CX_TEST_ASSERT(array_capacity >= 17); - CX_TEST_ASSERT(0 == cx_array_simple_add_sorted(array, d8, cx_cmp_int)); - CX_TEST_ASSERT(array_size == 18); - CX_TEST_ASSERT(array_capacity >= 18); - CX_TEST_ASSERT(0 == cx_array_simple_add_sorted(array, d9, cx_cmp_int)); - CX_TEST_ASSERT(array_size == 19); - CX_TEST_ASSERT(array_capacity >= 19); - CX_TEST_ASSERT(0 == cx_array_simple_insert_sorted(array, d10a, 3, cx_cmp_int)); - CX_TEST_ASSERT(array_size == 22); - CX_TEST_ASSERT(array_capacity >= 22); - CX_TEST_ASSERT(0 == cx_array_simple_insert_sorted(array, d11a, 6, cx_cmp_int)); - CX_TEST_ASSERT(array_size == 28); - CX_TEST_ASSERT(array_capacity >= 28); - CX_TEST_ASSERT(0 == cx_array_simple_insert_sorted(array, d12a, 3, cx_cmp_int)); - CX_TEST_ASSERT(array_size == 31); - CX_TEST_ASSERT(array_capacity >= 31); - - CX_TEST_ASSERT(0 == memcmp(array, expected, 31 * sizeof(int))); + CX_TEST_ASSERT(0 == cx_array_insert_sorted(array, cx_cmp_int, &d1)); + CX_TEST_ASSERT(array.size == 1); + CX_TEST_ASSERT(array.capacity == 4); + CX_TEST_ASSERT(0 == cx_array_insert_sorted(array, cx_cmp_int, &d2)); + CX_TEST_ASSERT(array.size == 2); + CX_TEST_ASSERT(array.capacity == 4); + CX_TEST_ASSERT(0 == cx_array_insert_sorted(array, cx_cmp_int, &d3)); + CX_TEST_ASSERT(array.size == 3); + CX_TEST_ASSERT(array.capacity == 4); + CX_TEST_ASSERT(0 == cx_array_insert_sorted(array, cx_cmp_int, &d4)); + CX_TEST_ASSERT(array.size == 4); + CX_TEST_ASSERT(array.capacity == 4); + CX_TEST_ASSERT(0 == cx_array_insert_sorted(array, cx_cmp_int, &d5)); + CX_TEST_ASSERT(array.size == 5); + CX_TEST_ASSERT(array.capacity >= 5); + CX_TEST_ASSERT(0 == cx_array_insert_sorted_array(array, cx_cmp_int, d6a, 6)); + CX_TEST_ASSERT(array.size == 11); + CX_TEST_ASSERT(array.capacity >= 11); + CX_TEST_ASSERT(0 == cx_array_insert_sorted_array(array, cx_cmp_int, d7a, 6)); + CX_TEST_ASSERT(array.size == 17); + CX_TEST_ASSERT(array.capacity >= 17); + CX_TEST_ASSERT(0 == cx_array_insert_sorted(array, cx_cmp_int, &d8)); + CX_TEST_ASSERT(array.size == 18); + CX_TEST_ASSERT(array.capacity >= 18); + CX_TEST_ASSERT(0 == cx_array_insert_sorted(array, cx_cmp_int, &d9)); + CX_TEST_ASSERT(array.size == 19); + CX_TEST_ASSERT(array.capacity >= 19); + CX_TEST_ASSERT(0 == cx_array_insert_sorted_array(array, cx_cmp_int, d10a, 3)); + CX_TEST_ASSERT(array.size == 22); + CX_TEST_ASSERT(array.capacity >= 22); + CX_TEST_ASSERT(0 == cx_array_insert_sorted_array(array, cx_cmp_int, d11a, 6)); + CX_TEST_ASSERT(array.size == 28); + CX_TEST_ASSERT(array.capacity >= 28); + CX_TEST_ASSERT(0 == cx_array_insert_sorted_array(array, cx_cmp_int, d12a, 3)); + CX_TEST_ASSERT(array.size == 31); + CX_TEST_ASSERT(array.capacity >= 31); + + CX_TEST_ASSERT(0 == memcmp(array.data, expected, 31 * sizeof(int))); } - cxFreeDefault(array); + cx_array_free(array); } CX_TEST(test_array_insert_unique) { @@ -178,47 +213,47 @@ 65, 67, 70, 75, 77, 78, 80, 90, 95, 100, 110 }; - CX_ARRAY_DECLARE(int, array); - cx_array_initialize(array, 4); + CX_ARRAY(int, array); + cx_array_init(array, 4); CX_TEST_DO { - CX_TEST_ASSERT(0 == cx_array_simple_add_unique(array, d1, cx_cmp_int)); - CX_TEST_ASSERT(array_size == 1); - CX_TEST_ASSERT(array_capacity == 4); - CX_TEST_ASSERT(0 == cx_array_simple_add_unique(array, d2, cx_cmp_int)); - CX_TEST_ASSERT(array_size == 2); - CX_TEST_ASSERT(array_capacity == 4); - CX_TEST_ASSERT(0 == cx_array_simple_add_unique(array, d3, cx_cmp_int)); - CX_TEST_ASSERT(array_size == 3); - CX_TEST_ASSERT(array_capacity == 4); - CX_TEST_ASSERT(0 == cx_array_simple_add_unique(array, d4, cx_cmp_int)); - CX_TEST_ASSERT(array_size == 4); - CX_TEST_ASSERT(array_capacity == 4); - CX_TEST_ASSERT(0 == cx_array_simple_add_unique(array, d5, cx_cmp_int)); - CX_TEST_ASSERT(array_size == 5); - CX_TEST_ASSERT(array_capacity >= 5); - CX_TEST_ASSERT(0 == cx_array_simple_insert_unique(array, d6a, 6, cx_cmp_int)); - CX_TEST_ASSERT(array_size == 11); - CX_TEST_ASSERT(array_capacity >= 11); - CX_TEST_ASSERT(0 == cx_array_simple_insert_unique(array, d7a, 6, cx_cmp_int)); - CX_TEST_ASSERT(array_size == 17); - CX_TEST_ASSERT(array_capacity >= 17); - CX_TEST_ASSERT(0 == cx_array_simple_add_unique(array, d8, cx_cmp_int)); - CX_TEST_ASSERT(array_size == 18); - CX_TEST_ASSERT(array_capacity >= 18); - CX_TEST_ASSERT(0 == cx_array_simple_add_unique(array, d9, cx_cmp_int)); - CX_TEST_ASSERT(array_size == 18); - CX_TEST_ASSERT(array_capacity >= 18); - CX_TEST_ASSERT(0 == cx_array_simple_insert_unique(array, d10a, 3, cx_cmp_int)); - CX_TEST_ASSERT(array_size == 19); - CX_TEST_ASSERT(array_capacity >= 19); - CX_TEST_ASSERT(0 == cx_array_simple_insert_unique(array, d11a, 8, cx_cmp_int)); - CX_TEST_ASSERT(array_size == 22); - CX_TEST_ASSERT(array_capacity >= 22); - - CX_TEST_ASSERT(0 == memcmp(array, expected, 22 * sizeof(int))); + CX_TEST_ASSERT(0 == cx_array_insert_unique(array, cx_cmp_int, &d1)); + CX_TEST_ASSERT(array.size == 1); + CX_TEST_ASSERT(array.capacity == 4); + CX_TEST_ASSERT(0 == cx_array_insert_unique(array, cx_cmp_int, &d2)); + CX_TEST_ASSERT(array.size == 2); + CX_TEST_ASSERT(array.capacity == 4); + CX_TEST_ASSERT(0 == cx_array_insert_unique(array, cx_cmp_int, &d3)); + CX_TEST_ASSERT(array.size == 3); + CX_TEST_ASSERT(array.capacity == 4); + CX_TEST_ASSERT(0 == cx_array_insert_unique(array, cx_cmp_int, &d4)); + CX_TEST_ASSERT(array.size == 4); + CX_TEST_ASSERT(array.capacity == 4); + CX_TEST_ASSERT(0 == cx_array_insert_unique(array, cx_cmp_int, &d5)); + CX_TEST_ASSERT(array.size == 5); + CX_TEST_ASSERT(array.capacity >= 5); + CX_TEST_ASSERT(0 == cx_array_insert_unique_array(array, cx_cmp_int, d6a, 6)); + CX_TEST_ASSERT(array.size == 11); + CX_TEST_ASSERT(array.capacity >= 11); + CX_TEST_ASSERT(0 == cx_array_insert_unique_array(array, cx_cmp_int, d7a, 6)); + CX_TEST_ASSERT(array.size == 17); + CX_TEST_ASSERT(array.capacity >= 17); + CX_TEST_ASSERT(0 == cx_array_insert_unique(array, cx_cmp_int, &d8)); + CX_TEST_ASSERT(array.size == 18); + CX_TEST_ASSERT(array.capacity >= 18); + CX_TEST_ASSERT(0 == cx_array_insert_unique(array, cx_cmp_int, &d9)); + CX_TEST_ASSERT(array.size == 18); + CX_TEST_ASSERT(array.capacity >= 18); + CX_TEST_ASSERT(0 == cx_array_insert_unique_array(array, cx_cmp_int, d10a, 3)); + CX_TEST_ASSERT(array.size == 19); + CX_TEST_ASSERT(array.capacity >= 19); + CX_TEST_ASSERT(0 == cx_array_insert_unique_array(array, cx_cmp_int, d11a, 8)); + CX_TEST_ASSERT(array.size == 22); + CX_TEST_ASSERT(array.capacity >= 22); + + CX_TEST_ASSERT(0 == memcmp(array.data, expected, 22 * sizeof(int))); } - cxFreeDefault(array); + cx_array_free(array); } CX_TEST(test_array_binary_search) { @@ -3243,8 +3278,8 @@ CxTestSuite *suite = cx_test_suite_new("array_list"); cx_test_register(suite, test_array_add); - cx_test_register(suite, test_array_copy_overlap); cx_test_register(suite, test_array_reserve); + cx_test_register(suite, test_array_move_to_new); cx_test_register(suite, test_array_insert_sorted); cx_test_register(suite, test_array_insert_unique); cx_test_register(suite, test_array_binary_search);