diff -r b60487c3ec36 -r af685cc9d623 ucx/cx/array_list.h --- a/ucx/cx/array_list.h Sun Aug 31 14:39:13 2025 +0200 +++ b/ucx/cx/array_list.h Sat Nov 08 23:06:11 2025 +0100 @@ -44,11 +44,10 @@ #endif /** - * The maximum item size in an array list that fits into stack buffer - * when swapped. + * The maximum item size in an array list that fits into + * a stack buffer when swapped. */ -cx_attr_export -extern const unsigned cx_array_swap_sbo_size; +CX_EXPORT extern const unsigned cx_array_swap_sbo_size; /** * Declares variables for an array that can be used with the convenience macros. @@ -84,7 +83,7 @@ /** * Declares variables for an array that can be used with the convenience macros. * - * The size and capacity variables will have @c size_t type. + * The size and capacity variables will have type @c size_t. * Use #CX_ARRAY_DECLARE_SIZED() to specify a different type. * * @par Examples @@ -123,7 +122,8 @@ * @endcode * * - * The memory for the array is allocated with stdlib malloc(). + * 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() @@ -133,7 +133,7 @@ #define cx_array_initialize(array, capacity) \ array##_capacity = capacity; \ array##_size = 0; \ - array = malloc(sizeof(array[0]) * capacity) + array = cxMallocDefault(sizeof(array[0]) * capacity) /** * Initializes an array with the given capacity using the specified allocator. @@ -146,10 +146,9 @@ * const CxAllocator *al = // ... * cx_array_initialize_a(al, myarray, 128); * // ... - * cxFree(al, myarray); // don't forget to free with same allocator + * cxFree(al, myarray); // remember to free with the same allocator * @endcode * - * The memory for the array is allocated with stdlib malloc(). * @param allocator (@c CxAllocator*) the allocator * @param array the name of the array * @param capacity the initial capacity @@ -172,43 +171,29 @@ * Reallocates space for the given array. * * Implementations are not required to free the original array. - * This allows reallocation of static memory by allocating heap memory - * and copying the array contents. The information in the custom fields of - * the referenced allocator can be used to track the state of the memory - * or to transport other additional data. + * 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 capacity the new capacity (number of elements) + * @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 */ - cx_attr_nodiscard - cx_attr_nonnull_arg(4) - cx_attr_allocsize(2, 3) - void *(*realloc)( - void *array, - size_t capacity, - size_t elem_size, - struct cx_array_reallocator_s *alloc - ); + void *(*realloc)( void *array, size_t old_capacity, size_t new_capacity, + size_t elem_size, struct cx_array_reallocator_s *alloc); /** - * Custom data pointer. + * The allocator that shall be used for the reallocations. */ - void *ptr1; - /** - * Custom data pointer. - */ - void *ptr2; + const CxAllocator *allocator; /** - * Custom data integer. + * Optional pointer to stack memory + * if the array is originally located on the stack. */ - size_t int1; - /** - * Custom data integer. - */ - size_t int2; + const void *stack_ptr; }; /** @@ -217,34 +202,30 @@ typedef struct cx_array_reallocator_s CxArrayReallocator; /** - * A default stdlib-based array reallocator. + * A default array reallocator that is based on the cxDefaultAllocator. */ -cx_attr_export -extern CxArrayReallocator *cx_array_default_reallocator; +CX_EXPORT extern CxArrayReallocator *cx_array_default_reallocator; /** * Creates a new array reallocator. * - * When @p allocator is @c NULL, the stdlib default allocator will be used. + * When @p allocator is @c NULL, the cxDefaultAllocator 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. + * 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 @c NULL will return a + * @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 stackmem the address of the array when the array is initially located - * on the stack or shall not reallocated in place + * @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_attr_export -CxArrayReallocator cx_array_reallocator( - const struct cx_allocator_s *allocator, - const void *stackmem -); +CX_EXPORT CxArrayReallocator cx_array_reallocator( + const struct cx_allocator_s *allocator, const void *stack_ptr); /** * Reserves memory for additional elements. @@ -261,7 +242,7 @@ * * 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 + * 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. * * @param array a pointer to the target array @@ -277,16 +258,9 @@ * @see cx_array_reallocator() */ cx_attr_nonnull_arg(1, 2, 3) -cx_attr_export -int cx_array_reserve( - void **array, - void *size, - void *capacity, - unsigned width, - size_t elem_size, - size_t elem_count, - CxArrayReallocator *reallocator -); +CX_EXPORT int cx_array_reserve(void **array, void *size, void *capacity, + unsigned width, size_t elem_size, size_t elem_count, + CxArrayReallocator *reallocator); /** * Copies elements from one array to another. @@ -294,7 +268,7 @@ * 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 - * would extend the array's size, the remaining @p capacity is used. + * 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. @@ -303,7 +277,7 @@ * * 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 + * 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. * * @param target a pointer to the target array @@ -321,18 +295,9 @@ * @see cx_array_reallocator() */ cx_attr_nonnull_arg(1, 2, 3, 6) -cx_attr_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 -); +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 @@ -480,17 +445,9 @@ * @retval non-zero failure */ cx_attr_nonnull_arg(1, 2, 3, 5) -cx_attr_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 -); +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. @@ -498,7 +455,7 @@ * 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 + * 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. @@ -584,6 +541,127 @@ #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. * @@ -607,14 +685,8 @@ * @see cx_array_binary_search() */ cx_attr_nonnull -cx_attr_export -size_t cx_array_binary_search_inf( - const void *arr, - size_t size, - size_t elem_size, - const void *elem, - cx_compare_func cmp_func -); +CX_EXPORT size_t cx_array_binary_search_inf(const void *arr, size_t size, + size_t elem_size, const void *elem, cx_compare_func cmp_func); /** * Searches an item in a sorted array. @@ -633,14 +705,8 @@ * @see cx_array_binary_search_sup() */ cx_attr_nonnull -cx_attr_export -size_t cx_array_binary_search( - const void *arr, - size_t size, - size_t elem_size, - const void *elem, - cx_compare_func cmp_func -); +CX_EXPORT size_t cx_array_binary_search(const void *arr, size_t size, + size_t elem_size, const void *elem, cx_compare_func cmp_func); /** * Searches the smallest upper bound in a sorted array. @@ -665,41 +731,29 @@ * @see cx_array_binary_search() */ cx_attr_nonnull -cx_attr_export -size_t cx_array_binary_search_sup( - const void *arr, - size_t size, - size_t elem_size, - const void *elem, - cx_compare_func cmp_func -); +CX_EXPORT size_t cx_array_binary_search_sup(const void *arr, size_t size, + size_t elem_size, const void *elem, cx_compare_func cmp_func); /** * Swaps two array elements. * * @param arr the array * @param elem_size the element size - * @param idx1 index of first element - * @param idx2 index of second element + * @param idx1 index of the first element + * @param idx2 index of the second element */ cx_attr_nonnull -cx_attr_export -void cx_array_swap( - void *arr, - size_t elem_size, - size_t idx1, - size_t idx2 -); +CX_EXPORT void cx_array_swap(void *arr, size_t elem_size, size_t idx1, size_t idx2); /** * Allocates an array list for storing elements with @p elem_size bytes each. * * If @p elem_size is #CX_STORE_POINTERS, the created list stores pointers instead of - * copies of the added elements and the compare function will be automatically set + * copies of the added elements, and the compare function will be automatically set * to cx_cmp_ptr(), if none is given. * * @param allocator the allocator for allocating the list memory - * (if @c NULL, a default stdlib allocator will be used) + * (if @c NULL, the cxDefaultAllocator will be used) * @param comparator the comparator for the elements * (if @c NULL, and the list is not storing pointers, sort and find * functions will not work) @@ -710,13 +764,8 @@ cx_attr_nodiscard cx_attr_malloc cx_attr_dealloc(cxListFree, 1) -cx_attr_export -CxList *cxArrayListCreate( - const CxAllocator *allocator, - cx_compare_func comparator, - size_t elem_size, - size_t initial_capacity -); +CX_EXPORT CxList *cxArrayListCreate(const CxAllocator *allocator, + cx_compare_func comparator, size_t elem_size, size_t initial_capacity); /** * Allocates an array list for storing elements with @p elem_size bytes each. @@ -727,7 +776,7 @@ * * If @p elem_size is #CX_STORE_POINTERS, the created list stores pointers instead of * copies of the added elements and the compare function will be automatically set - * to cx_cmp_ptr(), if none is given. + * to cx_cmp_ptr(). * * @param elem_size (@c size_t) the size of each element in bytes * @param initial_capacity (@c size_t) the initial number of elements the array can store