ucx/cx/array_list.h

changeset 888
af685cc9d623
parent 854
1c8401ece69e
--- 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

mercurial