--- a/ucx/cx/array_list.h Sun Dec 07 20:16:59 2025 +0100 +++ b/ucx/cx/array_list.h Fri Dec 19 17:53:18 2025 +0100 @@ -50,617 +50,892 @@ CX_EXPORT extern const unsigned cx_array_swap_sbo_size; /** - * 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) + * Declares a typed array with size and capacity. * - * // 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 elements + * @param name the name of the array + */ +#define CX_ARRAY(type, name) \ + struct { \ + type *data; \ + size_t size; \ + size_t capacity; \ + } name + +/** + * Internal structure for arrays. * - * @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) + * A generalization of array structures declared with CX_ARRAY(). + */ +typedef struct cx_array_s { + /** The array data. */ + void *data; + /** The number of elements. */ + size_t size; + /** The maximum number of elements. */ + size_t capacity; +} CxArray; + +/** + * Initializes an array by allocating memory. * - * @see cx_array_initialize() - * @see cx_array_simple_add() - * @see cx_array_simple_copy() - * @see cx_array_simple_add_sorted() - * @see cx_array_simple_insert_sorted() + * Internal function - do not use manually. + * + * @param allocator the allocator for the array + * @param array a pointer to the array structure + * @param elem_size size of one element + * @param capacity the initial maximum number of elements + * @retval zero allocation was successful + * @retval non-zero allocation failed */ -#define CX_ARRAY_DECLARE_SIZED(type, name, size_type) \ - type * name; \ - /** Array size. */ size_type name##_size; \ - /** Array capacity. */ size_type name##_capacity +cx_attr_nonnull +CX_EXPORT int cx_array_init_(const CxAllocator *allocator, CxArray *array, size_t elem_size, size_t 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. + * Initializes an array by allocating memory. * - * @par Examples - * @code - * // int array - * CX_ARRAY_DECLARE(int, myarray) + * The size is set to zero. + * + * @attention If the array was already initialized, this will leak memory. + * Use cx_array_reserve() to change the capacity of an initialized array. * - * // 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_add() - * @see cx_array_simple_copy() - * @see cx_array_simple_add_sorted() - * @see cx_array_simple_insert_sorted() + * @param allocator (@c CxAllocator*) the allocator for the array + * @param array the name of the array + * @param capacity (@c size_t) the initial maximum number of elements + * @retval zero allocation was successful + * @retval non-zero allocation failed */ -#define CX_ARRAY_DECLARE(type, name) CX_ARRAY_DECLARE_SIZED(type, name, size_t) +#define cx_array_init_a(allocator, array, capacity) cx_array_init_(allocator, (CxArray*)&(array), sizeof((array).data[0]), capacity) /** - * Initializes an array with the given capacity. - * - * The type of the capacity depends on the type used during declaration. + * Initializes an array by allocating memory. * - * @par Examples - * @code - * CX_ARRAY_DECLARE_SIZED(int, arr1, uint8_t) - * CX_ARRAY_DECLARE(int, arr2) // size and capacity are implicitly size_t + * The size is set to zero. * - * // 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. + * @attention If the array was already initialized, this will leak memory. * * @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() + * @param capacity (@c size_t) the initial maximum number of elements + * @retval zero allocation was successful + * @retval non-zero allocation failed */ -#define cx_array_initialize(array, capacity) \ - array##_capacity = capacity; \ - array##_size = 0; \ - array = cxMallocDefault(sizeof(array[0]) * capacity) +#define cx_array_init(array, capacity) cx_array_init_a(cxDefaultAllocator, array, capacity) + +/** + * Initializes an array with fixed size memory. + * + * Internal function - do not use manually. + * + * @param array a pointer to the array structure + * @param data the fixed size array + * @param capacity the capacity of the fixed size array + * @param size the number of initialized elements in the fixed size array + */ +cx_attr_nonnull +CX_EXPORT void cx_array_init_fixed_(CxArray *array, const void *data, size_t capacity, size_t size); /** - * Initializes an array with the given capacity using the specified allocator. + * Initializes an array with fixed size memory. + * + * This is useful, for example, when you want to work with memory on the stack + * and only want to move to the heap when the stack memory is not enough. + * + * With the @p num_initialized argument you can specify how many elements in the + * fixed size array are already correctly initialized, which determines the + * initial size of the array. * - * @par Example - * @code - * CX_ARRAY_DECLARE(int, myarray) + * The capacity is determined automatically by the compiler. * + * @attention When you add elements to an array that was initialized with fixed + * size memory, you MUST check the capacity before adding the element and invoke + * cx_array_copy_to_new() when you intend to exceed the capacity. + * + * @attention When you pass a pointer to an array that does not have a fixed + * size, the behavior is unspecified. * - * const CxAllocator *al = // ... - * cx_array_initialize_a(al, myarray, 128); - * // ... - * cxFree(al, myarray); // remember to free with the same allocator - * @endcode + * @param array the name of the array to initialize + * @param fixed_size_array (@c void*) the fixed size array + * @param num_initialized (@c size_t) the number of already initialized elements in the fixed size array + * @see cx_array_copy_to_new() + */ +#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) + +/** + * Changes the capacity of an array. * - * @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() + * Internal function - do not use. + * + * @param allocator the allocator + * @param array a pointer to the array structure + * @param elem_size the size of one element + * @param capacity the new capacity + * @retval zero allocation was successful + * @retval non-zero allocation failed */ -#define cx_array_initialize_a(allocator, array, capacity) \ - array##_capacity = capacity; \ - array##_size = 0; \ - array = cxMalloc(allocator, sizeof(array[0]) * capacity) +cx_attr_nonnull +CX_EXPORT int cx_array_reserve_(const CxAllocator *allocator, CxArray *array, size_t elem_size, size_t capacity); /** - * Defines a reallocation mechanism for arrays. - * You can create your own, use cx_array_reallocator(), or - * use the #cx_array_default_reallocator. + * Changes the capacity of an array. + * + * If required, the size is reduced to fit into the new capacity. + * + * @param allocator (@c CxAllocator*) the allocator for the array + * @param array the name of the array + * @param capacity (@c size_t) the new maximum number of elements + * @retval zero allocation was successful + * @retval non-zero allocation failed */ -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); +#define cx_array_reserve_a(allocator, array, capacity) \ + cx_array_reserve_(allocator, (CxArray*)&(array), sizeof((array).data[0]), capacity) - /** - * 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; -}; +/** + * Changes the capacity of an array. + * + * If required, the size is reduced to fit into the new capacity. + * + * @param array the name of the array + * @param capacity (@c size_t) the new maximum number of elements + * @retval zero allocation was successful + * @retval non-zero allocation failed + */ +#define cx_array_reserve(array, capacity) \ + cx_array_reserve_a(cxDefaultAllocator, array, capacity) /** - * Typedef for the array reallocator struct. + * Copies the array to a new memory region. + * + * Internal function - do not use. + * + * @param allocator the allocator for new new memory + * @param array a pointer to the array structure + * @param elem_size the size of one element + * @param capacity the new capacity + * @retval zero allocation was successful + * @retval non-zero allocation failed */ -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; +cx_attr_nonnull +CX_EXPORT int cx_array_copy_to_new_(const CxAllocator *allocator, CxArray *array, size_t elem_size, size_t capacity); /** - * Creates a new array reallocator. - * - * When @p allocator is @c NULL, the cxDefaultAllocator will be used. + * Copies the array to a new memory region. * - * 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. + * This is useful when you have initialized the array with a fixed size memory + * using cx_array_init_fixed(), and now you want to increase the capacity. + * + * @attention When the original memory does not belong to stack memory, and + * you do not have another reference to this memory, it will leak. * - * @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 + * @param allocator (@c CxAllocator*) the allocator for the new memory + * @param array the name of the array + * @param capacity (@c size_t) the new maximum number of elements + * @retval zero allocation was successful + * @retval non-zero allocation failed + * @see cx_array_init_fixed() */ -CX_EXPORT CxArrayReallocator cx_array_reallocator( - const struct cx_allocator_s *allocator, const void *stack_ptr); +#define cx_array_copy_to_new_a(allocator, array, capacity) \ + cx_array_copy_to_new_(allocator, (CxArray*)&(array), sizeof((array).data[0]), capacity) /** - * Reserves memory for additional elements. - * - * This function checks if the @p capacity of the array is sufficient to hold - * at least @p size plus @p elem_count elements. If not, a reallocation is - * performed 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. + * Copies the array to a new memory region. * - * This function can be useful to replace subsequent calls to cx_array_copy() - * with one single cx_array_reserve() and then - after guaranteeing a - * sufficient capacity - use simple memmove() or memcpy(). + * This is useful when you have initialized the array with a fixed size memory + * using cx_array_init_fixed(), and now you want to increase the capacity. * - * 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. + * @attention When the original memory does not belong to stack memory, and + * you do not have another reference to this memory, it will leak. * - * @param array a pointer to the target array - * @param size a pointer to the size of the array - * @param capacity a pointer to the capacity of the array - * @param width the width in bytes for the @p size and @p capacity or zero for default + * @param array the name of the array + * @param capacity (@c size_t) the new maximum number of elements + * @retval zero allocation was successful + * @retval non-zero allocation failed + * @see cx_array_init_fixed() + */ +#define cx_array_copy_to_new(array, capacity) \ + cx_array_copy_to_new_a(cxDefaultAllocator, array, capacity) + +/** + * Inserts data into an array. + * + * Internal function - do not use. + * + * @param allocator the allocator to use for a possible reallocation + * @param array a pointer to the array structure * @param elem_size the size of one element - * @param elem_count the number of expected additional elements - * @param reallocator the array reallocator to use - * (@c NULL defaults to #cx_array_default_reallocator) + * @param index the index where to insert the @p other data + * @param other a pointer to an array of data that shall be inserted + * @param n the number of elements that shall be inserted * @retval zero success - * @retval non-zero failure - * @see cx_array_reallocator() + * @retval non-zero a re-allocation was necessary but failed */ -cx_attr_nonnull_arg(1, 2, 3) -CX_EXPORT int cx_array_reserve(void **array, void *size, void *capacity, - unsigned width, size_t elem_size, size_t elem_count, - CxArrayReallocator *reallocator); +cx_attr_nonnull_arg(1, 2) +CX_EXPORT int cx_array_insert_(const CxAllocator *allocator, CxArray *array, + size_t elem_size, size_t index, const void *other, size_t n); /** - * 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. + * Appends an element to an array. * - * 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. + * When the capacity is not enough to hold the new element, a re-allocation is attempted. * - * @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) + * @param allocator (@c CxAllocator*) the allocator to use for a possible reallocation + * @param array the name of the array where the element shall be added + * @param element the element that shall be added * @retval zero success - * @retval non-zero failure - * @see cx_array_reallocator() + * @retval non-zero a re-allocation was necessary but failed */ -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); +#define cx_array_add_a(allocator, array, element) \ + cx_array_insert_(allocator, (CxArray*)&(array), sizeof((array).data[0]), (array).size, (void*)&(element), 1) + +/** + * Appends an element to an array. + * + * When the capacity is not enough to hold the new element, a re-allocation is attempted. + * + * @param array the name of the array where the element shall be added + * @param element (@c void*) a pointer to the element that shall be added + * @retval zero success + * @retval non-zero a re-allocation was necessary but failed + */ +#define cx_array_add(array, element) \ + cx_array_add_a(cxDefaultAllocator, array, element) /** - * Convenience macro that uses cx_array_copy() with a default layout and - * the specified reallocator. + * Inserts an element into an array. + * + * When the capacity is not enough to hold the new element, a re-allocation is attempted. * - * @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 + * @param allocator (@c CxAllocator*) the allocator to use for a possible reallocation + * @param array the name of the array where the element shall be inserted + * @param index (@c size_t) the index where to insert the @p element + * @param element the element that shall be inserted * @retval zero success - * @retval non-zero failure - * @see CX_ARRAY_DECLARE() - * @see cx_array_simple_copy() + * @retval non-zero a re-allocation was necessary but failed */ -#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) +#define cx_array_insert_a(allocator, array, index, element) \ + cx_array_insert_(allocator, (CxArray*)&(array), sizeof((array).data[0]), index, (void*)&(element), 1) /** - * Convenience macro that uses cx_array_copy() with a default layout and - * the default reallocator. + * Inserts an element into an array. + * + * When the capacity is not enough to hold the new element, a re-allocation is attempted. * - * @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 + * @param array the name of the array where the element shall be inserted + * @param index (@c size_t) the index where to insert the @p element + * @param element (@c void*) a pointer to the element that shall be inserted * @retval zero success - * @retval non-zero failure - * @see CX_ARRAY_DECLARE() - * @see cx_array_simple_copy_a() + * @retval non-zero a re-allocation was necessary but failed */ -#define cx_array_simple_copy(array, index, src, count) \ - cx_array_simple_copy_a(NULL, array, index, src, count) +#define cx_array_insert(array, index, element) \ + cx_array_insert_a(cxDefaultAllocator, array, index, element) /** - * Convenience macro that uses cx_array_reserve() with a default layout and - * the specified reallocator. + * Inserts data into an array. + * + * When the capacity is not enough to hold the new elements, a re-allocation is attempted. * - * @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 count (@c size_t) the number of expected @em additional elements + * @param allocator (@c CxAllocator*) the allocator to use for a possible reallocation + * @param array the name of the array where the elements shall be inserted + * @param index (@c size_t) the index where to insert the @p other data + * @param other (@c void*) a pointer to an array of data that shall be inserted + * @param n (@c size_t) the number of elements that shall be inserted * @retval zero success - * @retval non-zero failure - * @see CX_ARRAY_DECLARE() - * @see cx_array_simple_reserve() + * @retval non-zero a re-allocation was necessary but failed */ -#define cx_array_simple_reserve_a(reallocator, array, count) \ - cx_array_reserve((void**)&(array), &(array##_size), &(array##_capacity), \ - sizeof(array##_size), sizeof((array)[0]), count, \ - reallocator) +#define cx_array_insert_array_a(allocator, array, index, other, n) \ + cx_array_insert_(allocator, (CxArray*)&(array), sizeof((array).data[0]), index, other, n) /** - * Convenience macro that uses cx_array_reserve() with a default layout and - * the default reallocator. + * Inserts data into an array. + * + * When the capacity is not enough to hold the new elements, a re-allocation is attempted. * - * @param array the name of the array (NOT a pointer or alias to the array) - * @param count (@c size_t) the number of expected additional elements + * @param array the name of the array where the elements shall be inserted + * @param index (@c size_t) the index where to insert the @p other data + * @param other (@c void*) a pointer to an array of data that shall be inserted + * @param n (@c size_t) the number of elements that shall be inserted * @retval zero success - * @retval non-zero failure - * @see CX_ARRAY_DECLARE() - * @see cx_array_simple_reserve_a() + * @retval non-zero a re-allocation was necessary but failed */ -#define cx_array_simple_reserve(array, count) \ - cx_array_simple_reserve_a(NULL, array, count) +#define cx_array_insert_array(array, index, other, n) \ + cx_array_insert_array_a(cxDefaultAllocator, array, index, other, n) + +/** + * Appends data to an array. + * + * When the capacity is not enough to hold the new elements, a re-allocation is attempted. + * + * @param allocator (@c CxAllocator*) the allocator to use for a possible reallocation + * @param array the name of the array where the elements shall be added + * @param other (@c void*) a pointer to an array of data that shall be added + * @param n (@c size_t) the number of elements that shall be added + * @retval zero success + * @retval non-zero a re-allocation was necessary but failed + */ +#define cx_array_add_array_a(allocator, array, other, n) \ + cx_array_insert_(allocator, (CxArray*)&(array), sizeof((array).data[0]), (array).size, other, n) /** - * Adds an element to an array with the possibility of allocating more space. - * - * The element @p elem is added to the end of the @p target array which contains - * @p size elements, already. The @p capacity must point to a variable denoting - * the current maximum number of elements the array can hold. + * Appends data to an array. * - * If the capacity is insufficient to hold the new element, an attempt to - * increase the @p capacity is made and the new capacity is written back. - * - * 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. + * When the capacity is not enough to hold the new elements, a re-allocation is attempted. * - * @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 reallocator (@c CxArrayReallocator*) the array reallocator to use + * @param array the name of the array where the elements shall be added + * @param other (@c void*) a pointer to an array of data that shall be added + * @param n (@c size_t) the number of elements that shall be added * @retval zero success - * @retval non-zero failure + * @retval non-zero a re-allocation was necessary but failed */ -#define cx_array_add(target, size, capacity, elem_size, elem, reallocator) \ - cx_array_copy((void**)(target), size, capacity, sizeof(*(size)), \ - *(size), elem, elem_size, 1, reallocator) +#define cx_array_add_array(array, other, n) \ + cx_array_add_array_a(cxDefaultAllocator, array, other, n) /** - * Convenience macro that uses cx_array_add() with a default layout and - * the specified reallocator. + * Inserts sorted data into a sorted array. + * + * Internal function - do not use. * - * @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 allocator the allocator to use for a possible reallocation + * @param array a pointer to the array structure + * @param elem_size the size of one element + * @param sorted_data a pointer to an array of data that shall be inserted + * @param n the number of elements that shall be inserted + * @param cmp_func the compare function + * @param allow_duplicates @c false if duplicates shall be skipped during insertion * @retval zero success - * @retval non-zero failure - * @see CX_ARRAY_DECLARE() - * @see cx_array_simple_add() + * @retval non-zero a re-allocation was necessary but failed */ -#define cx_array_simple_add_a(reallocator, array, elem) \ - cx_array_simple_copy_a(reallocator, array, array##_size, &(elem), 1) +cx_attr_nonnull +CX_EXPORT int cx_array_insert_sorted_(const CxAllocator *allocator, CxArray *array, + size_t elem_size, const void *sorted_data, size_t n, + cx_compare_func cmp_func, bool allow_duplicates); /** - * Convenience macro that uses cx_array_add() with a default layout and - * the default reallocator. + * Inserts an element into a sorted array. * - * @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) - * @retval zero success - * @retval non-zero failure - * @see CX_ARRAY_DECLARE() - * @see cx_array_simple_add_a() - */ -#define cx_array_simple_add(array, elem) \ - cx_array_simple_add_a(cx_array_default_reallocator, array, elem) - -/** - * Inserts a sorted array into another sorted array. + * When the capacity is not enough to hold the new element, a re-allocation is attempted. * - * If either the target or the source array is not already sorted with respect - * to the specified @p cmp_func, the behavior is undefined. + * @attention if the array is not sorted according 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) + * @param allocator (@c CxAllocator*) the allocator to use for a possible reallocation + * @param array the name of the array where the elements shall be inserted + * @param element the element that shall be inserted + * @param cmp_func (@c cx_compare_func) the compare function that establishes the order * @retval zero success - * @retval non-zero failure + * @retval non-zero a re-allocation was necessary but failed */ -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); +#define cx_array_insert_sorted_a(allocator, array, element, cmp_func) \ + cx_array_insert_sorted_(allocator, (CxArray*)&(array), sizeof((array).data[0]), (void*)&(element), 1, cmp_func, true) /** * 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. + * When the capacity is not enough to hold the new element, a re-allocation is attempted. + * + * @attention if the array is not sorted according to the specified @p cmp_func, the behavior is undefined. + * + * @param array the name of the array where the elements shall be inserted + * @param element the element that shall be inserted + * @param cmp_func (@c cx_compare_func) the compare function that establishes the order + * @retval zero success + * @retval non-zero a re-allocation was necessary but failed + */ +#define cx_array_insert_sorted(array, element, cmp_func) \ + cx_array_insert_sorted_a(cxDefaultAllocator, array, element, cmp_func) + +/** + * Inserts sorted data into a sorted array. + * + * When the capacity is not enough to hold the new elements, a re-allocation is attempted. * - * If the capacity is not enough to hold the new data, a reallocation - * attempt is made. + * @attention if either array is not sorted according to the specified @p cmp_func, the behavior is undefined. * - * 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 allocator (@c CxAllocator*) the allocator to use for a possible reallocation + * @param array the name of the array where the elements shall be inserted + * @param sorted_data (@c void*) a pointer to an array of sorted data that shall be inserted + * @param n (@c size_t) the number of elements that shall be inserted + * @param cmp_func (@c cx_compare_func) the compare function that establishes the order + * @retval zero success + * @retval non-zero a re-allocation was necessary but failed + */ +#define cx_array_insert_sorted_array_a(allocator, array, sorted_data, n, cmp_func) \ + cx_array_insert_sorted_(allocator, (CxArray*)&(array), sizeof((array).data[0]), sorted_data, n, cmp_func, true) + +/** + * Inserts sorted data into a sorted array. + * + * When the capacity is not enough to hold the new elements, a re-allocation is attempted. + * + * @attention if either array is not sorted according to the specified @p cmp_func, the behavior is undefined. * - * @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 + * @param array the name of the array where the elements shall be inserted + * @param sorted_data (@c void*) a pointer to an array of sorted data that shall be inserted + * @param n (@c size_t) the number of elements that shall be inserted + * @param cmp_func (@c cx_compare_func) the compare function that establishes the order * @retval zero success - * @retval non-zero failure + * @retval non-zero a re-allocation was necessary but failed + */ +#define cx_array_insert_sorted_array(array, sorted_data, n, cmp_func) \ + cx_array_insert_sorted_array_a(cxDefaultAllocator, array, sorted_data, n, cmp_func) + +/** + * Inserts an element into a sorted array if it is not already contained. + * + * When the capacity is not enough to hold the new element, a re-allocation is attempted. + * + * @attention if the array is not sorted according to the specified @p cmp_func, the behavior is undefined. + * + * @param allocator (@c CxAllocator*) the allocator to use for a possible reallocation + * @param array the name of the array where the elements shall be inserted + * @param element the element that shall be inserted + * @param cmp_func (@c cx_compare_func) the compare function that establishes the order + * @retval zero success + * @retval non-zero a re-allocation was necessary but failed */ -#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) +#define cx_array_insert_unique_a(allocator, array, element, cmp_func) \ + cx_array_insert_sorted_(allocator, (CxArray*)&(array), sizeof((array).data[0]), (void*)&(element), 1, cmp_func, false) + +/** + * Inserts an element into a sorted array if it is not already contained. + * + * When the capacity is not enough to hold the new element, a re-allocation is attempted. + * + * @attention if the array is not sorted according to the specified @p cmp_func, the behavior is undefined. + * + * @param array the name of the array where the elements shall be inserted + * @param element the element that shall be inserted + * @param cmp_func (@c cx_compare_func) the compare function that establishes the order + * @retval zero success + * @retval non-zero a re-allocation was necessary but failed + */ +#define cx_array_insert_unique(array, element, cmp_func) \ + cx_array_insert_unique_a(cxDefaultAllocator, array, element, cmp_func) /** - * Convenience macro for cx_array_add_sorted() with a default - * layout and the specified reallocator. + * Inserts sorted data into a sorted array, skipping duplicates. + * + * When the capacity is not enough to hold the new elements, a re-allocation is attempted. + * + * @attention if either array is not sorted according to the specified @p cmp_func, the behavior is undefined. + * + * @param allocator (@c CxAllocator*) the allocator to use for a possible reallocation + * @param array the name of the array where the elements shall be inserted + * @param sorted_data (@c void*) a pointer to an array of sorted data that shall be inserted + * @param n (@c size_t) the number of elements that shall be inserted + * @param cmp_func (@c cx_compare_func) the compare function that establishes the order + * @retval zero success + * @retval non-zero a re-allocation was necessary but failed + */ +#define cx_array_insert_unique_array_a(allocator, array, sorted_data, n, cmp_func) \ + cx_array_insert_sorted_(allocator, (CxArray*)&(array), sizeof((array).data[0]), sorted_data, n, cmp_func, false) + +/** + * Inserts sorted data into a sorted array, skipping duplicates. + * + * When the capacity is not enough to hold the new elements, a re-allocation is attempted. + * + * @attention if either array is not sorted according to the specified @p cmp_func, the behavior is undefined. * - * @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 + * @param array the name of the array where the elements shall be inserted + * @param sorted_data (@c void*) a pointer to an array of sorted data that shall be inserted + * @param n (@c size_t) the number of elements that shall be inserted + * @param cmp_func (@c cx_compare_func) the compare function that establishes the order + * @retval zero success + * @retval non-zero a re-allocation was necessary but failed + */ +#define cx_array_insert_unique_array(array, sorted_data, n, cmp_func) \ + cx_array_insert_unique_array_a(cxDefaultAllocator, array, sorted_data, n, cmp_func) + +/** + * Inserts sorted data into a sorted array. + * + * Internal function - do not use. + * + * @param allocator the allocator to use for a possible reallocation + * @param array a pointer to the array structure + * @param elem_size the size of one element + * @param sorted_data a pointer to an array of data that shall be inserted + * @param n the number of elements that shall be inserted + * @param cmp_func the compare function + * @param context additional context for the compare function + * @param allow_duplicates @c false if duplicates shall be skipped during insertion * @retval zero success - * @retval non-zero failure - * @see CX_ARRAY_DECLARE() - * @see cx_array_simple_add_sorted() + * @retval non-zero a re-allocation was necessary but failed + */ +cx_attr_nonnull_arg(1, 2, 4, 6) +CX_EXPORT int cx_array_insert_sorted_c_(const CxAllocator *allocator, CxArray *array, + size_t elem_size, const void *sorted_data, size_t n, + cx_compare_func2 cmp_func, void *context, bool allow_duplicates); + +/** + * Inserts an element into a sorted array. + * + * When the capacity is not enough to hold the new element, a re-allocation is attempted. + * + * @attention if the array is not sorted according to the specified @p cmp_func, the behavior is undefined. + * + * @param allocator (@c CxAllocator*) the allocator to use for a possible reallocation + * @param array the name of the array where the elements shall be inserted + * @param element the element that shall be inserted + * @param cmp_func (@c cx_compare_func2) the compare function that establishes the order + * @param context (@c void*) additional context for the compare function + * @retval zero success + * @retval non-zero a re-allocation was necessary but failed */ -#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) +#define cx_array_insert_sorted_ca(allocator, array, element, cmp_func) \ + cx_array_insert_sorted_c_(allocator, (CxArray*)&(array), sizeof((array).data[0]), (void*)&(element), 1, cmp_func, context, true) + +/** + * Inserts an element into a sorted array. + * + * When the capacity is not enough to hold the new element, a re-allocation is attempted. + * + * @attention if the array is not sorted according to the specified @p cmp_func, the behavior is undefined. + * + * @param array the name of the array where the elements shall be inserted + * @param element the element that shall be inserted + * @param cmp_func (@c cx_compare_func2) the compare function that establishes the order + * @param context (@c void*) additional context for the compare function + * @retval zero success + * @retval non-zero a re-allocation was necessary but failed + */ +#define cx_array_insert_sorted_c(array, element, cmp_func, context) \ + cx_array_insert_sorted_ca(cxDefaultAllocator, array, element, cmp_func, context) + +/** + * Inserts sorted data into a sorted array. + * + * When the capacity is not enough to hold the new elements, a re-allocation is attempted. + * + * @attention if either array is not sorted according to the specified @p cmp_func, the behavior is undefined. + * + * @param allocator (@c CxAllocator*) the allocator to use for a possible reallocation + * @param array the name of the array where the elements shall be inserted + * @param sorted_data (@c void*) a pointer to an array of sorted data that shall be inserted + * @param n (@c size_t) the number of elements that shall be inserted + * @param cmp_func (@c cx_compare_func2) the compare function that establishes the order + * @param context (@c void*) additional context for the compare function + * @retval zero success + * @retval non-zero a re-allocation was necessary but failed + */ +#define cx_array_insert_sorted_array_ca(allocator, array, sorted_data, n, cmp_func, context) \ + cx_array_insert_sorted_c_(allocator, (CxArray*)&(array), sizeof((array).data[0]), sorted_data, n, cmp_func, context, true) /** - * Convenience macro for cx_array_add_sorted() with a default - * layout and the default reallocator. + * Inserts sorted data into a sorted array. + * + * When the capacity is not enough to hold the new elements, a re-allocation is attempted. + * + * @attention if either array is not sorted according to the specified @p cmp_func, the behavior is undefined. * - * @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 + * @param array the name of the array where the elements shall be inserted + * @param sorted_data (@c void*) a pointer to an array of sorted data that shall be inserted + * @param n (@c size_t) the number of elements that shall be inserted + * @param cmp_func (@c cx_compare_func2) the compare function that establishes the order + * @param context (@c void*) additional context for the compare function + * @retval zero success + * @retval non-zero a re-allocation was necessary but failed + */ +#define cx_array_insert_sorted_array_c(array, sorted_data, n, cmp_func, context) \ + cx_array_insert_sorted_array_ca(cxDefaultAllocator, array, sorted_data, n, cmp_func, context) + +/** + * Inserts an element into a sorted array if it is not already contained. + * + * When the capacity is not enough to hold the new element, a re-allocation is attempted. + * + * @attention if the array is not sorted according to the specified @p cmp_func, the behavior is undefined. + * + * @param allocator (@c CxAllocator*) the allocator to use for a possible reallocation + * @param array the name of the array where the elements shall be inserted + * @param element the element that shall be inserted + * @param cmp_func (@c cx_compare_func2) the compare function that establishes the order + * @param context (@c void*) additional context for the compare function * @retval zero success - * @retval non-zero failure - * @see CX_ARRAY_DECLARE() - * @see cx_array_simple_add_sorted_a() + * @retval non-zero a re-allocation was necessary but failed + */ +#define cx_array_insert_unique_ca(allocator, array, element, cmp_func, context) \ + cx_array_insert_sorted_c_(allocator, (CxArray*)&(array), sizeof((array).data[0]), (void*)&(element), 1, cmp_func, context, false) + +/** + * Inserts an element into a sorted array if it is not already contained. + * + * When the capacity is not enough to hold the new element, a re-allocation is attempted. + * + * @attention if the array is not sorted according to the specified @p cmp_func, the behavior is undefined. + * + * @param array the name of the array where the elements shall be inserted + * @param element the element that shall be inserted + * @param cmp_func (@c cx_compare_func2) the compare function that establishes the order + * @param context (@c void*) additional context for the compare function + * @retval zero success + * @retval non-zero a re-allocation was necessary but failed */ -#define cx_array_simple_add_sorted(array, elem, cmp_func) \ - cx_array_simple_add_sorted_a(NULL, array, elem, cmp_func) +#define cx_array_insert_unique_c(array, element, cmp_func, context) \ + cx_array_insert_unique_ca(cxDefaultAllocator, array, element, cmp_func, context) + +/** + * Inserts sorted data into a sorted array, skipping duplicates. + * + * When the capacity is not enough to hold the new elements, a re-allocation is attempted. + * + * @attention if either array is not sorted according to the specified @p cmp_func, the behavior is undefined. + * + * @param allocator (@c CxAllocator*) the allocator to use for a possible reallocation + * @param array the name of the array where the elements shall be inserted + * @param sorted_data (@c void*) a pointer to an array of sorted data that shall be inserted + * @param n (@c size_t) the number of elements that shall be inserted + * @param cmp_func (@c cx_compare_func2) the compare function that establishes the order + * @param context (@c void*) additional context for the compare function + * @retval zero success + * @retval non-zero a re-allocation was necessary but failed + */ +#define cx_array_insert_unique_array_ca(allocator, array, sorted_data, n, cmp_func, context) \ + cx_array_insert_sorted_c_(allocator, (CxArray*)&(array), sizeof((array).data[0]), sorted_data, n, cmp_func, context, false) + +/** + * Inserts sorted data into a sorted array, skipping duplicates. + * + * When the capacity is not enough to hold the new elements, a re-allocation is attempted. + * + * @attention if either array is not sorted according to the specified @p cmp_func, the behavior is undefined. + * + * @param array the name of the array where the elements shall be inserted + * @param sorted_data (@c void*) a pointer to an array of sorted data that shall be inserted + * @param n (@c size_t) the number of elements that shall be inserted + * @param cmp_func (@c cx_compare_func2) the compare function that establishes the order + * @param context (@c void*) additional context for the compare function + * @retval zero success + * @retval non-zero a re-allocation was necessary but failed + */ +#define cx_array_insert_unique_array_c(array, sorted_data, n, cmp_func, context) \ + cx_array_insert_unique_array_ca(cxDefaultAllocator, array, sorted_data, n, cmp_func, context) /** - * Convenience macro for cx_array_insert_sorted() with a default - * layout and the specified reallocator. + * An alternative to qsort_r() when that is not available on your platform. + * + * If it is available, qsort_r() is used directly. + * + * @param array the array that shall be sorted + * @param nmemb the number of elements in the array + * @param size the size of one element + * @param fn the compare function + * @param context the context for the compare function + */ +CX_EXPORT void cx_array_qsort_c(void *array, size_t nmemb, size_t size, + cx_compare_func2 fn, void *context); + +/** + * Sorts an array. + * + * Internal function - do not use. * - * @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() + * @param array a pointer to the array structure + * @param elem_size the size of one element + * @param fn the compare function */ -#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) +CX_EXPORT void cx_array_sort_(CxArray *array, size_t elem_size, + cx_compare_func fn); + +/** + * Sorts an array. + * + * Internal function - do not use. + * + * @param array a pointer to the array structure + * @param elem_size the size of one element + * @param fn the compare function + * @param context the context for the compare function + */ +CX_EXPORT void cx_array_sort_c_(CxArray *array, size_t elem_size, + cx_compare_func2 fn, void *context); + +/** + * Sorts an array. + * + * @param array the name of the array + * @param fn (@c cx_compare_func) the compare function + * @param context (@c void*) the context for the compare function + */ +#define cx_array_sort(array, fn) \ + cx_array_sort_((CxArray*)&(array), sizeof((array).data[0]), fn) /** - * Convenience macro for cx_array_insert_sorted() with a default - * layout and the default reallocator. + * Sorts an array. + * + * @param array the name of the array + * @param fn (@c cx_compare_func2) the compare function + * @param context (@c void*) the context for the compare function + */ +#define cx_array_sort_c(array, fn, context) \ + cx_array_sort_c_((CxArray*)&(array), sizeof((array).data[0]), fn, context) + +/** + * Creates an iterator over the elements of an array. + * + * Internal function - do not use. + * + * @param array a pointer to the array structure + * @param elem_size the size of one element + * @return an iterator over the elements + */ +cx_attr_nodiscard cx_attr_nonnull +CX_EXPORT CxIterator cx_array_iterator_(CxArray *array, size_t elem_size); + +/** + * Creates an iterator over the elements of an array. + * + * The iterator will yield pointers to the elements. + * + * This iterator cannot be used to remove elements + * because it does not get a modifiable reference to the array's size. * - * @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() + * @param array the name of the array + * @return an iterator over the elements + * @see cx_array_iterator_ptr() + */ +#define cx_array_iterator(array) \ + cx_array_iterator_((CxArray*)&(array), sizeof((array).data[0])) + +/** + * Creates an iterator over the elements of an array containing pointers. + * + * Internal function - do not use. + * + * @param array the name of the array + * @return an iterator over the elements */ -#define cx_array_simple_insert_sorted(array, src, n, cmp_func) \ - cx_array_simple_insert_sorted_a(NULL, array, src, n, cmp_func) +cx_attr_nodiscard cx_attr_nonnull +CX_EXPORT CxIterator cx_array_iterator_ptr_(CxArray *array); + +/** + * Creates an iterator over the elements of an array containing pointers. + * + * The iterator will yield the elements themselves, which are supposed to + * be pointers. + * + * This iterator cannot be used to remove elements + * because it does not get a modifiable reference to the array's size. + * + * @param array the name of the array + * @return an iterator over the elements + * @see cx_array_iterator() + */ +#define cx_array_iterator_ptr(array) \ + cx_array_iterator_ptr_((CxArray*)&(array)) /** - * 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. + * Removes elements from the array. * - * 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. + * Internal function - do not use. * - * @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 array a pointer to the array structure * @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 + * @param index the index of the first element to remove + * @param n the number of elements to remove + * @param fast indicates whether tail elements should be copied into the gap */ -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); +cx_attr_nonnull +CX_EXPORT void cx_array_remove_(CxArray *array, size_t elem_size, size_t index, size_t n, bool fast); /** - * 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. + * Removes one element from the array. * - * If the capacity is insufficient to hold the new data, a reallocation - * attempt is made. + * Tail elements are all moved by one. If you don't need a stable order + * in the array, consider using cx_array_remove_fast(). * - * 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. + * If the index is out of bounds, this function does nothing. * - * @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 + * @param array the name of the array + * @param index (@c size_t) the index of the element to remove + * @see cx_array_remove_fast() */ -#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) +#define cx_array_remove(array, index) \ + cx_array_remove_((CxArray*)&(array), sizeof((array).data[0]), index, 1, false) + +/** + * Removes one element from the array. + * + * The gap will be filled with a copy of the last element in the array. + * This changes the order of elements. If you want a stable order, + * use cx_array_remove() instead. + * + * If the index is out of bounds, this function does nothing. + * + * @param array the name of the array + * @param index (@c size_t) the index of the element to remove + * @see cx_array_remove() + */ +#define cx_array_remove_fast(array, index) \ + cx_array_remove_((CxArray*)&(array), sizeof((array).data[0]), index, 1, true) /** - * Convenience macro for cx_array_add_unique() with a default - * layout and the specified reallocator. + * Removes multiple elements from the array. + * + * Tail elements are all moved to close the gap. If you don't need a stable + * order in the array, consider using cx_array_remove_array_fast(). * - * @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() + * If the index is out of bounds, this function does nothing. + * If @n overflows the array, this function removes as many elements as it can. + * + * @param array the name of the array + * @param index (@c size_t) the index of the first element to remove + * @param n (@c size_t) the number of elements to remove + * @see cx_array_remove_array_fast() */ -#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) +#define cx_array_remove_array(array, index, n) \ + cx_array_remove_((CxArray*)&(array), sizeof((array).data[0]), index, n, false) /** - * Convenience macro for cx_array_insert_unique() with a default - * layout and the specified reallocator. + * Removes multiple elements from the array. + * + * Tail elements are copied into the gap. If you have more tail elements + * than the number of elements that are removed, this will change the order + * of elements. If you want a stable order, use cx_array_remove_array() instead. * - * @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() + * If the index is out of bounds, this function does nothing. + * If @n overflows the array, this function removes as many elements as it can. + * + * @param array the name of the array + * @param index (@c size_t) the index of the first element to remove + * @param n (@c size_t) the number of elements to remove + * @see cx_array_remove_array() */ -#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) +#define cx_array_remove_array_fast(array, index, n) \ + cx_array_remove_((CxArray*)&(array), sizeof((array).data[0]), index, n, true) /** - * Convenience macro for cx_array_insert_unique() with a default - * layout and the default reallocator. + * Deallocates an array. + * + * Internal function - do not use. + * + * @param allocator (@c CxAllocator*) the allocator which was used to allocate the array + * @param array a pointer to the array structure + */ +cx_attr_nonnull +CX_EXPORT void cx_array_free_(const CxAllocator *allocator, CxArray *array); + +/** + * Deallocates an array. + * + * The structure is reset to zero and can be re-initialized with + * cx_array_inita(). * - * @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() + * @param array the name of the array */ -#define cx_array_simple_insert_unique(array, src, n, cmp_func) \ - cx_array_simple_insert_unique_a(NULL, array, src, n, cmp_func) +#define cx_array_free(array) cx_array_free_(cxDefaultAllocator, (CxArray*)&(array)) + +/** + * Deallocates an array. + * + * The structure is reset to zero and can be re-initialized with + * cx_array_init_a(). + * + * @param allocator (@c CxAllocator*) the allocator which was used to allocate the array + * @param array the name of the array + */ +#define cx_array_free_a(allocator, array) cx_array_free_(allocator, (CxArray*)&(array)) + /** * Searches the largest lower bound in a sorted array. @@ -669,6 +944,9 @@ * in @p arr that is less or equal to @p elem with respect to @p cmp_func. * When no such element exists, @p size is returned. * + * When such an element exists more than once, the largest index of all those + * elements is returned. + * * If @p elem is contained in the array, this is identical to * #cx_array_binary_search(). * @@ -691,6 +969,9 @@ /** * Searches an item in a sorted array. * + * When such an element exists more than once, the largest index of all those + * elements is returned. + * * If the array is not sorted with respect to the @p cmp_func, the behavior * is undefined. * @@ -715,6 +996,9 @@ * in @p arr that is greater or equal to @p elem with respect to @p cmp_func. * When no such element exists, @p size is returned. * + * When such an element exists more than once, the smallest index of all those + * elements is returned. + * * If @p elem is contained in the array, this is identical to * #cx_array_binary_search(). * @@ -734,6 +1018,91 @@ 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); + +/** + * Searches the largest lower bound in a sorted array. + * + * In other words, this function returns the index of the largest element + * in @p arr that is less or equal to @p elem with respect to @p cmp_func. + * When no such element exists, @p size is returned. + * + * When such an element exists more than once, the largest index of all those + * elements is returned. + * + * If @p elem is contained in the array, this is identical to + * #cx_array_binary_search(). + * + * If the array is not sorted with respect to the @p cmp_func, the behavior + * is undefined. + * + * @param arr the array to search + * @param size the size of the array + * @param elem_size the size of one element + * @param elem the element to find + * @param cmp_func the compare function + * @param context the context for the compare function + * @return the index of the largest lower bound, or @p size + * @see cx_array_binary_search_sup() + * @see cx_array_binary_search() + */ +cx_attr_nonnull +CX_EXPORT size_t cx_array_binary_search_inf_c(const void *arr, size_t size, + size_t elem_size, const void *elem, cx_compare_func2 cmp_func, void *context); + +/** + * Searches an item in a sorted array. + * + * When such an element exists more than once, the largest index of all those + * elements is returned. + * + * If the array is not sorted with respect to the @p cmp_func, the behavior + * is undefined. + * + * @param arr the array to search + * @param size the size of the array + * @param elem_size the size of one element + * @param elem the element to find + * @param cmp_func the compare function + * @param context the context for the compare function + * @return the index of the element in the array, or @p size if the element + * cannot be found + * @see cx_array_binary_search_inf() + * @see cx_array_binary_search_sup() + */ +cx_attr_nonnull +CX_EXPORT size_t cx_array_binary_search_c(const void *arr, size_t size, + size_t elem_size, const void *elem, cx_compare_func2 cmp_func, void *context); + +/** + * Searches the smallest upper bound in a sorted array. + * + * In other words, this function returns the index of the smallest element + * in @p arr that is greater or equal to @p elem with respect to @p cmp_func. + * When no such element exists, @p size is returned. + * + * When such an element exists more than once, the smallest index of all those + * elements is returned. + * + * If @p elem is contained in the array, this is identical to + * #cx_array_binary_search(). + * + * If the array is not sorted with respect to the @p cmp_func, the behavior + * is undefined. + * + * @param arr the array to search + * @param size the size of the array + * @param elem_size the size of one element + * @param elem the element to find + * @param cmp_func the compare function + * @param context the context for the compare function + * @return the index of the smallest upper bound, or @p size + * @see cx_array_binary_search_inf() + * @see cx_array_binary_search() + */ +cx_attr_nonnull +CX_EXPORT size_t cx_array_binary_search_sup_c(const void *arr, size_t size, + size_t elem_size, const void *elem, cx_compare_func2 cmp_func, void *context); + /** * Swaps two array elements. * @@ -750,13 +1119,10 @@ * * 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 allocator the allocator for allocating the list memory * (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) * @param elem_size the size of each element in bytes * @param initial_capacity the initial number of elements the array can store * @return the created list @@ -765,25 +1131,7 @@ cx_attr_malloc cx_attr_dealloc(cxListFree, 1) 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. - * - * The list will use the cxDefaultAllocator and @em NO compare function. - * If you want to call functions that need a compare function, you have to - * set it immediately after creation or use cxArrayListCreate(). - * - * 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(). - * - * @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 - * @return the created list - */ -#define cxArrayListCreateSimple(elem_size, initial_capacity) \ - cxArrayListCreate(NULL, NULL, elem_size, initial_capacity) + size_t elem_size, size_t initial_capacity); #ifdef __cplusplus } // extern "C"