--- a/ucx/array_list.c Tue Dec 30 21:39:38 2025 +0100 +++ b/ucx/array_list.c Wed Dec 31 16:41:16 2025 +0100 @@ -101,11 +101,18 @@ if (index > array->size) return -1; if (n == 0) return 0; + // calculate required capacity + size_t req_capacity = array->size + n; + if (req_capacity <= array->size) { + errno = EOVERFLOW; + return -1; + } + // guarantee enough capacity - if (array->capacity < array->size + n) { - const size_t new_capacity = cx_array_grow_capacity(array->capacity,array->size + n); + if (array->capacity < req_capacity) { + const size_t new_capacity = cx_array_grow_capacity(array->capacity,req_capacity); if (cxReallocateArray(allocator, &array->data, new_capacity, elem_size)) { - return -1; // LCOV_EXCL_LINE + return -1; } array->capacity = new_capacity; } @@ -115,8 +122,8 @@ dst += index * elem_size; // do we need to move some elements? - if (index < array->size) { - size_t elems_to_move = array->size - index; + size_t elems_to_move = array->size - index; + if (elems_to_move > 0) { char *target = dst + n * elem_size; memmove(target, dst, elems_to_move * elem_size); } @@ -314,7 +321,9 @@ left_src += elem_size; skip_len++; } else { - break; + // should be unreachable because the requirement is + // that the source array is sorted + break; // LCOV_EXCL_LINE } } } @@ -350,22 +359,42 @@ ) { cx_compare_func_wrapper wrapper = {cmp_func}; return cx_array_insert_sorted_c_(allocator, array, elem_size, sorted_data, - n, cx_ccmp_wrap, &wrapper, allow_duplicates); + n, cx_cmp_wrap, &wrapper, allow_duplicates); } #ifndef WITH_QSORT_R -static thread_local cx_compare_func2 cx_array_fn_for_qsort; -static thread_local void *cx_array_context_for_qsort; +static cx_thread_local cx_compare_func2 cx_array_fn_for_qsort; +static cx_thread_local void *cx_array_context_for_qsort; static int cx_array_qsort_wrapper(const void *l, const void *r) { return cx_array_fn_for_qsort(l, r, cx_array_context_for_qsort); } #endif +#if defined(WITH_QSORT_R) && defined(__APPLE__) +// macOS uses a different comparefunc signature for qsort_r +typedef struct QsortCmpFuncWrapper { + cx_compare_func2 fn; + void *context; +} QsortCmpFuncWrapper; + +static int sort_comparefunc(void *context, const void *left, const void *right){ + QsortCmpFuncWrapper *w = context; + return w->fn(left, right, w->context); +} +#endif + void cx_array_qsort_c(void *array, size_t nmemb, size_t size, cx_compare_func2 fn, void *context) { #ifdef WITH_QSORT_R +#ifndef __APPLE__ qsort_r(array, nmemb, size, fn, context); #else + QsortCmpFuncWrapper wrapper; + wrapper.fn = fn; + wrapper.context = context; + qsort_r(array, nmemb, size, &wrapper, sort_comparefunc); +#endif +#else cx_array_fn_for_qsort = fn; cx_array_context_for_qsort = context; qsort(array, nmemb, size, cx_array_qsort_wrapper); @@ -578,7 +607,7 @@ cx_compare_func cmp_func ) { cx_compare_func_wrapper wrapper = {cmp_func}; - return cx_array_binary_search_inf_c(arr, size, elem_size, elem, cx_ccmp_wrap, &wrapper); + return cx_array_binary_search_inf_c(arr, size, elem_size, elem, cx_cmp_wrap, &wrapper); } size_t cx_array_binary_search( @@ -589,7 +618,7 @@ cx_compare_func cmp_func ) { cx_compare_func_wrapper wrapper = {cmp_func}; - return cx_array_binary_search_c(arr, size, elem_size, elem, cx_ccmp_wrap, &wrapper); + return cx_array_binary_search_c(arr, size, elem_size, elem, cx_cmp_wrap, &wrapper); } size_t cx_array_binary_search_sup( @@ -600,7 +629,7 @@ cx_compare_func cmp_func ) { cx_compare_func_wrapper wrapper = {cmp_func}; - return cx_array_binary_search_sup_c(arr, size, elem_size, elem, cx_ccmp_wrap, &wrapper); + return cx_array_binary_search_sup_c(arr, size, elem_size, elem, cx_cmp_wrap, &wrapper); } #ifndef CX_ARRAY_SWAP_SBO_SIZE @@ -1064,8 +1093,7 @@ cx_array_list *list = cxCalloc(allocator, 1, sizeof(cx_array_list)); if (list == NULL) return NULL; - cx_list_init((CxList*)list, &cx_array_list_class, - allocator, elem_size); + cx_list_init((CxList*)list, &cx_array_list_class, allocator, elem_size); list->capacity = initial_capacity; // allocate the array after the real elem_size is known