From: Olaf Wintermann Date: Sun, 4 Jan 2026 17:16:15 +0000 (+0100) Subject: update ucx to version 4.0 X-Git-Url: https://uap-core.de/gitweb/?a=commitdiff_plain;p=uwplayer.git update ucx to version 4.0 --- diff --git a/application/utils.c b/application/utils.c index 5d18fdb..f3f7dc4 100644 --- a/application/utils.c +++ b/application/utils.c @@ -55,9 +55,9 @@ char* util_concat_path(const char *url_base, const char *p) { cxmutstr url; if(add_separator) { - url = cx_strcat(3, base, cx_strn("/", 1), path); + url = cx_strcat(CX_NULLSTR, 3, base, cx_strn("/", 1), path); } else { - url = cx_strcat(2, base, path); + url = cx_strcat(CX_NULLSTR, 2, base, path); } return url.ptr; diff --git a/ucx/allocator.c b/ucx/allocator.c index bb01129..c07406b 100644 --- a/ucx/allocator.c +++ b/ucx/allocator.c @@ -61,14 +61,14 @@ unsigned long cx_system_page_size(void) { #endif static void *cx_malloc_stdlib( - cx_attr_unused void *d, + CX_UNUSED void *d, size_t n ) { return malloc(n); } static void *cx_realloc_stdlib( - cx_attr_unused void *d, + CX_UNUSED void *d, void *mem, size_t n ) { @@ -76,7 +76,7 @@ static void *cx_realloc_stdlib( } static void *cx_calloc_stdlib( - cx_attr_unused void *d, + CX_UNUSED void *d, size_t nmemb, size_t size ) { @@ -84,7 +84,7 @@ static void *cx_calloc_stdlib( } static void cx_free_stdlib( - cx_attr_unused void *d, + CX_UNUSED void *d, void *mem ) { free(mem); diff --git a/ucx/array_list.c b/ucx/array_list.c index 9867b41..98b0ca7 100644 --- a/ucx/array_list.c +++ b/ucx/array_list.c @@ -112,7 +112,7 @@ int cx_array_insert_(const CxAllocator *allocator, CxArray *array, 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; } @@ -370,10 +370,30 @@ static int cx_array_qsort_wrapper(const void *l, const void *r) { } #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; diff --git a/ucx/cx/allocator.h b/ucx/cx/allocator.h index 1549b8d..ff6b287 100644 --- a/ucx/cx/allocator.h +++ b/ucx/cx/allocator.h @@ -35,10 +35,6 @@ #include "common.h" -#ifdef __cplusplus -extern "C" { -#endif - /** * The class definition for an allocator. */ @@ -153,8 +149,8 @@ typedef void*(*cx_clone_func)(void *target, const void *source, * * @return the system's memory page size in bytes */ -cx_attr_nodiscard -CX_EXPORT unsigned long cx_system_page_size(void); +CX_EXTERN CX_NODISCARD +unsigned long cx_system_page_size(void); /** * Reallocate a previously allocated block. @@ -167,8 +163,8 @@ CX_EXPORT unsigned long cx_system_page_size(void); * @retval non-zero failure * @see cx_reallocatearray() */ -cx_attr_nonnull cx_attr_nodiscard -CX_EXPORT int cx_reallocate_(void **mem, size_t n); +CX_EXTERN CX_NONNULL CX_NODISCARD +int cx_reallocate_(void **mem, size_t n); /** * Reallocate a previously allocated block. @@ -182,8 +178,8 @@ CX_EXPORT int cx_reallocate_(void **mem, size_t n); * @retval non-zero failure * @see cx_reallocate() */ -cx_attr_nonnull cx_attr_nodiscard -CX_EXPORT int cx_reallocatearray_(void **mem, size_t nmemb, size_t size); +CX_EXTERN CX_NONNULL CX_NODISCARD +int cx_reallocatearray_(void **mem, size_t nmemb, size_t size); /** * Reallocate a previously allocated block and changes the pointer in-place, @@ -239,8 +235,8 @@ CX_EXPORT int cx_reallocatearray_(void **mem, size_t nmemb, size_t size); * @param allocator the allocator * @param mem a pointer to the block to free */ -cx_attr_nonnull_arg(1) -CX_EXPORT void cxFree(const CxAllocator *allocator, void *mem); +CX_EXTERN CX_NONNULL_ARG(1) +void cxFree(const CxAllocator *allocator, void *mem); /** * Allocate @p n bytes of memory. @@ -249,9 +245,9 @@ CX_EXPORT void cxFree(const CxAllocator *allocator, void *mem); * @param n the number of bytes * @return a pointer to the allocated memory */ -cx_attr_nodiscard cx_attr_nonnull -cx_attr_malloc cx_attr_dealloc_ucx cx_attr_allocsize(2) -CX_EXPORT void *cxMalloc(const CxAllocator *allocator, size_t n); +CX_EXTERN CX_NODISCARD CX_NONNULL +CX_MALLOC CX_DEALLOC_UCX CX_ALLOCSIZE(2) +void *cxMalloc(const CxAllocator *allocator, size_t n); /** * Reallocate the previously allocated block in @p mem, making the new block @@ -268,9 +264,9 @@ CX_EXPORT void *cxMalloc(const CxAllocator *allocator, size_t n); * @param n the new size in bytes * @return a pointer to the reallocated memory */ -cx_attr_nodiscard cx_attr_nonnull_arg(1) -cx_attr_dealloc_ucx cx_attr_allocsize(3) -CX_EXPORT void *cxRealloc(const CxAllocator *allocator, void *mem, size_t n); +CX_EXTERN CX_NODISCARD CX_NONNULL_ARG(1) +CX_DEALLOC_UCX CX_ALLOCSIZE(3) +void *cxRealloc(const CxAllocator *allocator, void *mem, size_t n); /** * Reallocate the previously allocated block in @p mem. @@ -292,9 +288,9 @@ CX_EXPORT void *cxRealloc(const CxAllocator *allocator, void *mem, size_t n); * @param size the size of each element * @return a pointer to the reallocated memory */ -cx_attr_nodiscard cx_attr_nonnull_arg(1) -cx_attr_dealloc_ucx cx_attr_allocsize(3, 4) -CX_EXPORT void *cxReallocArray(const CxAllocator *allocator, +CX_EXTERN CX_NODISCARD CX_NONNULL_ARG(1) +CX_DEALLOC_UCX CX_ALLOCSIZE(3, 4) +void *cxReallocArray(const CxAllocator *allocator, void *mem, size_t nmemb, size_t size); /** @@ -308,8 +304,8 @@ CX_EXPORT void *cxReallocArray(const CxAllocator *allocator, * @retval zero success * @retval non-zero failure */ -cx_attr_nodiscard cx_attr_nonnull -CX_EXPORT int cxReallocate_(const CxAllocator *allocator, void **mem, size_t n); +CX_EXTERN CX_NODISCARD CX_NONNULL +int cxReallocate_(const CxAllocator *allocator, void **mem, size_t n); /** * Reallocate a previously allocated block and changes the pointer in-place, @@ -342,8 +338,8 @@ CX_EXPORT int cxReallocate_(const CxAllocator *allocator, void **mem, size_t n); * @retval zero success * @retval non-zero on failure */ -cx_attr_nodiscard cx_attr_nonnull -CX_EXPORT int cxReallocateArray_(const CxAllocator *allocator, +CX_EXTERN CX_NODISCARD CX_NONNULL +int cxReallocateArray_(const CxAllocator *allocator, void **mem, size_t nmemb, size_t size); /** @@ -376,9 +372,9 @@ CX_EXPORT int cxReallocateArray_(const CxAllocator *allocator, * @param size the size of each element in bytes * @return a pointer to the allocated memory */ -cx_attr_nonnull_arg(1) cx_attr_nodiscard -cx_attr_malloc cx_attr_dealloc_ucx cx_attr_allocsize(2, 3) -CX_EXPORT void *cxCalloc(const CxAllocator *allocator, size_t nmemb, size_t size); +CX_EXTERN CX_NONNULL_ARG(1) CX_NODISCARD +CX_MALLOC CX_DEALLOC_UCX CX_ALLOCSIZE(2, 3) +void *cxCalloc(const CxAllocator *allocator, size_t nmemb, size_t size); /** * Allocate @p n bytes of memory and sets every byte to zero. @@ -387,9 +383,9 @@ CX_EXPORT void *cxCalloc(const CxAllocator *allocator, size_t nmemb, size_t size * @param n the number of bytes * @return a pointer to the allocated memory */ -cx_attr_nodiscard cx_attr_nonnull -cx_attr_malloc cx_attr_dealloc_ucx cx_attr_allocsize(2) -CX_EXPORT void *cxZalloc(const CxAllocator *allocator, size_t n); +CX_EXTERN CX_NODISCARD CX_NONNULL +CX_MALLOC CX_DEALLOC_UCX CX_ALLOCSIZE(2) +void *cxZalloc(const CxAllocator *allocator, size_t n); /** * Allocate @p n bytes of memory. @@ -510,10 +506,7 @@ CX_EXPORT void *cxZalloc(const CxAllocator *allocator, size_t n); * * @param mem the memory to deallocate */ -CX_EXPORT void cxFreeDefault(void *mem); - -#ifdef __cplusplus -} // extern "C" -#endif +CX_EXTERN +void cxFreeDefault(void *mem); #endif // UCX_ALLOCATOR_H diff --git a/ucx/cx/array_list.h b/ucx/cx/array_list.h index fd76c37..e415f45 100644 --- a/ucx/cx/array_list.h +++ b/ucx/cx/array_list.h @@ -39,10 +39,6 @@ #include "list.h" -#ifdef __cplusplus -extern "C" { -#endif - /** * The maximum item size in an array list that fits into * a stack buffer when swapped. @@ -88,8 +84,8 @@ typedef struct cx_array_s { * @retval zero allocation was successful * @retval non-zero allocation failed */ -cx_attr_nonnull -CX_EXPORT int cx_array_init_(const CxAllocator *allocator, CxArray *array, size_t elem_size, size_t capacity); +CX_EXTERN CX_NONNULL +int cx_array_init_(const CxAllocator *allocator, CxArray *array, size_t elem_size, size_t capacity); /** * Initializes an array by allocating memory. @@ -131,8 +127,8 @@ CX_EXPORT int cx_array_init_(const CxAllocator *allocator, CxArray *array, size_ * @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); +CX_EXTERN CX_NONNULL +void cx_array_init_fixed_(CxArray *array, const void *data, size_t capacity, size_t size); /** * Initializes an array with fixed size memory. @@ -173,8 +169,8 @@ CX_EXPORT void cx_array_init_fixed_(CxArray *array, const void *data, size_t cap * @retval zero allocation was successful * @retval non-zero allocation failed */ -cx_attr_nonnull -CX_EXPORT int cx_array_reserve_(const CxAllocator *allocator, CxArray *array, size_t elem_size, size_t capacity); +CX_EXTERN CX_NONNULL +int cx_array_reserve_(const CxAllocator *allocator, CxArray *array, size_t elem_size, size_t capacity); /** * Changes the capacity of an array. @@ -215,8 +211,8 @@ CX_EXPORT int cx_array_reserve_(const CxAllocator *allocator, CxArray *array, si * @retval zero allocation was successful * @retval non-zero allocation failed */ -cx_attr_nonnull -CX_EXPORT int cx_array_copy_to_new_(const CxAllocator *allocator, CxArray *array, size_t elem_size, size_t capacity); +CX_EXTERN CX_NONNULL +int cx_array_copy_to_new_(const CxAllocator *allocator, CxArray *array, size_t elem_size, size_t capacity); /** * Copies the array to a new memory region. @@ -269,8 +265,8 @@ CX_EXPORT int cx_array_copy_to_new_(const CxAllocator *allocator, CxArray *array * @retval zero success * @retval non-zero a re-allocation was necessary but failed */ -cx_attr_nonnull_arg(1, 2) -CX_EXPORT int cx_array_insert_(const CxAllocator *allocator, CxArray *array, +CX_EXTERN CX_NONNULL_ARG(1, 2) +int cx_array_insert_(const CxAllocator *allocator, CxArray *array, size_t elem_size, size_t index, const void *other, size_t n); /** @@ -404,8 +400,8 @@ CX_EXPORT int cx_array_insert_(const CxAllocator *allocator, CxArray *array, * @retval zero success * @retval non-zero a re-allocation was necessary but failed */ -cx_attr_nonnull -CX_EXPORT int cx_array_insert_sorted_(const CxAllocator *allocator, CxArray *array, +CX_EXTERN CX_NONNULL +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); @@ -561,8 +557,8 @@ CX_EXPORT int cx_array_insert_sorted_(const CxAllocator *allocator, CxArray *arr * @retval zero success * @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, +CX_EXTERN CX_NONNULL_ARG(1, 2, 4, 6) +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); @@ -581,7 +577,7 @@ CX_EXPORT int cx_array_insert_sorted_c_(const CxAllocator *allocator, CxArray *a * @retval zero success * @retval non-zero a re-allocation was necessary but failed */ -#define cx_array_insert_sorted_ca(allocator, array, element, cmp_func) \ +#define cx_array_insert_sorted_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, true) /** @@ -721,7 +717,8 @@ CX_EXPORT int cx_array_insert_sorted_c_(const CxAllocator *allocator, CxArray *a * @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_EXTERN CX_NONNULL +void cx_array_qsort_c(void *array, size_t nmemb, size_t size, cx_compare_func2 fn, void *context); /** @@ -733,7 +730,8 @@ CX_EXPORT void cx_array_qsort_c(void *array, size_t nmemb, size_t size, * @param elem_size the size of one element * @param fn the compare function */ -CX_EXPORT void cx_array_sort_(CxArray *array, size_t elem_size, +CX_EXTERN CX_NONNULL +void cx_array_sort_(CxArray *array, size_t elem_size, cx_compare_func fn); /** @@ -746,7 +744,8 @@ CX_EXPORT void cx_array_sort_(CxArray *array, size_t elem_size, * @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_EXTERN CX_NONNULL +void cx_array_sort_c_(CxArray *array, size_t elem_size, cx_compare_func2 fn, void *context); /** @@ -754,7 +753,6 @@ CX_EXPORT void cx_array_sort_c_(CxArray *array, size_t elem_size, * * @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) @@ -778,8 +776,8 @@ CX_EXPORT void cx_array_sort_c_(CxArray *array, size_t elem_size, * @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); +CX_EXTERN CX_NODISCARD CX_NONNULL +CxIterator cx_array_iterator_(CxArray *array, size_t elem_size); /** * Creates an iterator over the elements of an array. @@ -804,8 +802,8 @@ CX_EXPORT CxIterator cx_array_iterator_(CxArray *array, size_t elem_size); * @param array the name of the array * @return an iterator over the elements */ -cx_attr_nodiscard cx_attr_nonnull -CX_EXPORT CxIterator cx_array_iterator_ptr_(CxArray *array); +CX_EXTERN CX_NODISCARD CX_NONNULL +CxIterator cx_array_iterator_ptr_(CxArray *array); /** * Creates an iterator over the elements of an array containing pointers. @@ -835,8 +833,8 @@ CX_EXPORT CxIterator cx_array_iterator_ptr_(CxArray *array); * @param n the number of elements to remove * @param fast indicates whether tail elements should be copied into the gap */ -cx_attr_nonnull -CX_EXPORT void cx_array_remove_(CxArray *array, size_t elem_size, size_t index, size_t n, bool fast); +CX_EXTERN CX_NONNULL +void cx_array_remove_(CxArray *array, size_t elem_size, size_t index, size_t n, bool fast); /** * Removes one element from the array. @@ -912,8 +910,8 @@ CX_EXPORT void cx_array_remove_(CxArray *array, size_t elem_size, size_t index, * @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); +CX_EXTERN CX_NONNULL +void cx_array_free_(const CxAllocator *allocator, CxArray *array); /** * Deallocates an array. @@ -962,8 +960,8 @@ CX_EXPORT void cx_array_free_(const CxAllocator *allocator, CxArray *array); * @see cx_array_binary_search_sup() * @see cx_array_binary_search() */ -cx_attr_nonnull -CX_EXPORT size_t cx_array_binary_search_inf(const void *arr, size_t size, +CX_EXTERN CX_NONNULL +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); /** @@ -985,8 +983,8 @@ CX_EXPORT size_t cx_array_binary_search_inf(const void *arr, size_t size, * @see cx_array_binary_search_inf() * @see cx_array_binary_search_sup() */ -cx_attr_nonnull -CX_EXPORT size_t cx_array_binary_search(const void *arr, size_t size, +CX_EXTERN CX_NONNULL +size_t cx_array_binary_search(const void *arr, size_t size, size_t elem_size, const void *elem, cx_compare_func cmp_func); /** @@ -1014,8 +1012,8 @@ CX_EXPORT size_t cx_array_binary_search(const void *arr, size_t size, * @see cx_array_binary_search_inf() * @see cx_array_binary_search() */ -cx_attr_nonnull -CX_EXPORT size_t cx_array_binary_search_sup(const void *arr, size_t size, +CX_EXTERN CX_NONNULL +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); @@ -1045,8 +1043,8 @@ CX_EXPORT size_t cx_array_binary_search_sup(const void *arr, size_t 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, +CX_EXTERN CX_NONNULL +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); /** @@ -1069,8 +1067,8 @@ CX_EXPORT size_t cx_array_binary_search_inf_c(const void *arr, size_t size, * @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, +CX_EXTERN CX_NONNULL +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); /** @@ -1099,8 +1097,8 @@ CX_EXPORT size_t cx_array_binary_search_c(const void *arr, size_t 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, +CX_EXTERN CX_NONNULL +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); /** @@ -1111,8 +1109,8 @@ CX_EXPORT size_t cx_array_binary_search_sup_c(const void *arr, size_t size, * @param idx1 index of the first element * @param idx2 index of the second element */ -cx_attr_nonnull -CX_EXPORT void cx_array_swap(void *arr, size_t elem_size, size_t idx1, size_t idx2); +CX_EXTERN CX_NONNULL +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. @@ -1127,14 +1125,8 @@ CX_EXPORT void cx_array_swap(void *arr, size_t elem_size, size_t idx1, size_t id * @param initial_capacity the initial number of elements the array can store * @return the created list */ -cx_attr_nodiscard -cx_attr_malloc -cx_attr_dealloc(cxListFree, 1) -CX_EXPORT CxList *cxArrayListCreate(const CxAllocator *allocator, +CX_EXTERN CX_NODISCARD CX_MALLOC CX_DEALLOC(cxListFree, 1) +CxList *cxArrayListCreate(const CxAllocator *allocator, size_t elem_size, size_t initial_capacity); -#ifdef __cplusplus -} // extern "C" -#endif - #endif // UCX_ARRAY_LIST_H diff --git a/ucx/cx/buffer.h b/ucx/cx/buffer.h index f90de73..4c2bdbd 100644 --- a/ucx/cx/buffer.h +++ b/ucx/cx/buffer.h @@ -50,10 +50,6 @@ #include "allocator.h" #include "string.h" -#ifdef __cplusplus -extern "C" { -#endif - /** * No buffer features enabled (all flags cleared). */ @@ -177,8 +173,8 @@ typedef struct cx_buffer_s CxBuffer; * @param flags buffer features (see cx_buffer_s.flags) * @return zero on success, non-zero if a required allocation failed */ -cx_attr_nonnull_arg(1) -CX_EXPORT int cxBufferInit(CxBuffer *buffer, const CxAllocator *allocator, +CX_EXTERN CX_NONNULL_ARG(1) +int cxBufferInit(CxBuffer *buffer, const CxAllocator *allocator, void *space, size_t capacity, int flags); /** @@ -190,8 +186,8 @@ CX_EXPORT int cxBufferInit(CxBuffer *buffer, const CxAllocator *allocator, * @param buffer the buffer which contents shall be destroyed * @see cxBufferInit() */ -cx_attr_nonnull -CX_EXPORT void cxBufferDestroy(CxBuffer *buffer); +CX_EXTERN CX_NONNULL +void cxBufferDestroy(CxBuffer *buffer); /** * Deallocates the buffer. @@ -202,7 +198,8 @@ CX_EXPORT void cxBufferDestroy(CxBuffer *buffer); * @param buffer the buffer to deallocate * @see cxBufferCreate() */ -CX_EXPORT void cxBufferFree(CxBuffer *buffer); +CX_EXTERN +void cxBufferFree(CxBuffer *buffer); /** * Allocates and initializes a fresh buffer. @@ -228,8 +225,8 @@ CX_EXPORT void cxBufferFree(CxBuffer *buffer); * @param flags buffer features (see cx_buffer_s.flags) * @return a pointer to the buffer on success, @c NULL if a required allocation failed */ -cx_attr_malloc cx_attr_dealloc(cxBufferFree, 1) cx_attr_nodiscard -CX_EXPORT CxBuffer *cxBufferCreate(const CxAllocator *allocator, void *space, +CX_EXTERN CX_MALLOC CX_DEALLOC(cxBufferFree, 1) CX_NODISCARD +CxBuffer *cxBufferCreate(const CxAllocator *allocator, void *space, size_t capacity, int flags); /** @@ -268,8 +265,8 @@ CX_EXPORT CxBuffer *cxBufferCreate(const CxAllocator *allocator, void *space, * @see cxBufferShiftLeft() * @see cxBufferShiftRight() */ -cx_attr_nonnull -CX_EXPORT int cxBufferShift(CxBuffer *buffer, off_t shift); +CX_EXTERN CX_NONNULL +int cxBufferShift(CxBuffer *buffer, off_t shift); /** * Shifts the buffer to the right. @@ -281,8 +278,8 @@ CX_EXPORT int cxBufferShift(CxBuffer *buffer, off_t shift); * @retval non-zero if a required auto-extension or copy-on-write fails * @see cxBufferShift() */ -cx_attr_nonnull -CX_EXPORT int cxBufferShiftRight(CxBuffer *buffer, size_t shift); +CX_EXTERN CX_NONNULL +int cxBufferShiftRight(CxBuffer *buffer, size_t shift); /** * Shifts the buffer to the left. @@ -294,8 +291,8 @@ CX_EXPORT int cxBufferShiftRight(CxBuffer *buffer, size_t shift); * @retval non-zero if the buffer uses copy-on-write and the allocation fails * @see cxBufferShift() */ -cx_attr_nonnull -CX_EXPORT int cxBufferShiftLeft(CxBuffer *buffer, size_t shift); +CX_EXTERN CX_NONNULL +int cxBufferShiftLeft(CxBuffer *buffer, size_t shift); /** @@ -318,8 +315,8 @@ CX_EXPORT int cxBufferShiftLeft(CxBuffer *buffer, size_t shift); * @retval non-zero if the position is invalid * */ -cx_attr_nonnull -CX_EXPORT int cxBufferSeek(CxBuffer *buffer, off_t offset, int whence); +CX_EXTERN CX_NONNULL +int cxBufferSeek(CxBuffer *buffer, off_t offset, int whence); /** * Discards items from the end of the buffer. @@ -332,8 +329,8 @@ CX_EXPORT int cxBufferSeek(CxBuffer *buffer, off_t offset, int whence); * @param nitems the number of items to discard * @return the actual number of discarded items */ -cx_attr_nonnull -CX_EXPORT size_t cxBufferPop(CxBuffer *buffer, size_t size, size_t nitems); +CX_EXTERN CX_NONNULL +size_t cxBufferPop(CxBuffer *buffer, size_t size, size_t nitems); /** * Clears the buffer by resetting the position and deleting the data. @@ -347,8 +344,8 @@ CX_EXPORT size_t cxBufferPop(CxBuffer *buffer, size_t size, size_t nitems); * @param buffer the buffer to be cleared * @see cxBufferReset() */ -cx_attr_nonnull -CX_EXPORT void cxBufferClear(CxBuffer *buffer); +CX_EXTERN CX_NONNULL +void cxBufferClear(CxBuffer *buffer); /** * Resets the buffer by resetting the position and size to zero. @@ -359,8 +356,8 @@ CX_EXPORT void cxBufferClear(CxBuffer *buffer); * @param buffer the buffer to be cleared * @see cxBufferClear() */ -cx_attr_nonnull -CX_EXPORT void cxBufferReset(CxBuffer *buffer); +CX_EXTERN CX_NONNULL +void cxBufferReset(CxBuffer *buffer); /** * Tests, if the buffer position has exceeded the buffer size. @@ -370,8 +367,8 @@ CX_EXPORT void cxBufferReset(CxBuffer *buffer); * byte of the buffer's contents * @retval false otherwise */ -cx_attr_nonnull cx_attr_nodiscard -CX_EXPORT bool cxBufferEof(const CxBuffer *buffer); +CX_EXTERN CX_NONNULL CX_NODISCARD +bool cxBufferEof(const CxBuffer *buffer); /** * Ensures that the buffer has the required capacity. @@ -391,8 +388,8 @@ CX_EXPORT bool cxBufferEof(const CxBuffer *buffer); * @see cxBufferShrink() * @see cxBufferMinimumCapacity() */ -cx_attr_nonnull -CX_EXPORT int cxBufferReserve(CxBuffer *buffer, size_t capacity); +CX_EXTERN CX_NONNULL +int cxBufferReserve(CxBuffer *buffer, size_t capacity); /** * Limits the buffer's capacity. @@ -410,8 +407,8 @@ CX_EXPORT int cxBufferReserve(CxBuffer *buffer, size_t capacity); * @see cxBufferReserve() * @see cxBufferMinimumCapacity() */ -cx_attr_nonnull -CX_EXPORT int cxBufferMaximumCapacity(CxBuffer *buffer, size_t capacity); +CX_EXTERN CX_NONNULL +int cxBufferMaximumCapacity(CxBuffer *buffer, size_t capacity); /** * Ensures that the buffer has a minimum capacity. @@ -430,8 +427,8 @@ CX_EXPORT int cxBufferMaximumCapacity(CxBuffer *buffer, size_t capacity); * @see cxBufferReserve() * @see cxBufferShrink() */ -cx_attr_nonnull -CX_EXPORT int cxBufferMinimumCapacity(CxBuffer *buffer, size_t capacity); +CX_EXTERN CX_NONNULL +int cxBufferMinimumCapacity(CxBuffer *buffer, size_t capacity); /** * Shrinks the capacity of the buffer to fit its current size. @@ -450,8 +447,8 @@ CX_EXPORT int cxBufferMinimumCapacity(CxBuffer *buffer, size_t capacity); * @see cxBufferReserve() * @see cxBufferMinimumCapacity() */ -cx_attr_nonnull -CX_EXPORT void cxBufferShrink(CxBuffer *buffer, size_t reserve); +CX_EXTERN CX_NONNULL +void cxBufferShrink(CxBuffer *buffer, size_t reserve); /** * Writes data to a CxBuffer. @@ -474,8 +471,8 @@ CX_EXPORT void cxBufferShrink(CxBuffer *buffer, size_t reserve); * @see cxBufferAppend() * @see cxBufferRead() */ -cx_attr_nonnull -CX_EXPORT size_t cxBufferWrite(const void *ptr, size_t size, +CX_EXTERN CX_NONNULL +size_t cxBufferWrite(const void *ptr, size_t size, size_t nitems, CxBuffer *buffer); /** @@ -497,8 +494,8 @@ CX_EXPORT size_t cxBufferWrite(const void *ptr, size_t size, * @see cxBufferWrite() * @see cxBufferRead() */ -cx_attr_nonnull -CX_EXPORT size_t cxBufferAppend(const void *ptr, size_t size, +CX_EXTERN CX_NONNULL +size_t cxBufferAppend(const void *ptr, size_t size, size_t nitems, CxBuffer *buffer); /** @@ -516,8 +513,8 @@ CX_EXPORT size_t cxBufferAppend(const void *ptr, size_t size, * @see cxBufferWrite() * @see cxBufferAppend() */ -cx_attr_nonnull -CX_EXPORT size_t cxBufferRead(void *ptr, size_t size, +CX_EXTERN CX_NONNULL +size_t cxBufferRead(void *ptr, size_t size, size_t nitems, CxBuffer *buffer); /** @@ -540,8 +537,8 @@ CX_EXPORT size_t cxBufferRead(void *ptr, size_t size, * stream is reached, and automatic extension is not enabled or not possible * @see cxBufferTerminate() */ -cx_attr_nonnull -CX_EXPORT int cxBufferPut(CxBuffer *buffer, int c); +CX_EXTERN CX_NONNULL +int cxBufferPut(CxBuffer *buffer, int c); /** * Writes a terminating zero to a buffer at the current position. @@ -555,8 +552,8 @@ CX_EXPORT int cxBufferPut(CxBuffer *buffer, int c); * @return zero, if the terminator could be written, non-zero otherwise * @see cxBufferShrink() */ -cx_attr_nonnull -CX_EXPORT int cxBufferTerminate(CxBuffer *buffer); +CX_EXTERN CX_NONNULL +int cxBufferTerminate(CxBuffer *buffer); /** * Internal function - do not use. @@ -566,8 +563,8 @@ CX_EXPORT int cxBufferTerminate(CxBuffer *buffer); * @return the number of bytes written * @see cxBufferPutString() */ -cx_attr_nonnull -CX_EXPORT size_t cx_buffer_put_string(CxBuffer *buffer, cxstring str); +CX_EXTERN CX_NONNULL +size_t cx_buffer_put_string(CxBuffer *buffer, cxstring str); /** * Writes a string to a buffer with cxBufferWrite(). @@ -588,8 +585,8 @@ CX_EXPORT size_t cx_buffer_put_string(CxBuffer *buffer, cxstring str); * @return the number of bytes written * @see cxBufferPutString() */ -cx_attr_nonnull -CX_EXPORT size_t cx_buffer_append_string(CxBuffer *buffer, cxstring str); +CX_EXTERN CX_NONNULL +size_t cx_buffer_append_string(CxBuffer *buffer, cxstring str); /** * Appends a string to a buffer with cxBufferAppend(). @@ -610,8 +607,8 @@ CX_EXPORT size_t cx_buffer_append_string(CxBuffer *buffer, cxstring str); * @param buffer the buffer to read from * @return the character or @c EOF, if the end of the buffer is reached */ -cx_attr_nonnull -CX_EXPORT int cxBufferGet(CxBuffer *buffer); +CX_EXTERN CX_NONNULL +int cxBufferGet(CxBuffer *buffer); /** * Gets the data in a buffer as a @c cxstring. @@ -619,7 +616,8 @@ CX_EXPORT int cxBufferGet(CxBuffer *buffer); * @param buffer the buffer * @return the data in the buffer interpreted as a @c cxstring */ -CX_INLINE cxstring cx_bstr(CxBuffer *buffer) { +CX_NONNULL CX_INLINE +cxstring cx_bstr(CxBuffer *buffer) { return cx_strn(buffer->space, buffer->size); } @@ -629,12 +627,9 @@ CX_INLINE cxstring cx_bstr(CxBuffer *buffer) { * @param buffer the buffer * @return the data in the buffer interpreted as a @c cxmutstr */ -CX_INLINE cxmutstr cx_bstr_m(CxBuffer *buffer) { +CX_NONNULL CX_INLINE +cxmutstr cx_bstr_m(CxBuffer *buffer) { return cx_mutstrn(buffer->space, buffer->size); } -#ifdef __cplusplus -} -#endif - #endif // UCX_BUFFER_H diff --git a/ucx/cx/collection.h b/ucx/cx/collection.h index ae54cb1..607d6e6 100644 --- a/ucx/cx/collection.h +++ b/ucx/cx/collection.h @@ -40,10 +40,6 @@ #include "iterator.h" #include "compare.h" -#ifdef __cplusplus -extern "C" { -#endif - /** * Special constant used for creating collections that are storing pointers. */ @@ -316,8 +312,22 @@ struct cx_collection_s { if ((c)->collection.simple_destructor) cx_invoke_simple_destructor(c,e); \ if ((c)->collection.advanced_destructor) cx_invoke_advanced_destructor(c,e) -#ifdef __cplusplus -} // extern "C" -#endif +/** + * Invokes all available destructor functions for a specific element. + * + * Usually only used by collection implementations. There should be no need + * to invoke this macro manually. + * + * In contrast to cx_invoke_destructor(), this macro does not automatically + * dereference pointers to the elements when cxCollectionStoresPointers() + * returns true. + * + * @param c a pointer to a struct that contains #CX_COLLECTION_BASE + * @param e pointer to the element + */ +#define cx_invoke_destructor_raw(c, e) \ + if ((c)->collection.simple_destructor) (c)->collection.simple_destructor(e); \ + if ((c)->collection.advanced_destructor) (c)->collection.advanced_destructor((c)->collection.destructor_data, e) + #endif // UCX_COLLECTION_H diff --git a/ucx/cx/common.h b/ucx/cx/common.h index cba17d1..5938ce3 100644 --- a/ucx/cx/common.h +++ b/ucx/cx/common.h @@ -133,27 +133,27 @@ /** * Inform the compiler that falling through a switch case is intentional. */ -#define cx_attr_fallthrough __attribute__((__fallthrough__)) +#define CX_FALLTHROUGH __attribute__((__fallthrough__)) /** * All pointer arguments must be non-NULL. */ -#define cx_attr_nonnull __attribute__((__nonnull__)) +#define CX_NONNULL __attribute__((__nonnull__)) /** * The specified pointer arguments must be non-NULL. */ -#define cx_attr_nonnull_arg(...) __attribute__((__nonnull__(__VA_ARGS__))) +#define CX_NONNULL_ARG(...) __attribute__((__nonnull__(__VA_ARGS__))) /** * The returned value is guaranteed to be non-NULL. */ -#define cx_attr_returns_nonnull __attribute__((__returns_nonnull__)) +#define CX_RETURNS_NONNULL __attribute__((__returns_nonnull__)) /** * The attributed function always returns freshly allocated memory. */ -#define cx_attr_malloc __attribute__((__malloc__)) +#define CX_MALLOC __attribute__((__malloc__)) #if !defined(__clang__) && __GNUC__ >= 11 /** @@ -163,59 +163,59 @@ * @param freefunc the function that shall be used to free the memory * @param freefunc_arg the index of the pointer argument in @p freefunc */ -#define cx_attr_dealloc(freefunc, freefunc_arg) \ +#define CX_DEALLOC(freefunc, freefunc_arg) \ __attribute__((__malloc__(freefunc, freefunc_arg))) #else /** * Not supported in clang. */ -#define cx_attr_dealloc(...) +#define CX_DEALLOC(...) #endif // __clang__ /** * Shortcut to specify #cxFree() as deallocator. */ -#define cx_attr_dealloc_ucx cx_attr_dealloc(cxFree, 2) +#define CX_DEALLOC_UCX CX_DEALLOC(cxFree, 2) /** * Specifies the parameters from which the allocation size is calculated. */ -#define cx_attr_allocsize(...) __attribute__((__alloc_size__(__VA_ARGS__))) +#define CX_ALLOCSIZE(...) __attribute__((__alloc_size__(__VA_ARGS__))) #ifdef __clang__ /** * No support for @c null_terminated_string_arg in clang or GCC below 14. */ -#define cx_attr_cstr_arg(idx) +#define CX_CSTR_ARG(idx) /** * No support for the access attribute in clang. */ -#define cx_attr_access(mode, ...) +#define CX_ACCESS(mode, ...) #else #if __GNUC__ < 10 /** * No support for access attribute in GCC < 10. */ -#define cx_attr_access(mode, ...) +#define CX_ACCESS(mode, ...) #else /** * Helper macro to define access macros. */ -#define cx_attr_access(mode, ...) __attribute__((__access__(mode, __VA_ARGS__))) +#define CX_ACCESS(mode, ...) __attribute__((__access__(mode, __VA_ARGS__))) #endif // __GNUC__ < 10 #if __GNUC__ < 14 /** * No support for @c null_terminated_string_arg in clang or GCC below 14. */ -#define cx_attr_cstr_arg(idx) +#define CX_CSTR_ARG(idx) #else /** * The specified argument is expected to be a zero-terminated string. * * @param idx the index of the argument */ -#define cx_attr_cstr_arg(idx) \ +#define CX_CSTR_ARG(idx) \ __attribute__((__null_terminated_string_arg__(idx))) #endif // __GNUC__ < 14 #endif // __clang__ @@ -227,7 +227,7 @@ * Takes one or two arguments: the index of the pointer and (optionally) the * index of another argument specifying the maximum number of accessed bytes. */ -#define cx_attr_access_r(...) cx_attr_access(__read_only__, __VA_ARGS__) +#define CX_ACCESS_R(...) CX_ACCESS(__read_only__, __VA_ARGS__) /** * Specifies that the function will read and write through the given pointer. @@ -235,7 +235,7 @@ * Takes one or two arguments: the index of the pointer and (optionally) the * index of another argument specifying the maximum number of accessed bytes. */ -#define cx_attr_access_rw(...) cx_attr_access(__read_write__, __VA_ARGS__) +#define CX_ACCESS_RW(...) CX_ACCESS(__read_write__, __VA_ARGS__) /** * Specifies that the function will only write through the given pointer. @@ -243,17 +243,17 @@ * Takes one or two arguments: the index of the pointer and (optionally) the * index of another argument specifying the maximum number of accessed bytes. */ -#define cx_attr_access_w(...) cx_attr_access(__write_only__, __VA_ARGS__) +#define CX_ACCESS_W(...) CX_ACCESS(__write_only__, __VA_ARGS__) /** * Do not warn about unused variable. */ -#define cx_attr_unused __attribute__((__unused__)) +#define CX_UNUSED __attribute__((__unused__)) /** * Warn about discarded return value. */ -#define cx_attr_nodiscard __attribute__((__warn_unused_result__)) +#define CX_NODISCARD __attribute__((__warn_unused_result__)) // --------------------------------------------------------------------------- @@ -266,9 +266,11 @@ #ifdef _MSC_VER #define cx_thread_local __declspec(thread) #else // ! _MSC_VER -#if __STDC_VERSION__ < 202300L +#if !defined __STDC_VERSION__ || __STDC_VERSION__ < 202300L +/** Platform independent thread-local macro. */ #define cx_thread_local _Thread_local #else // C23 or newer +/** Platform independent thread-local macro. */ #define cx_thread_local thread_local #endif // C23 #endif // _MSC_VER @@ -287,6 +289,16 @@ #define CX_EXPORT #endif // CX_WINDLL / CX_WINDLL_EXPORT +#ifdef __cplusplus +#define CX_EXTERN extern "C" CX_EXPORT +#define CX_FPTR extern "C" typedef +#else +/** Declares a function with external linkage. */ +#define CX_EXTERN CX_EXPORT +/** Defines a function pointer. */ +#define CX_FPTR typedef +#endif + #ifdef __GNUC__ /** * Declares a function to be inlined. @@ -364,10 +376,8 @@ typedef size_t (*cx_read_func)(void*, size_t, size_t, void*); * @retval zero success * @retval non-zero the multiplication would overflow */ -#if __cplusplus -extern "C" -#endif -CX_EXPORT int cx_szmul_impl(size_t a, size_t b, size_t *result); +CX_EXTERN +int cx_szmul_impl(size_t a, size_t b, size_t *result); #endif // cx_szmul #endif // UCX_COMMON_H diff --git a/ucx/cx/compare.h b/ucx/cx/compare.h index 40265c5..931bd9c 100644 --- a/ucx/cx/compare.h +++ b/ucx/cx/compare.h @@ -38,10 +38,6 @@ #include "common.h" -#ifdef __cplusplus -extern "C" { -#endif - /** * A comparator function comparing two arbitrary values. * @@ -54,14 +50,14 @@ extern "C" { * can be used, but they are NOT compatible with this function * pointer. */ -typedef int (*cx_compare_func)(const void *left, const void *right); +CX_FPTR int (*cx_compare_func)(const void *left, const void *right); /** * A comparator function comparing two arbitrary values. * * Functions with this signature allow specifying a pointer to custom data. */ -typedef int (*cx_compare_func2)(const void *left, const void *right, void *data); +CX_FPTR int (*cx_compare_func2)(const void *left, const void *right, void *data); /** * Compares two integers of type int. @@ -75,8 +71,8 @@ typedef int (*cx_compare_func2)(const void *left, const void *right, void *data) * @retval 0 if both arguments are equal * @retval 1 if the left argument is greater than the right argument */ -cx_attr_nonnull cx_attr_nodiscard -CX_EXPORT int cx_cmp_int(const void *i1, const void *i2); +CX_EXTERN CX_NONNULL CX_NODISCARD +int cx_cmp_int(const void *i1, const void *i2); /** * Compares two integers of type int. @@ -87,8 +83,8 @@ CX_EXPORT int cx_cmp_int(const void *i1, const void *i2); * @retval 0 if both arguments are equal * @retval 1 if the left argument is greater than the right argument */ -cx_attr_nodiscard -CX_EXPORT int cx_vcmp_int(int i1, int i2); +CX_EXTERN CX_NODISCARD +int cx_vcmp_int(int i1, int i2); /** * Compares two integers of type long int. @@ -102,8 +98,8 @@ CX_EXPORT int cx_vcmp_int(int i1, int i2); * @retval 0 if both arguments are equal * @retval 1 if the left argument is greater than the right argument */ -cx_attr_nonnull cx_attr_nodiscard -CX_EXPORT int cx_cmp_longint(const void *i1, const void *i2); +CX_EXTERN CX_NONNULL CX_NODISCARD +int cx_cmp_longint(const void *i1, const void *i2); /** * Compares two integers of type long int. @@ -114,8 +110,8 @@ CX_EXPORT int cx_cmp_longint(const void *i1, const void *i2); * @retval 0 if both arguments are equal * @retval 1 if the left argument is greater than the right argument */ -cx_attr_nodiscard -CX_EXPORT int cx_vcmp_longint(long int i1, long int i2); +CX_EXTERN CX_NODISCARD +int cx_vcmp_longint(long int i1, long int i2); /** * Compares two integers of type long long. @@ -129,8 +125,8 @@ CX_EXPORT int cx_vcmp_longint(long int i1, long int i2); * @retval 0 if both arguments are equal * @retval 1 if the left argument is greater than the right argument */ -cx_attr_nonnull cx_attr_nodiscard -CX_EXPORT int cx_cmp_longlong(const void *i1, const void *i2); +CX_EXTERN CX_NONNULL CX_NODISCARD +int cx_cmp_longlong(const void *i1, const void *i2); /** * Compares two integers of type long long. @@ -141,8 +137,8 @@ CX_EXPORT int cx_cmp_longlong(const void *i1, const void *i2); * @retval 0 if both arguments are equal * @retval 1 if the left argument is greater than the right argument */ -cx_attr_nodiscard -CX_EXPORT int cx_vcmp_longlong(long long int i1, long long int i2); +CX_EXTERN CX_NODISCARD +int cx_vcmp_longlong(long long int i1, long long int i2); /** * Compares two integers of type int16_t. @@ -156,8 +152,8 @@ CX_EXPORT int cx_vcmp_longlong(long long int i1, long long int i2); * @retval 0 if both arguments are equal * @retval 1 if the left argument is greater than the right argument */ -cx_attr_nonnull cx_attr_nodiscard -CX_EXPORT int cx_cmp_int16(const void *i1, const void *i2); +CX_EXTERN CX_NONNULL CX_NODISCARD +int cx_cmp_int16(const void *i1, const void *i2); /** * Compares two integers of type int16_t. @@ -168,8 +164,8 @@ CX_EXPORT int cx_cmp_int16(const void *i1, const void *i2); * @retval 0 if both arguments are equal * @retval 1 if the left argument is greater than the right argument */ -cx_attr_nodiscard -CX_EXPORT int cx_vcmp_int16(int16_t i1, int16_t i2); +CX_EXTERN CX_NODISCARD +int cx_vcmp_int16(int16_t i1, int16_t i2); /** * Compares two integers of type int32_t. @@ -183,8 +179,8 @@ CX_EXPORT int cx_vcmp_int16(int16_t i1, int16_t i2); * @retval 0 if both arguments are equal * @retval 1 if the left argument is greater than the right argument */ -cx_attr_nonnull cx_attr_nodiscard -CX_EXPORT int cx_cmp_int32(const void *i1, const void *i2); +CX_EXTERN CX_NONNULL CX_NODISCARD +int cx_cmp_int32(const void *i1, const void *i2); /** * Compares two integers of type int32_t. @@ -195,8 +191,8 @@ CX_EXPORT int cx_cmp_int32(const void *i1, const void *i2); * @retval 0 if both arguments are equal * @retval 1 if the left argument is greater than the right argument */ -cx_attr_nodiscard -CX_EXPORT int cx_vcmp_int32(int32_t i1, int32_t i2); +CX_EXTERN CX_NODISCARD +int cx_vcmp_int32(int32_t i1, int32_t i2); /** * Compares two integers of type int64_t. @@ -210,8 +206,8 @@ CX_EXPORT int cx_vcmp_int32(int32_t i1, int32_t i2); * @retval 0 if both arguments are equal * @retval 1 if the left argument is greater than the right argument */ -cx_attr_nonnull cx_attr_nodiscard -CX_EXPORT int cx_cmp_int64(const void *i1, const void *i2); +CX_EXTERN CX_NONNULL CX_NODISCARD +int cx_cmp_int64(const void *i1, const void *i2); /** * Compares two integers of type int64_t. @@ -222,8 +218,8 @@ CX_EXPORT int cx_cmp_int64(const void *i1, const void *i2); * @retval 0 if both arguments are equal * @retval 1 if the left argument is greater than the right argument */ -cx_attr_nodiscard -CX_EXPORT int cx_vcmp_int64(int64_t i1, int64_t i2); +CX_EXTERN CX_NODISCARD +int cx_vcmp_int64(int64_t i1, int64_t i2); /** * Compares two integers of type unsigned int. @@ -237,8 +233,8 @@ CX_EXPORT int cx_vcmp_int64(int64_t i1, int64_t i2); * @retval 0 if both arguments are equal * @retval 1 if the left argument is greater than the right argument */ -cx_attr_nonnull cx_attr_nodiscard -CX_EXPORT int cx_cmp_uint(const void *i1, const void *i2); +CX_EXTERN CX_NONNULL CX_NODISCARD +int cx_cmp_uint(const void *i1, const void *i2); /** * Compares two integers of type unsigned int. @@ -249,8 +245,8 @@ CX_EXPORT int cx_cmp_uint(const void *i1, const void *i2); * @retval 0 if both arguments are equal * @retval 1 if the left argument is greater than the right argument */ -cx_attr_nodiscard -CX_EXPORT int cx_vcmp_uint(unsigned int i1, unsigned int i2); +CX_EXTERN CX_NODISCARD +int cx_vcmp_uint(unsigned int i1, unsigned int i2); /** * Compares two integers of type unsigned long int. @@ -264,8 +260,8 @@ CX_EXPORT int cx_vcmp_uint(unsigned int i1, unsigned int i2); * @retval 0 if both arguments are equal * @retval 1 if the left argument is greater than the right argument */ -cx_attr_nonnull cx_attr_nodiscard -CX_EXPORT int cx_cmp_ulongint(const void *i1, const void *i2); +CX_EXTERN CX_NONNULL CX_NODISCARD +int cx_cmp_ulongint(const void *i1, const void *i2); /** * Compares two integers of type unsigned long int. @@ -276,8 +272,8 @@ CX_EXPORT int cx_cmp_ulongint(const void *i1, const void *i2); * @retval 0 if both arguments are equal * @retval 1 if the left argument is greater than the right argument */ -cx_attr_nodiscard -CX_EXPORT int cx_vcmp_ulongint(unsigned long int i1, unsigned long int i2); +CX_EXTERN CX_NODISCARD +int cx_vcmp_ulongint(unsigned long int i1, unsigned long int i2); /** * Compares two integers of type unsigned long long. @@ -291,8 +287,8 @@ CX_EXPORT int cx_vcmp_ulongint(unsigned long int i1, unsigned long int i2); * @retval 0 if both arguments are equal * @retval 1 if the left argument is greater than the right argument */ -cx_attr_nonnull cx_attr_nodiscard -CX_EXPORT int cx_cmp_ulonglong(const void *i1, const void *i2); +CX_EXTERN CX_NONNULL CX_NODISCARD +int cx_cmp_ulonglong(const void *i1, const void *i2); /** * Compares two integers of type unsigned long long. @@ -303,8 +299,8 @@ CX_EXPORT int cx_cmp_ulonglong(const void *i1, const void *i2); * @retval 0 if both arguments are equal * @retval 1 if the left argument is greater than the right argument */ -cx_attr_nodiscard -CX_EXPORT int cx_vcmp_ulonglong(unsigned long long int i1, unsigned long long int i2); +CX_EXTERN CX_NODISCARD +int cx_vcmp_ulonglong(unsigned long long int i1, unsigned long long int i2); /** * Compares two integers of type uint16_t. @@ -318,8 +314,8 @@ CX_EXPORT int cx_vcmp_ulonglong(unsigned long long int i1, unsigned long long in * @retval 0 if both arguments are equal * @retval 1 if the left argument is greater than the right argument */ -cx_attr_nonnull cx_attr_nodiscard -CX_EXPORT int cx_cmp_uint16(const void *i1, const void *i2); +CX_EXTERN CX_NONNULL CX_NODISCARD +int cx_cmp_uint16(const void *i1, const void *i2); /** * Compares two integers of type uint16_t. @@ -330,8 +326,8 @@ CX_EXPORT int cx_cmp_uint16(const void *i1, const void *i2); * @retval 0 if both arguments are equal * @retval 1 if the left argument is greater than the right argument */ -cx_attr_nodiscard -CX_EXPORT int cx_vcmp_uint16(uint16_t i1, uint16_t i2); +CX_EXTERN CX_NODISCARD +int cx_vcmp_uint16(uint16_t i1, uint16_t i2); /** * Compares two integers of type uint32_t. @@ -345,8 +341,8 @@ CX_EXPORT int cx_vcmp_uint16(uint16_t i1, uint16_t i2); * @retval 0 if both arguments are equal * @retval 1 if the left argument is greater than the right argument */ -cx_attr_nonnull cx_attr_nodiscard -CX_EXPORT int cx_cmp_uint32(const void *i1, const void *i2); +CX_EXTERN CX_NONNULL CX_NODISCARD +int cx_cmp_uint32(const void *i1, const void *i2); /** * Compares two integers of type uint32_t. @@ -357,8 +353,8 @@ CX_EXPORT int cx_cmp_uint32(const void *i1, const void *i2); * @retval 0 if both arguments are equal * @retval 1 if the left argument is greater than the right argument */ -cx_attr_nodiscard -CX_EXPORT int cx_vcmp_uint32(uint32_t i1, uint32_t i2); +CX_EXTERN CX_NODISCARD +int cx_vcmp_uint32(uint32_t i1, uint32_t i2); /** * Compares two integers of type uint64_t. @@ -372,8 +368,8 @@ CX_EXPORT int cx_vcmp_uint32(uint32_t i1, uint32_t i2); * @retval 0 if both arguments are equal * @retval 1 if the left argument is greater than the right argument */ -cx_attr_nonnull cx_attr_nodiscard -CX_EXPORT int cx_cmp_uint64(const void *i1, const void *i2); +CX_EXTERN CX_NONNULL CX_NODISCARD +int cx_cmp_uint64(const void *i1, const void *i2); /** * Compares two integers of type uint64_t. @@ -384,8 +380,8 @@ CX_EXPORT int cx_cmp_uint64(const void *i1, const void *i2); * @retval 0 if both arguments are equal * @retval 1 if the left argument is greater than the right argument */ -cx_attr_nodiscard -CX_EXPORT int cx_vcmp_uint64(uint64_t i1, uint64_t i2); +CX_EXTERN CX_NODISCARD +int cx_vcmp_uint64(uint64_t i1, uint64_t i2); /** * Compares two integers of type size_t. @@ -399,8 +395,8 @@ CX_EXPORT int cx_vcmp_uint64(uint64_t i1, uint64_t i2); * @retval 0 if both arguments are equal * @retval 1 if the left argument is greater than the right argument */ -cx_attr_nonnull cx_attr_nodiscard -CX_EXPORT int cx_cmp_size(const void *i1, const void *i2); +CX_EXTERN CX_NONNULL CX_NODISCARD +int cx_cmp_size(const void *i1, const void *i2); /** * Compares two integers of type size_t. @@ -411,8 +407,8 @@ CX_EXPORT int cx_cmp_size(const void *i1, const void *i2); * @retval 0 if both arguments are equal * @retval 1 if the left argument is greater than the right argument */ -cx_attr_nodiscard -CX_EXPORT int cx_vcmp_size(size_t i1, size_t i2); +CX_EXTERN CX_NODISCARD +int cx_vcmp_size(size_t i1, size_t i2); /** * Compares two real numbers of type float with precision 1e-6f. @@ -426,8 +422,8 @@ CX_EXPORT int cx_vcmp_size(size_t i1, size_t i2); * @retval 0 if both arguments are equal * @retval 1 if the left argument is greater than the right argument */ -cx_attr_nonnull cx_attr_nodiscard -CX_EXPORT int cx_cmp_float(const void *f1, const void *f2); +CX_EXTERN CX_NONNULL CX_NODISCARD +int cx_cmp_float(const void *f1, const void *f2); /** * Compares two real numbers of type float with precision 1e-6f. @@ -438,8 +434,8 @@ CX_EXPORT int cx_cmp_float(const void *f1, const void *f2); * @retval 0 if both arguments are equal * @retval 1 if the left argument is greater than the right argument */ -cx_attr_nodiscard -CX_EXPORT int cx_vcmp_float(float f1, float f2); +CX_EXTERN CX_NODISCARD +int cx_vcmp_float(float f1, float f2); /** * Compares two real numbers of type double with precision 1e-14. @@ -453,8 +449,8 @@ CX_EXPORT int cx_vcmp_float(float f1, float f2); * @retval 0 if both arguments are equal * @retval 1 if the left argument is greater than the right argument */ -cx_attr_nonnull cx_attr_nodiscard -CX_EXPORT int cx_cmp_double(const void *d1, const void *d2); +CX_EXTERN CX_NONNULL CX_NODISCARD +int cx_cmp_double(const void *d1, const void *d2); /** * Compares two real numbers of type double with precision 1e-14. @@ -465,8 +461,8 @@ CX_EXPORT int cx_cmp_double(const void *d1, const void *d2); * @retval 0 if both arguments are equal * @retval 1 if the left argument is greater than the right argument */ -cx_attr_nodiscard -CX_EXPORT int cx_vcmp_double(double d1, double d2); +CX_EXTERN CX_NODISCARD +int cx_vcmp_double(double d1, double d2); /** * Compares the integer representation of two pointers. @@ -480,8 +476,8 @@ CX_EXPORT int cx_vcmp_double(double d1, double d2); * @retval 0 if both arguments are equal * @retval 1 if the left argument is greater than the right argument */ -cx_attr_nonnull cx_attr_nodiscard -CX_EXPORT int cx_cmp_intptr(const void *ptr1, const void *ptr2); +CX_EXTERN CX_NONNULL CX_NODISCARD +int cx_cmp_intptr(const void *ptr1, const void *ptr2); /** * Compares the integer representation of two pointers. @@ -492,8 +488,8 @@ CX_EXPORT int cx_cmp_intptr(const void *ptr1, const void *ptr2); * @retval 0 if both arguments are equal * @retval 1 if the left argument is greater than the right argument */ -cx_attr_nodiscard -CX_EXPORT int cx_vcmp_intptr(intptr_t ptr1, intptr_t ptr2); +CX_EXTERN CX_NODISCARD +int cx_vcmp_intptr(intptr_t ptr1, intptr_t ptr2); /** * Compares the unsigned integer representation of two pointers. @@ -507,8 +503,8 @@ CX_EXPORT int cx_vcmp_intptr(intptr_t ptr1, intptr_t ptr2); * @retval 0 if both arguments are equal * @retval 1 if the left argument is greater than the right argument */ -cx_attr_nonnull cx_attr_nodiscard -CX_EXPORT int cx_cmp_uintptr(const void *ptr1, const void *ptr2); +CX_EXTERN CX_NONNULL CX_NODISCARD +int cx_cmp_uintptr(const void *ptr1, const void *ptr2); /** * Compares the unsigned integer representation of two pointers. @@ -519,8 +515,8 @@ CX_EXPORT int cx_cmp_uintptr(const void *ptr1, const void *ptr2); * @retval 0 if both arguments are equal * @retval 1 if the left argument is greater than the right argument */ -cx_attr_nodiscard -CX_EXPORT int cx_vcmp_uintptr(uintptr_t ptr1, uintptr_t ptr2); +CX_EXTERN CX_NODISCARD +int cx_vcmp_uintptr(uintptr_t ptr1, uintptr_t ptr2); /** * Compares the pointers specified in the arguments without dereferencing. @@ -531,8 +527,8 @@ CX_EXPORT int cx_vcmp_uintptr(uintptr_t ptr1, uintptr_t ptr2); * @retval 0 if both arguments are equal * @retval 1 if the left argument is greater than the right argument */ -cx_attr_nonnull cx_attr_nodiscard -CX_EXPORT int cx_cmp_ptr(const void *ptr1, const void *ptr2); +CX_EXTERN CX_NONNULL CX_NODISCARD +int cx_cmp_ptr(const void *ptr1, const void *ptr2); /** Wraps a compare function for cx_cmp_wrap. */ typedef struct { @@ -549,11 +545,7 @@ typedef struct { * @return the result of the invoked compare function * @see cx_compare_func_wrapper */ -cx_attr_nonnull cx_attr_nodiscard -CX_EXPORT int cx_cmp_wrap(const void *ptr1, const void *ptr2, void* cmp_wrapper); - -#ifdef __cplusplus -} // extern "C" -#endif +CX_EXTERN CX_NONNULL CX_NODISCARD +int cx_cmp_wrap(const void *ptr1, const void *ptr2, void* cmp_wrapper); #endif //UCX_COMPARE_H diff --git a/ucx/cx/hash_key.h b/ucx/cx/hash_key.h index d198d45..e0fa205 100644 --- a/ucx/cx/hash_key.h +++ b/ucx/cx/hash_key.h @@ -40,10 +40,6 @@ #include "common.h" #include "string.h" -#ifdef __cplusplus -extern "C" { -#endif - /** Internal structure for a key within a hash map. */ struct cx_hash_key_s { /** @@ -78,8 +74,8 @@ typedef struct cx_hash_key_s CxHashKey; * @param key the key, the hash shall be computed for * @see cx_hash_key() */ -cx_attr_nonnull -CX_EXPORT void cx_hash_murmur(CxHashKey *key); +CX_EXTERN CX_NONNULL +void cx_hash_murmur(CxHashKey *key); /** * Mixes up a 32-bit integer to be used as a hash. @@ -89,7 +85,13 @@ CX_EXPORT void cx_hash_murmur(CxHashKey *key); * @param x the integer * @return the hash */ -CX_EXPORT uint32_t cx_hash_u32(uint32_t x); +CX_INLINE +uint32_t cx_hash_u32(uint32_t x) { + x = ((x >> 16) ^ x) * 0x45d9f3bu; + x = ((x >> 16) ^ x) * 0x45d9f3bu; + x = (x >> 16) ^ x; + return x; +} /** * Mixes up a 64-bit integer to be used as a hash. @@ -99,7 +101,27 @@ CX_EXPORT uint32_t cx_hash_u32(uint32_t x); * @param x the integer * @return the hash */ -CX_EXPORT uint64_t cx_hash_u64(uint64_t x); +CX_INLINE +uint64_t cx_hash_u64(uint64_t x){ + x = (x ^ (x >> 30)) * UINT64_C(0xbf58476d1ce4e5b9); + x = (x ^ (x >> 27)) * UINT64_C(0x94d049bb133111eb); + x = x ^ (x >> 31); + return x; +} + +/** + * Computes a hash key for an arbitrary object. + * + * The computation uses the in-memory representation that might not be + * the same on different platforms. Therefore, this hash should not be + * used for data exchange with different machines. + * + * @param obj a pointer to an arbitrary object + * @param len the length of the object in memory + * @return the hash key + */ +CX_EXTERN CX_NODISCARD CX_ACCESS_R(1, 2) +CxHashKey cx_hash_key(const void *obj, size_t len); /** * Computes a hash key from a 32-bit integer. @@ -107,8 +129,14 @@ CX_EXPORT uint64_t cx_hash_u64(uint64_t x); * @param x the integer * @return the hash key */ -cx_attr_nodiscard -CX_EXPORT CxHashKey cx_hash_key_u32(uint32_t x); +CX_NODISCARD CX_INLINE +CxHashKey cx_hash_key_u32(uint32_t x) { + CxHashKey key; + key.data = NULL; + key.len = 0; + key.hash = cx_hash_u32(x); + return key; +} /** * Computes a hash key from a 64-bit integer. @@ -116,8 +144,14 @@ CX_EXPORT CxHashKey cx_hash_key_u32(uint32_t x); * @param x the integer * @return the hash key */ -cx_attr_nodiscard -CX_EXPORT CxHashKey cx_hash_key_u64(uint64_t x); +CX_NODISCARD CX_INLINE +CxHashKey cx_hash_key_u64(uint64_t x) { + CxHashKey key; + key.data = NULL; + key.len = 0; + key.hash = cx_hash_u64(x); + return key; +} /** * Computes a hash key from a string. @@ -127,8 +161,10 @@ CX_EXPORT CxHashKey cx_hash_key_u64(uint64_t x); * @param str the string * @return the hash key */ -cx_attr_nodiscard cx_attr_cstr_arg(1) -CX_EXPORT CxHashKey cx_hash_key_str(const char *str); +CX_NODISCARD CX_CSTR_ARG(1) CX_INLINE +CxHashKey cx_hash_key_str(const char *str) { + return cx_hash_key((const void*)str, str == NULL ? 0 : strlen(str)); +} /** * Computes a hash key from a string. @@ -141,8 +177,10 @@ CX_EXPORT CxHashKey cx_hash_key_str(const char *str); * @param str the string * @return the hash key */ -cx_attr_nodiscard cx_attr_cstr_arg(1) -CX_EXPORT CxHashKey cx_hash_key_ustr(const unsigned char *str); +CX_NODISCARD CX_CSTR_ARG(1) CX_INLINE +CxHashKey cx_hash_key_ustr(const unsigned char *str) { + return cx_hash_key((const void*)str, str == NULL ? 0 : strlen((const char*)str)); +} /** * Computes a hash key from a byte array. @@ -151,23 +189,10 @@ CX_EXPORT CxHashKey cx_hash_key_ustr(const unsigned char *str); * @param len the length * @return the hash key */ -cx_attr_nodiscard cx_attr_access_r(1, 2) -CX_EXPORT CxHashKey cx_hash_key_bytes(const unsigned char *bytes, size_t len); - -/** - * Computes a hash key for an arbitrary object. - * - * The computation uses the in-memory representation that might not be - * the same on different platforms. Therefore, this hash should not be - * used for data exchange with different machines. - * - * @param obj a pointer to an arbitrary object - * @param len the length of the object in memory - * @return the hash key - */ -cx_attr_nodiscard -cx_attr_access_r(1, 2) -CX_EXPORT CxHashKey cx_hash_key(const void *obj, size_t len); +CX_NODISCARD CX_ACCESS_R(1, 2) CX_INLINE +CxHashKey cx_hash_key_bytes(const unsigned char *bytes, size_t len) { + return cx_hash_key((const void*)bytes, len); +} /** * Computes a hash key from a UCX string. @@ -175,8 +200,10 @@ CX_EXPORT CxHashKey cx_hash_key(const void *obj, size_t len); * @param str the string * @return the hash key */ -cx_attr_nodiscard -CX_EXPORT CxHashKey cx_hash_key_cxstr(cxstring str); +CX_NODISCARD CX_INLINE +CxHashKey cx_hash_key_cxstr(cxstring str) { + return cx_hash_key((void*)str.ptr, str.length); +} /** * Computes a hash key from a UCX string. @@ -184,26 +211,40 @@ CX_EXPORT CxHashKey cx_hash_key_cxstr(cxstring str); * @param str the string * @return the hash key */ -cx_attr_nodiscard -CX_EXPORT CxHashKey cx_hash_key_mutstr(cxmutstr str); +CX_NODISCARD CX_INLINE +CxHashKey cx_hash_key_mutstr(cxmutstr str) { + return cx_hash_key((void*)str.ptr, str.length); +} /** * The identity function for the CX_HASH_KEY() macro. * You should never need to use this manually. * * @param key the key - * @return a copy of the key + * @return a copy of the key (not the data) */ -cx_attr_nodiscard -CX_INLINE CxHashKey cx_hash_key_identity(CxHashKey key) { +CX_NODISCARD CX_INLINE +CxHashKey cx_hash_key_identity(CxHashKey key) { return key; } +/** + * The dereference function for the CX_HASH_KEY() macro. + * You should never need to use this manually. + * + * @param key a pointer to a key + * @return a copy of the key (not the data) + */ +CX_NODISCARD CX_INLINE +CxHashKey cx_hash_key_deref(const CxHashKey *key) { + return *key; +} + #ifndef __cplusplus /** * Creates a hash key from any of the supported types with implicit length. * - * Does nothing when passing a CxHashkey. + * Does nothing when passing a CxHashKey and dereferences CxHashKey pointers. * * Supported types are UCX strings, zero-terminated C strings, * and 32-bit or 64-bit unsigned integers. @@ -212,6 +253,8 @@ CX_INLINE CxHashKey cx_hash_key_identity(CxHashKey key) { * @returns the @c CxHashKey */ #define CX_HASH_KEY(key) _Generic((key), \ + CxHashKey*: cx_hash_key_deref, \ + const CxHashKey*: cx_hash_key_deref, \ CxHashKey: cx_hash_key_identity, \ cxstring: cx_hash_key_cxstr, \ cxmutstr: cx_hash_key_mutstr, \ @@ -233,8 +276,8 @@ CX_INLINE CxHashKey cx_hash_key_identity(CxHashKey key) { * @param right (@c CxHashKey*) the second key * @return zero when the keys equal, non-zero when they differ */ -cx_attr_nodiscard cx_attr_nonnull -CX_EXPORT int cx_hash_key_cmp(const void *left, const void *right); +CX_EXTERN CX_NODISCARD CX_NONNULL +int cx_hash_key_cmp(const void *left, const void *right); /** * Interprets the key data as a string and returns it. @@ -242,11 +285,10 @@ CX_EXPORT int cx_hash_key_cmp(const void *left, const void *right); * @param key the key * @return the key data as a string */ -CX_EXPORT cxstring cx_hash_key_as_string(const CxHashKey *key); +CX_EXTERN +cxstring cx_hash_key_as_string(const CxHashKey *key); #ifdef __cplusplus -} // extern "C" - // ---------------------------------------------------------- // Overloads of CX_HASH_KEY (the C++ version of a _Generic) // ---------------------------------------------------------- @@ -255,6 +297,10 @@ CX_CPPDECL CxHashKey CX_HASH_KEY(CxHashKey key) { return key; } +CX_CPPDECL CxHashKey CX_HASH_KEY(const CxHashKey *key) { + return *key; +} + CX_CPPDECL CxHashKey CX_HASH_KEY(cxstring str) { return cx_hash_key_cxstr(str); } diff --git a/ucx/cx/hash_map.h b/ucx/cx/hash_map.h index 438e175..153d49c 100644 --- a/ucx/cx/hash_map.h +++ b/ucx/cx/hash_map.h @@ -38,10 +38,6 @@ #include "map.h" -#ifdef __cplusplus -extern "C" { -#endif - /** Internal structure for an element of a hash map. */ struct cx_hash_map_element_s; @@ -83,8 +79,8 @@ struct cx_hash_map_s { * @param buckets the initial number of buckets in this hash map * @return a pointer to the new hash map */ -cx_attr_nodiscard cx_attr_malloc cx_attr_dealloc(cxMapFree, 1) -CX_EXPORT CxMap *cxHashMapCreate(const CxAllocator *allocator, +CX_EXTERN CX_NODISCARD CX_MALLOC CX_DEALLOC(cxMapFree, 1) +CxMap *cxHashMapCreate(const CxAllocator *allocator, size_t itemsize, size_t buckets); /** @@ -106,12 +102,7 @@ CX_EXPORT CxMap *cxHashMapCreate(const CxAllocator *allocator, * @retval zero success * @retval non-zero if a memory allocation error occurred */ -cx_attr_nonnull -CX_EXPORT int cxMapRehash(CxMap *map); - - -#ifdef __cplusplus -} // extern "C" -#endif +CX_EXTERN CX_NONNULL +int cxMapRehash(CxMap *map); #endif // UCX_HASH_MAP_H diff --git a/ucx/cx/iterator.h b/ucx/cx/iterator.h index 56aa731..74d7e58 100644 --- a/ucx/cx/iterator.h +++ b/ucx/cx/iterator.h @@ -38,10 +38,6 @@ #include "common.h" -#ifdef __cplusplus -extern "C" { -#endif - /** * Common data for all iterators. */ @@ -182,16 +178,6 @@ typedef struct cx_iterator_s CxIterator; */ #define cxIteratorFlagRemoval(iter) ((iter).base.remove = (iter).base.allow_remove) -/** - * Obtains a reference to an arbitrary iterator. - * - * This is useful for APIs that expect some iterator as an argument. - * - * @param iter the iterator - * @return (@c struct @c cx_iterator_base_s*) a pointer to the iterator - */ -#define cxIteratorRef(iter) &((iter).base) - /** * Loops over an iterator. * @@ -220,8 +206,8 @@ for (type elem; cxIteratorValid(iter) && (elem = (type)cxIteratorCurrent(iter)) * @return an iterator for the specified array * @see cxIteratorPtr() */ -cx_attr_nodiscard -CX_EXPORT CxIterator cxIterator(const void *array, +CX_EXTERN CX_NODISCARD +CxIterator cxIterator(const void *array, size_t elem_size, size_t elem_count); /** @@ -237,11 +223,7 @@ CX_EXPORT CxIterator cxIterator(const void *array, * @return an iterator for the specified array * @see cxIterator() */ -cx_attr_nodiscard -CX_EXPORT CxIterator cxIteratorPtr(const void *array, size_t elem_count); - -#ifdef __cplusplus -} // extern "C" -#endif +CX_EXTERN CX_NODISCARD +CxIterator cxIteratorPtr(const void *array, size_t elem_count); #endif // UCX_ITERATOR_H diff --git a/ucx/cx/json.h b/ucx/cx/json.h index 0dd7db1..7268164 100644 --- a/ucx/cx/json.h +++ b/ucx/cx/json.h @@ -43,11 +43,6 @@ #include "array_list.h" #include "map.h" -#ifdef __cplusplus -extern "C" { -#endif - - /** * The type of the parsed token. */ @@ -114,6 +109,10 @@ enum cx_json_value_type { * Reserved. */ CX_JSON_NOTHING, // this allows us to always return non-NULL values + /** + * No meaningful data. + */ + CX_JSON_UNINITIALIZED, /** * A JSON object. */ @@ -288,13 +287,6 @@ struct cx_json_s { */ CxBuffer buffer; - /** - * Used internally. - * - * Remembers the prefix of the last uncompleted token. - */ - CxJsonToken uncompleted; - /** * A pointer to an intermediate state of the currently parsed value. * @@ -309,6 +301,16 @@ struct cx_json_s { */ cxmutstr uncompleted_member_name; + /** + * Internal buffer for uncompleted tokens. + */ + cxmutstr uncompleted_content; + + /** + * The expected type of the currently parsed, uncompleted token. + */ + CxJsonTokenType uncompleted_tokentype; + /** * State stack. */ @@ -424,8 +426,8 @@ typedef struct cx_json_writer_s CxJsonWriter; * * @return new JSON writer settings */ -cx_attr_nodiscard -CX_EXPORT CxJsonWriter cxJsonWriterCompact(void); +CX_EXTERN CX_NODISCARD +CxJsonWriter cxJsonWriterCompact(void); /** * Creates a default writer configuration for pretty output. @@ -433,8 +435,8 @@ CX_EXPORT CxJsonWriter cxJsonWriterCompact(void); * @param use_spaces false if you want tabs, true if you want four spaces instead * @return new JSON writer settings */ -cx_attr_nodiscard -CX_EXPORT CxJsonWriter cxJsonWriterPretty(bool use_spaces); +CX_EXTERN CX_NODISCARD +CxJsonWriter cxJsonWriterPretty(bool use_spaces); /** * Writes a JSON value to a buffer or stream. @@ -454,8 +456,8 @@ CX_EXPORT CxJsonWriter cxJsonWriterPretty(bool use_spaces); * @retval zero success * @retval non-zero when no or not all data could be written */ -cx_attr_nonnull_arg(1, 2, 3) -CX_EXPORT int cxJsonWrite(void* target, const CxJsonValue* value, +CX_EXTERN CX_NONNULL_ARG(1, 2, 3) +int cxJsonWrite(void* target, const CxJsonValue* value, cx_write_func wfunc, const CxJsonWriter* settings); @@ -469,8 +471,8 @@ CX_EXPORT int cxJsonWrite(void* target, const CxJsonValue* value, * @see cxJsonWriterCompact() * @see cxJsonToPrettyString() */ -cx_attr_nonnull_arg(2) -CX_EXPORT cxmutstr cxJsonToString(const CxAllocator *allocator, CxJsonValue *value); +CX_EXTERN CX_NONNULL_ARG(2) CX_NODISCARD +cxmutstr cxJsonToString(const CxAllocator *allocator, CxJsonValue *value); /** * Produces a pretty string representation of the specified JSON value. @@ -482,8 +484,8 @@ CX_EXPORT cxmutstr cxJsonToString(const CxAllocator *allocator, CxJsonValue *val * @see cxJsonWriterPretty() * @see cxJsonToString() */ -cx_attr_nonnull_arg(2) -CX_EXPORT cxmutstr cxJsonToPrettyString(const CxAllocator *allocator, CxJsonValue *value); +CX_EXTERN CX_NONNULL_ARG(2) CX_NODISCARD +cxmutstr cxJsonToPrettyString(const CxAllocator *allocator, CxJsonValue *value); /** * Initializes the JSON interface. @@ -492,8 +494,8 @@ CX_EXPORT cxmutstr cxJsonToPrettyString(const CxAllocator *allocator, CxJsonValu * @param allocator the allocator that shall be used for the produced values * @see cxJsonDestroy() */ -cx_attr_nonnull_arg(1) -CX_EXPORT void cxJsonInit(CxJson *json, const CxAllocator *allocator); +CX_EXTERN CX_NONNULL_ARG(1) +void cxJsonInit(CxJson *json, const CxAllocator *allocator); /** * Destroys the JSON interface. @@ -501,8 +503,8 @@ CX_EXPORT void cxJsonInit(CxJson *json, const CxAllocator *allocator); * @param json the JSON interface * @see cxJsonInit() */ -cx_attr_nonnull -CX_EXPORT void cxJsonDestroy(CxJson *json); +CX_EXTERN CX_NONNULL +void cxJsonDestroy(CxJson *json); /** * Destroys and re-initializes the JSON interface. @@ -512,8 +514,8 @@ CX_EXPORT void cxJsonDestroy(CxJson *json); * * @param json the JSON interface */ -cx_attr_nonnull -CX_EXPORT void cxJsonReset(CxJson *json); +CX_EXTERN CX_NONNULL +void cxJsonReset(CxJson *json); /** * Fills the input buffer. @@ -533,8 +535,8 @@ CX_EXPORT void cxJsonReset(CxJson *json); * @retval non-zero internal allocation error * @see cxJsonFill() */ -cx_attr_nonnull_arg(1) cx_attr_access_r(2, 3) -CX_EXPORT int cxJsonFilln(CxJson *json, const char *buf, size_t len); +CX_EXTERN CX_NONNULL_ARG(1) CX_ACCESS_R(2, 3) +int cxJsonFilln(CxJson *json, const char *buf, size_t len); /** @@ -545,8 +547,8 @@ CX_EXPORT int cxJsonFilln(CxJson *json, const char *buf, size_t len); * @retval zero success * @retval non-zero internal allocation error */ -cx_attr_nonnull -CX_INLINE int cx_json_fill(CxJson *json, cxstring str) { +CX_NONNULL CX_INLINE +int cx_json_fill(CxJson *json, cxstring str) { return cxJsonFilln(json, str.ptr, str.length); } @@ -578,8 +580,8 @@ CX_INLINE int cx_json_fill(CxJson *json, cxstring str) { * @param value a pointer where the JSON value shall be stored to * @return status code */ -cx_attr_nonnull_arg(3) -CX_EXPORT CxJsonStatus cx_json_from_string(const CxAllocator *allocator, +CX_EXTERN CX_NONNULL_ARG(3) CX_ACCESS_W(3) +CxJsonStatus cx_json_from_string(const CxAllocator *allocator, cxstring str, CxJsonValue **value); /** @@ -599,6 +601,20 @@ CX_EXPORT CxJsonStatus cx_json_from_string(const CxAllocator *allocator, #define cxJsonFromString(allocator, str, value) \ cx_json_from_string(allocator, cx_strcast(str), value) +/** + * Recursively deallocates the memory of a JSON value. + * + * @remark The type of each deallocated value will be changed + * to #CX_JSON_NOTHING, and values of such a type will be skipped + * by the deallocation. That means this function protects + * you from double-frees when you are accidentally freeing + * a nested value and then the parent value (or vice versa). + * + * @param value the value + */ +CX_EXTERN +void cxJsonValueFree(CxJsonValue *value); + /** * Creates a new (empty) JSON object. * @@ -607,8 +623,8 @@ CX_EXPORT CxJsonStatus cx_json_from_string(const CxAllocator *allocator, * @see cxJsonObjPutObj() * @see cxJsonArrAddValues() */ -cx_attr_nodiscard -CX_EXPORT CxJsonValue* cxJsonCreateObj(const CxAllocator* allocator); +CX_EXTERN CX_NODISCARD CX_MALLOC CX_DEALLOC(cxJsonValueFree, 1) +CxJsonValue* cxJsonCreateObj(const CxAllocator* allocator); /** * Creates a new (empty) JSON array. @@ -621,8 +637,8 @@ CX_EXPORT CxJsonValue* cxJsonCreateObj(const CxAllocator* allocator); * @see cxJsonObjPutArr() * @see cxJsonArrAddValues() */ -cx_attr_nodiscard -CX_EXPORT CxJsonValue* cxJsonCreateArr(const CxAllocator* allocator, size_t capacity); +CX_EXTERN CX_NODISCARD CX_MALLOC CX_DEALLOC(cxJsonValueFree, 1) +CxJsonValue* cxJsonCreateArr(const CxAllocator* allocator, size_t capacity); /** * Creates a new JSON number value. @@ -633,8 +649,8 @@ CX_EXPORT CxJsonValue* cxJsonCreateArr(const CxAllocator* allocator, size_t capa * @see cxJsonObjPutNumber() * @see cxJsonArrAddNumbers() */ -cx_attr_nodiscard -CX_EXPORT CxJsonValue* cxJsonCreateNumber(const CxAllocator* allocator, double num); +CX_EXTERN CX_NODISCARD CX_MALLOC CX_DEALLOC(cxJsonValueFree, 1) +CxJsonValue* cxJsonCreateNumber(const CxAllocator* allocator, double num); /** * Creates a new JSON number value based on an integer. @@ -645,8 +661,8 @@ CX_EXPORT CxJsonValue* cxJsonCreateNumber(const CxAllocator* allocator, double n * @see cxJsonObjPutInteger() * @see cxJsonArrAddIntegers() */ -cx_attr_nodiscard -CX_EXPORT CxJsonValue* cxJsonCreateInteger(const CxAllocator* allocator, int64_t num); +CX_EXTERN CX_NODISCARD CX_MALLOC CX_DEALLOC(cxJsonValueFree, 1) +CxJsonValue* cxJsonCreateInteger(const CxAllocator* allocator, int64_t num); /** * Creates a new JSON string. @@ -659,8 +675,8 @@ CX_EXPORT CxJsonValue* cxJsonCreateInteger(const CxAllocator* allocator, int64_t * @see cxJsonObjPutString() * @see cxJsonArrAddCxStrings() */ -cx_attr_nodiscard -CX_EXPORT CxJsonValue* cx_json_create_string(const CxAllocator* allocator, cxstring str); +CX_EXTERN CX_NODISCARD CX_MALLOC CX_DEALLOC(cxJsonValueFree, 1) +CxJsonValue* cx_json_create_string(const CxAllocator* allocator, cxstring str); /** * Creates a new JSON string. @@ -682,8 +698,8 @@ CX_EXPORT CxJsonValue* cx_json_create_string(const CxAllocator* allocator, cxstr * @see cxJsonObjPutLiteral() * @see cxJsonArrAddLiterals() */ -cx_attr_nodiscard -CX_EXPORT CxJsonValue* cxJsonCreateLiteral(const CxAllocator* allocator, CxJsonLiteral lit); +CX_EXTERN CX_NODISCARD CX_MALLOC CX_DEALLOC(cxJsonValueFree, 1) +CxJsonValue* cxJsonCreateLiteral(const CxAllocator* allocator, CxJsonLiteral lit); /** * Adds number values to a JSON array. @@ -694,8 +710,8 @@ CX_EXPORT CxJsonValue* cxJsonCreateLiteral(const CxAllocator* allocator, CxJsonL * @retval zero success * @retval non-zero allocation failure */ -cx_attr_nonnull cx_attr_access_r(2, 3) -CX_EXPORT int cxJsonArrAddNumbers(CxJsonValue* arr, const double* num, size_t count); +CX_EXTERN CX_NONNULL CX_ACCESS_R(2, 3) +int cxJsonArrAddNumbers(CxJsonValue* arr, const double* num, size_t count); /** * Adds number values, of which all are integers, to a JSON array. @@ -706,8 +722,8 @@ CX_EXPORT int cxJsonArrAddNumbers(CxJsonValue* arr, const double* num, size_t co * @retval zero success * @retval non-zero allocation failure */ -cx_attr_nonnull cx_attr_access_r(2, 3) -CX_EXPORT int cxJsonArrAddIntegers(CxJsonValue* arr, const int64_t* num, size_t count); +CX_EXTERN CX_NONNULL CX_ACCESS_R(2, 3) +int cxJsonArrAddIntegers(CxJsonValue* arr, const int64_t* num, size_t count); /** * Adds strings to a JSON array. @@ -721,8 +737,8 @@ CX_EXPORT int cxJsonArrAddIntegers(CxJsonValue* arr, const int64_t* num, size_t * @retval non-zero allocation failure * @see cxJsonArrAddCxStrings() */ -cx_attr_nonnull cx_attr_access_r(2, 3) -CX_EXPORT int cxJsonArrAddStrings(CxJsonValue* arr, const char* const* str, size_t count); +CX_EXTERN CX_NONNULL CX_ACCESS_R(2, 3) +int cxJsonArrAddStrings(CxJsonValue* arr, const char* const* str, size_t count); /** * Adds strings to a JSON array. @@ -736,8 +752,8 @@ CX_EXPORT int cxJsonArrAddStrings(CxJsonValue* arr, const char* const* str, size * @retval non-zero allocation failure * @see cxJsonArrAddStrings() */ -cx_attr_nonnull cx_attr_access_r(2, 3) -CX_EXPORT int cxJsonArrAddCxStrings(CxJsonValue* arr, const cxstring* str, size_t count); +CX_EXTERN CX_NONNULL CX_ACCESS_R(2, 3) +int cxJsonArrAddCxStrings(CxJsonValue* arr, const cxstring* str, size_t count); /** * Adds literals to a JSON array. @@ -748,8 +764,8 @@ CX_EXPORT int cxJsonArrAddCxStrings(CxJsonValue* arr, const cxstring* str, size_ * @retval zero success * @retval non-zero allocation failure */ -cx_attr_nonnull cx_attr_access_r(2, 3) -CX_EXPORT int cxJsonArrAddLiterals(CxJsonValue* arr, const CxJsonLiteral* lit, size_t count); +CX_EXTERN CX_NONNULL CX_ACCESS_R(2, 3) +int cxJsonArrAddLiterals(CxJsonValue* arr, const CxJsonLiteral* lit, size_t count); /** * Add arbitrary values to a JSON array. @@ -763,8 +779,8 @@ CX_EXPORT int cxJsonArrAddLiterals(CxJsonValue* arr, const CxJsonLiteral* lit, s * @retval zero success * @retval non-zero allocation failure */ -cx_attr_nonnull cx_attr_access_r(2, 3) -CX_EXPORT int cxJsonArrAddValues(CxJsonValue* arr, CxJsonValue* const* val, size_t count); +CX_EXTERN CX_NONNULL CX_ACCESS_R(2, 3) +int cxJsonArrAddValues(CxJsonValue* arr, CxJsonValue* const* val, size_t count); /** * Adds or replaces a value within a JSON object. @@ -777,8 +793,8 @@ CX_EXPORT int cxJsonArrAddValues(CxJsonValue* arr, CxJsonValue* const* val, size * @retval zero success * @retval non-zero allocation failure */ -cx_attr_nonnull -CX_EXPORT int cx_json_obj_put(CxJsonValue* obj, cxstring name, CxJsonValue* child); +CX_EXTERN CX_NONNULL +int cx_json_obj_put(CxJsonValue* obj, cxstring name, CxJsonValue* child); /** * Adds or replaces a value within a JSON object. @@ -807,8 +823,8 @@ CX_EXPORT int cx_json_obj_put(CxJsonValue* obj, cxstring name, CxJsonValue* chil * @see cxJsonObjPut() * @see cxJsonCreateObj() */ -cx_attr_nonnull -CX_EXPORT CxJsonValue* cx_json_obj_put_obj(CxJsonValue* obj, cxstring name); +CX_EXTERN CX_NONNULL CX_MALLOC CX_DEALLOC(cxJsonValueFree, 1) +CxJsonValue* cx_json_obj_put_obj(CxJsonValue* obj, cxstring name); /** * Creates a new JSON object and adds it to an existing object. @@ -833,8 +849,8 @@ CX_EXPORT CxJsonValue* cx_json_obj_put_obj(CxJsonValue* obj, cxstring name); * @see cxJsonObjPut() * @see cxJsonCreateArr() */ -cx_attr_nonnull -CX_EXPORT CxJsonValue* cx_json_obj_put_arr(CxJsonValue* obj, cxstring name, size_t capacity); +CX_EXTERN CX_NONNULL CX_MALLOC CX_DEALLOC(cxJsonValueFree, 1) +CxJsonValue* cx_json_obj_put_arr(CxJsonValue* obj, cxstring name, size_t capacity); /** * Creates a new JSON array and adds it to an object. @@ -860,8 +876,8 @@ CX_EXPORT CxJsonValue* cx_json_obj_put_arr(CxJsonValue* obj, cxstring name, size * @see cxJsonObjPut() * @see cxJsonCreateNumber() */ -cx_attr_nonnull -CX_EXPORT CxJsonValue* cx_json_obj_put_number(CxJsonValue* obj, cxstring name, double num); +CX_EXTERN CX_NONNULL CX_MALLOC CX_DEALLOC(cxJsonValueFree, 1) +CxJsonValue* cx_json_obj_put_number(CxJsonValue* obj, cxstring name, double num); /** * Creates a new JSON number and adds it to an object. @@ -887,8 +903,8 @@ CX_EXPORT CxJsonValue* cx_json_obj_put_number(CxJsonValue* obj, cxstring name, d * @see cxJsonObjPut() * @see cxJsonCreateInteger() */ -cx_attr_nonnull -CX_EXPORT CxJsonValue* cx_json_obj_put_integer(CxJsonValue* obj, cxstring name, int64_t num); +CX_EXTERN CX_NONNULL CX_MALLOC CX_DEALLOC(cxJsonValueFree, 1) +CxJsonValue* cx_json_obj_put_integer(CxJsonValue* obj, cxstring name, int64_t num); /** * Creates a new JSON number, based on an integer, and adds it to an object. @@ -914,8 +930,8 @@ CX_EXPORT CxJsonValue* cx_json_obj_put_integer(CxJsonValue* obj, cxstring name, * @see cxJsonObjPut() * @see cxJsonCreateString() */ -cx_attr_nonnull -CX_EXPORT CxJsonValue* cx_json_obj_put_string(CxJsonValue* obj, cxstring name, cxstring str); +CX_EXTERN CX_NONNULL CX_MALLOC CX_DEALLOC(cxJsonValueFree, 1) +CxJsonValue* cx_json_obj_put_string(CxJsonValue* obj, cxstring name, cxstring str); /** * Creates a new JSON string and adds it to an object. @@ -943,8 +959,8 @@ CX_EXPORT CxJsonValue* cx_json_obj_put_string(CxJsonValue* obj, cxstring name, c * @see cxJsonObjPut() * @see cxJsonCreateLiteral() */ -cx_attr_nonnull -CX_EXPORT CxJsonValue* cx_json_obj_put_literal(CxJsonValue* obj, cxstring name, CxJsonLiteral lit); +CX_EXTERN CX_NONNULL CX_MALLOC CX_DEALLOC(cxJsonValueFree, 1) +CxJsonValue* cx_json_obj_put_literal(CxJsonValue* obj, cxstring name, CxJsonLiteral lit); /** * Creates a new JSON literal and adds it to an object. @@ -958,19 +974,6 @@ CX_EXPORT CxJsonValue* cx_json_obj_put_literal(CxJsonValue* obj, cxstring name, */ #define cxJsonObjPutLiteral(obj, name, lit) cx_json_obj_put_literal(obj, cx_strcast(name), lit) -/** - * Recursively deallocates the memory of a JSON value. - * - * @remark The type of each deallocated value will be changed - * to #CX_JSON_NOTHING, and values of such a type will be skipped - * by the deallocation. That means this function protects - * you from double-frees when you are accidentally freeing - * a nested value and then the parent value (or vice versa). - * - * @param value the value - */ -CX_EXPORT void cxJsonValueFree(CxJsonValue *value); - /** * Tries to obtain the next JSON value. * @@ -993,8 +996,8 @@ CX_EXPORT void cxJsonValueFree(CxJsonValue *value); * @retval CX_JSON_FORMAT_ERROR_NUMBER the JSON text contains an illegally formatted number * @retval CX_JSON_FORMAT_ERROR_UNEXPECTED_TOKEN JSON syntax error */ -cx_attr_nonnull cx_attr_access_w(2) -CX_EXPORT CxJsonStatus cxJsonNext(CxJson *json, CxJsonValue **value); +CX_EXTERN CX_NONNULL CX_ACCESS_W(2) +CxJsonStatus cxJsonNext(CxJson *json, CxJsonValue **value); /** * Checks if the specified value is a JSON object. @@ -1003,8 +1006,8 @@ CX_EXPORT CxJsonStatus cxJsonNext(CxJson *json, CxJsonValue **value); * @retval true the value is a JSON object * @retval false otherwise */ -cx_attr_nonnull -CX_INLINE bool cxJsonIsObject(const CxJsonValue *value) { +CX_NONNULL CX_NODISCARD CX_INLINE +bool cxJsonIsObject(const CxJsonValue *value) { return value->type == CX_JSON_OBJECT; } @@ -1015,8 +1018,8 @@ CX_INLINE bool cxJsonIsObject(const CxJsonValue *value) { * @retval true the value is a JSON array * @retval false otherwise */ -cx_attr_nonnull -CX_INLINE bool cxJsonIsArray(const CxJsonValue *value) { +CX_NONNULL CX_NODISCARD CX_INLINE +bool cxJsonIsArray(const CxJsonValue *value) { return value->type == CX_JSON_ARRAY; } @@ -1027,8 +1030,8 @@ CX_INLINE bool cxJsonIsArray(const CxJsonValue *value) { * @retval true the value is a string * @retval false otherwise */ -cx_attr_nonnull -CX_INLINE bool cxJsonIsString(const CxJsonValue *value) { +CX_NONNULL CX_NODISCARD CX_INLINE +bool cxJsonIsString(const CxJsonValue *value) { return value->type == CX_JSON_STRING; } @@ -1043,8 +1046,8 @@ CX_INLINE bool cxJsonIsString(const CxJsonValue *value) { * @retval false otherwise * @see cxJsonIsInteger() */ -cx_attr_nonnull -CX_INLINE bool cxJsonIsNumber(const CxJsonValue *value) { +CX_NONNULL CX_NODISCARD CX_INLINE +bool cxJsonIsNumber(const CxJsonValue *value) { return value->type == CX_JSON_NUMBER || value->type == CX_JSON_INTEGER; } @@ -1056,8 +1059,8 @@ CX_INLINE bool cxJsonIsNumber(const CxJsonValue *value) { * @retval false otherwise * @see cxJsonIsNumber() */ -cx_attr_nonnull -CX_INLINE bool cxJsonIsInteger(const CxJsonValue *value) { +CX_NONNULL CX_NODISCARD CX_INLINE +bool cxJsonIsInteger(const CxJsonValue *value) { return value->type == CX_JSON_INTEGER; } @@ -1073,8 +1076,8 @@ CX_INLINE bool cxJsonIsInteger(const CxJsonValue *value) { * @see cxJsonIsFalse() * @see cxJsonIsNull() */ -cx_attr_nonnull -CX_INLINE bool cxJsonIsLiteral(const CxJsonValue *value) { +CX_NONNULL CX_NODISCARD CX_INLINE +bool cxJsonIsLiteral(const CxJsonValue *value) { return value->type == CX_JSON_LITERAL; } @@ -1087,8 +1090,8 @@ CX_INLINE bool cxJsonIsLiteral(const CxJsonValue *value) { * @see cxJsonIsTrue() * @see cxJsonIsFalse() */ -cx_attr_nonnull -CX_INLINE bool cxJsonIsBool(const CxJsonValue *value) { +CX_NONNULL CX_NODISCARD CX_INLINE +bool cxJsonIsBool(const CxJsonValue *value) { return cxJsonIsLiteral(value) && value->literal != CX_JSON_NULL; } @@ -1104,8 +1107,8 @@ CX_INLINE bool cxJsonIsBool(const CxJsonValue *value) { * @see cxJsonIsBool() * @see cxJsonIsFalse() */ -cx_attr_nonnull -CX_INLINE bool cxJsonIsTrue(const CxJsonValue *value) { +CX_NONNULL CX_NODISCARD CX_INLINE +bool cxJsonIsTrue(const CxJsonValue *value) { return cxJsonIsLiteral(value) && value->literal == CX_JSON_TRUE; } @@ -1121,8 +1124,8 @@ CX_INLINE bool cxJsonIsTrue(const CxJsonValue *value) { * @see cxJsonIsBool() * @see cxJsonIsTrue() */ -cx_attr_nonnull -CX_INLINE bool cxJsonIsFalse(const CxJsonValue *value) { +CX_NONNULL CX_NODISCARD CX_INLINE +bool cxJsonIsFalse(const CxJsonValue *value) { return cxJsonIsLiteral(value) && value->literal == CX_JSON_FALSE; } @@ -1134,8 +1137,8 @@ CX_INLINE bool cxJsonIsFalse(const CxJsonValue *value) { * @retval false otherwise * @see cxJsonIsLiteral() */ -cx_attr_nonnull -CX_INLINE bool cxJsonIsNull(const CxJsonValue *value) { +CX_NONNULL CX_NODISCARD CX_INLINE +bool cxJsonIsNull(const CxJsonValue *value) { return cxJsonIsLiteral(value) && value->literal == CX_JSON_NULL; } @@ -1148,8 +1151,8 @@ CX_INLINE bool cxJsonIsNull(const CxJsonValue *value) { * @return the value represented as C string * @see cxJsonIsString() */ -cx_attr_nonnull cx_attr_returns_nonnull -CX_EXPORT char *cxJsonAsString(const CxJsonValue *value); +CX_EXTERN CX_NONNULL CX_RETURNS_NONNULL CX_NODISCARD +char *cxJsonAsString(const CxJsonValue *value); /** * Obtains a UCX string from the given JSON value. @@ -1160,8 +1163,8 @@ CX_EXPORT char *cxJsonAsString(const CxJsonValue *value); * @return the value represented as UCX string * @see cxJsonIsString() */ -cx_attr_nonnull -CX_EXPORT cxstring cxJsonAsCxString(const CxJsonValue *value); +CX_EXTERN CX_NONNULL CX_NODISCARD +cxstring cxJsonAsCxString(const CxJsonValue *value); /** * Obtains a mutable UCX string from the given JSON value. @@ -1172,8 +1175,8 @@ CX_EXPORT cxstring cxJsonAsCxString(const CxJsonValue *value); * @return the value represented as mutable UCX string * @see cxJsonIsString() */ -cx_attr_nonnull -CX_EXPORT cxmutstr cxJsonAsCxMutStr(const CxJsonValue *value); +CX_EXTERN CX_NONNULL CX_NODISCARD +cxmutstr cxJsonAsCxMutStr(const CxJsonValue *value); /** * Obtains a double-precision floating-point value from the given JSON value. @@ -1184,8 +1187,8 @@ CX_EXPORT cxmutstr cxJsonAsCxMutStr(const CxJsonValue *value); * @return the value represented as double * @see cxJsonIsNumber() */ -cx_attr_nonnull -CX_EXPORT double cxJsonAsDouble(const CxJsonValue *value); +CX_EXTERN CX_NONNULL CX_NODISCARD +double cxJsonAsDouble(const CxJsonValue *value); /** * Obtains a 64-bit signed integer from the given JSON value. @@ -1199,8 +1202,8 @@ CX_EXPORT double cxJsonAsDouble(const CxJsonValue *value); * @see cxJsonIsNumber() * @see cxJsonIsInteger() */ -cx_attr_nonnull -CX_EXPORT int64_t cxJsonAsInteger(const CxJsonValue *value); +CX_EXTERN CX_NONNULL CX_NODISCARD +int64_t cxJsonAsInteger(const CxJsonValue *value); /** * Obtains a Boolean value from the given JSON value. @@ -1212,8 +1215,8 @@ CX_EXPORT int64_t cxJsonAsInteger(const CxJsonValue *value); * @return the value represented as double * @see cxJsonIsLiteral() */ -cx_attr_nonnull -CX_INLINE bool cxJsonAsBool(const CxJsonValue *value) { +CX_NONNULL CX_NODISCARD CX_INLINE +bool cxJsonAsBool(const CxJsonValue *value) { return value->literal == CX_JSON_TRUE; } @@ -1226,8 +1229,8 @@ CX_INLINE bool cxJsonAsBool(const CxJsonValue *value) { * @return the size of the array * @see cxJsonIsArray() */ -cx_attr_nonnull -CX_INLINE size_t cxJsonArrSize(const CxJsonValue *value) { +CX_NONNULL CX_NODISCARD CX_INLINE +size_t cxJsonArrSize(const CxJsonValue *value) { return value->array.size; } @@ -1245,8 +1248,8 @@ CX_INLINE size_t cxJsonArrSize(const CxJsonValue *value) { * @return the value at the specified index * @see cxJsonIsArray() */ -cx_attr_nonnull cx_attr_returns_nonnull -CX_EXPORT CxJsonValue *cxJsonArrGet(const CxJsonValue *value, size_t index); +CX_EXTERN CX_NONNULL CX_RETURNS_NONNULL CX_NODISCARD +CxJsonValue *cxJsonArrGet(const CxJsonValue *value, size_t index); /** * Removes an element from a JSON array. @@ -1261,8 +1264,8 @@ CX_EXPORT CxJsonValue *cxJsonArrGet(const CxJsonValue *value, size_t index); * @return the removed value from the specified index or @c NULL when the index was out of bounds * @see cxJsonIsArray() */ -cx_attr_nonnull -CX_EXPORT CxJsonValue *cxJsonArrRemove(CxJsonValue *value, size_t index); +CX_EXTERN CX_NONNULL +CxJsonValue *cxJsonArrRemove(CxJsonValue *value, size_t index); /** * Returns an iterator over the JSON array elements. @@ -1275,8 +1278,8 @@ CX_EXPORT CxJsonValue *cxJsonArrRemove(CxJsonValue *value, size_t index); * @return an iterator over the array elements * @see cxJsonIsArray() */ -cx_attr_nonnull cx_attr_nodiscard -CX_EXPORT CxIterator cxJsonArrIter(const CxJsonValue *value); +CX_EXTERN CX_NONNULL CX_NODISCARD +CxIterator cxJsonArrIter(const CxJsonValue *value); /** * Returns the size of a JSON object. @@ -1287,8 +1290,8 @@ CX_EXPORT CxIterator cxJsonArrIter(const CxJsonValue *value); * @return the size of the object, i.e., the number of key/value pairs * @see cxJsonIsObject() */ -cx_attr_nonnull -CX_INLINE size_t cxJsonObjSize(const CxJsonValue *value) { +CX_NONNULL CX_INLINE +size_t cxJsonObjSize(const CxJsonValue *value) { return cxCollectionSize(value->object); } @@ -1304,8 +1307,8 @@ CX_INLINE size_t cxJsonObjSize(const CxJsonValue *value) { * @return an iterator over the object members * @see cxJsonIsObject() */ -cx_attr_nonnull cx_attr_nodiscard -CX_EXPORT CxMapIterator cxJsonObjIter(const CxJsonValue *value); +CX_EXTERN CX_NONNULL CX_NODISCARD +CxMapIterator cxJsonObjIter(const CxJsonValue *value); /** * Internal function, do not use. @@ -1313,8 +1316,8 @@ CX_EXPORT CxMapIterator cxJsonObjIter(const CxJsonValue *value); * @param name the key to look up * @return the value corresponding to the key */ -cx_attr_nonnull cx_attr_returns_nonnull -CX_EXPORT CxJsonValue *cx_json_obj_get(const CxJsonValue *value, cxstring name); +CX_EXTERN CX_NONNULL CX_RETURNS_NONNULL CX_NODISCARD +CxJsonValue *cx_json_obj_get(const CxJsonValue *value, cxstring name); /** * Returns a value corresponding to a key in a JSON object. @@ -1338,8 +1341,8 @@ CX_EXPORT CxJsonValue *cx_json_obj_get(const CxJsonValue *value, cxstring name); * @param name the key to look up * @return the value corresponding to the key or @c NULL when the key is not part of the object */ -cx_attr_nonnull -CX_EXPORT CxJsonValue *cx_json_obj_remove(CxJsonValue *value, cxstring name); +CX_EXTERN CX_NONNULL +CxJsonValue *cx_json_obj_remove(CxJsonValue *value, cxstring name); /** * Removes and returns a value corresponding to a key in a JSON object. @@ -1366,7 +1369,8 @@ CX_EXPORT CxJsonValue *cx_json_obj_remove(CxJsonValue *value, cxstring name); * @retval zero the values are equal (except for ordering of object members) * @retval non-zero the values differ */ -CX_EXPORT int cxJsonCompare(const CxJsonValue *json, const CxJsonValue *other); +CX_EXTERN CX_NODISCARD +int cxJsonCompare(const CxJsonValue *json, const CxJsonValue *other); /** @@ -1382,11 +1386,10 @@ CX_EXPORT int cxJsonCompare(const CxJsonValue *json, const CxJsonValue *other); * @return the new value or @c NULL if any allocation was unsuccessful * @see cxJsonCloneFunc() */ -cx_attr_nodiscard -CX_EXPORT CxJsonValue* cxJsonClone(const CxJsonValue* value, +CX_EXTERN CX_NODISCARD +CxJsonValue* cxJsonClone(const CxJsonValue* value, const CxAllocator* allocator); - /** * A @c cx_clone_func compatible version of cxJsonClone(). * @@ -1399,8 +1402,8 @@ CX_EXPORT CxJsonValue* cxJsonClone(const CxJsonValue* value, * @return the new value or @c NULL if any allocation was unsuccessful * @see cxJsonClone() */ -cx_attr_nodiscard -CX_EXPORT CxJsonValue* cx_json_clone_func( +CX_EXTERN CX_NODISCARD +CxJsonValue* cx_json_clone_func( CxJsonValue* target, const CxJsonValue* source, const CxAllocator* allocator, void *data); @@ -1416,9 +1419,5 @@ CX_EXPORT CxJsonValue* cx_json_clone_func( */ #define cxJsonCloneFunc ((cx_clone_func) cx_json_clone_func) -#ifdef __cplusplus -} -#endif - #endif /* UCX_JSON_H */ diff --git a/ucx/cx/kv_list.h b/ucx/cx/kv_list.h index 81eac84..5e8962c 100644 --- a/ucx/cx/kv_list.h +++ b/ucx/cx/kv_list.h @@ -40,10 +40,6 @@ #include "list.h" #include "map.h" -#ifdef __cplusplus -extern "C" { -#endif - /** * Allocates a linked list with a lookup-map for storing elements with @p elem_size bytes each. * @@ -63,8 +59,8 @@ extern "C" { * @see cxKvListAsMap() * @see cxKvListAsList() */ -cx_attr_nodiscard cx_attr_malloc cx_attr_dealloc(cxListFree, 1) -CX_EXPORT CxList *cxKvListCreate(const CxAllocator *allocator, +CX_EXTERN CX_NODISCARD CX_MALLOC CX_DEALLOC(cxListFree, 1) +CxList *cxKvListCreate(const CxAllocator *allocator, size_t elem_size); /** @@ -85,8 +81,8 @@ CX_EXPORT CxList *cxKvListCreate(const CxAllocator *allocator, * @see cxKvListAsMap() * @see cxKvListAsList() */ -cx_attr_nodiscard cx_attr_malloc cx_attr_dealloc(cxMapFree, 1) -CX_EXPORT CxMap *cxKvListCreateAsMap(const CxAllocator *allocator, +CX_EXTERN CX_NODISCARD CX_MALLOC CX_DEALLOC(cxMapFree, 1) +CxMap *cxKvListCreateAsMap(const CxAllocator *allocator, size_t elem_size); /** @@ -95,8 +91,8 @@ CX_EXPORT CxMap *cxKvListCreateAsMap(const CxAllocator *allocator, * @param map a map pointer that was returned by a call to cxKvListAsMap() * @return the original list pointer */ -cx_attr_nodiscard cx_attr_nonnull cx_attr_returns_nonnull -CX_EXPORT CxList *cxKvListAsList(CxMap *map); +CX_EXTERN CX_NODISCARD CX_NONNULL CX_RETURNS_NONNULL +CxList *cxKvListAsList(CxMap *map); /** * Converts a map pointer belonging to a key-value-List back to the original list pointer. @@ -104,8 +100,8 @@ CX_EXPORT CxList *cxKvListAsList(CxMap *map); * @param list a list created by cxKvListCreate() * @return a map pointer that lets you use the list as if it was a map */ -cx_attr_nodiscard cx_attr_nonnull cx_attr_returns_nonnull -CX_EXPORT CxMap *cxKvListAsMap(CxList *list); +CX_EXTERN CX_NODISCARD CX_NONNULL CX_RETURNS_NONNULL +CxMap *cxKvListAsMap(CxList *list); /** * Sets or updates the key of a list item. @@ -120,8 +116,8 @@ CX_EXPORT CxMap *cxKvListAsMap(CxList *list); * @retval non-zero memory allocation failure or the index is out of bounds * @see cxKvListSetKey() */ -cx_attr_nonnull -CX_EXPORT int cx_kv_list_set_key(CxList *list, size_t index, CxHashKey key); +CX_EXTERN CX_NONNULL +int cx_kv_list_set_key(CxList *list, size_t index, CxHashKey key); /** * Inserts an item into the list at the specified index and associates it with the specified key. @@ -134,8 +130,8 @@ CX_EXPORT int cx_kv_list_set_key(CxList *list, size_t index, CxHashKey key); * @retval non-zero memory allocation failure or the index is out of bounds * @see cxKvListInsert() */ -cx_attr_nonnull -CX_EXPORT int cx_kv_list_insert(CxList *list, size_t index, CxHashKey key, void *value); +CX_EXTERN CX_NONNULL +int cx_kv_list_insert(CxList *list, size_t index, CxHashKey key, void *value); /** * Sets or updates the key of a list item. @@ -165,7 +161,6 @@ CX_EXPORT int cx_kv_list_insert(CxList *list, size_t index, CxHashKey key, void */ #define cxKvListInsert(list, index, key, value) cx_kv_list_insert(list, index, CX_HASH_KEY(key), value) - /** * Removes the key of a list item. * @@ -178,8 +173,8 @@ CX_EXPORT int cx_kv_list_insert(CxList *list, size_t index, CxHashKey key, void * @retval zero success * @retval non-zero the index is out of bounds */ -cx_attr_nonnull -CX_EXPORT int cxKvListRemoveKey(CxList *list, size_t index); +CX_EXTERN CX_NONNULL +int cxKvListRemoveKey(CxList *list, size_t index); /** * Returns the key of a list item. @@ -188,8 +183,8 @@ CX_EXPORT int cxKvListRemoveKey(CxList *list, size_t index); * @param index the index of the element in the list * @return a pointer to the key or @c NULL when the index is out of bounds or the item does not have a key */ -cx_attr_nonnull -CX_EXPORT const CxHashKey *cxKvListGetKey(CxList *list, size_t index); +CX_EXTERN CX_NONNULL CX_NODISCARD +const CxHashKey *cxKvListGetKey(CxList *list, size_t index); /** * Adds an item into the list and associates it with the specified key. @@ -202,8 +197,4 @@ CX_EXPORT const CxHashKey *cxKvListGetKey(CxList *list, size_t index); */ #define cxKvListAdd(list, key, value) cxKvListInsert(list, (list)->collection.size, key, value) -#ifdef __cplusplus -} // extern "C" -#endif - #endif // UCX_KV_LIST_H diff --git a/ucx/cx/linked_list.h b/ucx/cx/linked_list.h index fe6d435..b828725 100644 --- a/ucx/cx/linked_list.h +++ b/ucx/cx/linked_list.h @@ -39,10 +39,6 @@ #include "common.h" #include "list.h" -#ifdef __cplusplus -extern "C" { -#endif - /** * Metadata for a linked list. */ @@ -94,8 +90,8 @@ typedef struct cx_linked_list_s { * @param elem_size the size of each element in bytes * @return the created list */ -cx_attr_nodiscard cx_attr_malloc cx_attr_dealloc(cxListFree, 1) -CX_EXPORT CxList *cxLinkedListCreate(const CxAllocator *allocator, +CX_EXTERN CX_NODISCARD CX_MALLOC CX_DEALLOC(cxListFree, 1) +CxList *cxLinkedListCreate(const CxAllocator *allocator, size_t elem_size); /** @@ -112,8 +108,8 @@ CX_EXPORT CxList *cxLinkedListCreate(const CxAllocator *allocator, * @param list the list (must be a linked list) * @param len the length of the extra data */ -cx_attr_nonnull -CX_EXPORT void cx_linked_list_extra_data(cx_linked_list *list, size_t len); +CX_EXTERN CX_NONNULL +void cx_linked_list_extra_data(cx_linked_list *list, size_t len); /** * Finds the node at a certain index. @@ -132,8 +128,8 @@ CX_EXPORT void cx_linked_list_extra_data(cx_linked_list *list, size_t len); * @param index the search index * @return the node found at the specified index */ -cx_attr_nonnull cx_attr_nodiscard -CX_EXPORT void *cx_linked_list_at(const void *start,size_t start_index, +CX_EXTERN CX_NONNULL CX_NODISCARD +void *cx_linked_list_at(const void *start,size_t start_index, ptrdiff_t loc_advance, size_t index); /** @@ -148,8 +144,8 @@ CX_EXPORT void *cx_linked_list_at(const void *start,size_t start_index, * @param cmp_func a compare function to compare @p elem against the node data * @return a pointer to the found node or @c NULL if no matching node was found */ -cx_attr_nonnull_arg(1, 4, 6) -CX_EXPORT void *cx_linked_list_find(const void *start, ptrdiff_t loc_advance, +CX_EXTERN CX_NONNULL_ARG(1, 4, 6) +void *cx_linked_list_find(const void *start, ptrdiff_t loc_advance, ptrdiff_t loc_data, const void *elem, size_t *found_index, cx_compare_func cmp_func); @@ -166,8 +162,8 @@ CX_EXPORT void *cx_linked_list_find(const void *start, ptrdiff_t loc_advance, * @param context additional context for the compare function * @return a pointer to the found node or @c NULL if no matching node was found */ -cx_attr_nonnull_arg(1, 4, 6) -CX_EXPORT void *cx_linked_list_find_c(const void *start, ptrdiff_t loc_advance, +CX_EXTERN CX_NONNULL_ARG(1, 4, 6) +void *cx_linked_list_find_c(const void *start, ptrdiff_t loc_advance, ptrdiff_t loc_data, const void *elem, size_t *found_index, cx_compare_func2 cmp_func, void *context); @@ -182,8 +178,8 @@ CX_EXPORT void *cx_linked_list_find_c(const void *start, ptrdiff_t loc_advance, * @param loc_prev the location of the @c prev pointer * @return a pointer to the first node */ -cx_attr_nonnull cx_attr_returns_nonnull -CX_EXPORT void *cx_linked_list_first(const void *node, ptrdiff_t loc_prev); +CX_EXTERN CX_NONNULL CX_RETURNS_NONNULL +void *cx_linked_list_first(const void *node, ptrdiff_t loc_prev); /** * Finds the last node in a linked list. @@ -196,8 +192,8 @@ CX_EXPORT void *cx_linked_list_first(const void *node, ptrdiff_t loc_prev); * @param loc_next the location of the @c next pointer * @return a pointer to the last node */ -cx_attr_nonnull cx_attr_returns_nonnull -CX_EXPORT void *cx_linked_list_last(const void *node, ptrdiff_t loc_next); +CX_EXTERN CX_NONNULL CX_RETURNS_NONNULL +void *cx_linked_list_last(const void *node, ptrdiff_t loc_next); /** * Finds the predecessor of a node in case it is not linked. @@ -209,8 +205,8 @@ CX_EXPORT void *cx_linked_list_last(const void *node, ptrdiff_t loc_next); * @param node the successor of the node to find * @return the node or @c NULL if @p node has no predecessor */ -cx_attr_nonnull -CX_EXPORT void *cx_linked_list_prev(const void *begin, ptrdiff_t loc_next, const void *node); +CX_EXTERN CX_NONNULL +void *cx_linked_list_prev(const void *begin, ptrdiff_t loc_next, const void *node); /** * Adds a new node to a linked list. @@ -224,8 +220,8 @@ CX_EXPORT void *cx_linked_list_prev(const void *begin, ptrdiff_t loc_next, const * @param loc_next the location of a @c next pointer within your node struct (required) * @param new_node a pointer to the node that shall be appended */ -cx_attr_nonnull_arg(5) -CX_EXPORT void cx_linked_list_add(void **begin, void **end, ptrdiff_t loc_prev, ptrdiff_t loc_next, void *new_node); +CX_EXTERN CX_NONNULL_ARG(5) +void cx_linked_list_add(void **begin, void **end, ptrdiff_t loc_prev, ptrdiff_t loc_next, void *new_node); /** * Prepends a new node to a linked list. @@ -239,8 +235,8 @@ CX_EXPORT void cx_linked_list_add(void **begin, void **end, ptrdiff_t loc_prev, * @param loc_next the location of a @c next pointer within your node struct (required) * @param new_node a pointer to the node that shall be prepended */ -cx_attr_nonnull_arg(5) -CX_EXPORT void cx_linked_list_prepend(void **begin, void **end, ptrdiff_t loc_prev, ptrdiff_t loc_next, void *new_node); +CX_EXTERN CX_NONNULL_ARG(5) +void cx_linked_list_prepend(void **begin, void **end, ptrdiff_t loc_prev, ptrdiff_t loc_next, void *new_node); /** * Links two nodes. @@ -250,8 +246,8 @@ CX_EXPORT void cx_linked_list_prepend(void **begin, void **end, ptrdiff_t loc_pr * @param loc_prev the location of a @c prev pointer within your node struct (negative if your struct does not have one) * @param loc_next the location of a @c next pointer within your node struct (required) */ -cx_attr_nonnull -CX_EXPORT void cx_linked_list_link(void *left, void *right, ptrdiff_t loc_prev, ptrdiff_t loc_next); +CX_EXTERN CX_NONNULL +void cx_linked_list_link(void *left, void *right, ptrdiff_t loc_prev, ptrdiff_t loc_next); /** * Unlinks two nodes. @@ -263,8 +259,8 @@ CX_EXPORT void cx_linked_list_link(void *left, void *right, ptrdiff_t loc_prev, * @param loc_prev the location of a @c prev pointer within your node struct (negative if your struct does not have one) * @param loc_next the location of a @c next pointer within your node struct (required) */ -cx_attr_nonnull -CX_EXPORT void cx_linked_list_unlink(void *left, void *right, ptrdiff_t loc_prev, ptrdiff_t loc_next); +CX_EXTERN CX_NONNULL +void cx_linked_list_unlink(void *left, void *right, ptrdiff_t loc_prev, ptrdiff_t loc_next); /** * Inserts a new node after a given node of a linked list. @@ -280,8 +276,8 @@ CX_EXPORT void cx_linked_list_unlink(void *left, void *right, ptrdiff_t loc_prev * @param node the node after which to insert (@c NULL if you want to prepend the node to the list) * @param new_node a pointer to the node that shall be inserted */ -cx_attr_nonnull_arg(6) -CX_EXPORT void cx_linked_list_insert(void **begin, void **end, +CX_EXTERN CX_NONNULL_ARG(6) +void cx_linked_list_insert(void **begin, void **end, ptrdiff_t loc_prev, ptrdiff_t loc_next, void *node, void *new_node); /** @@ -304,8 +300,8 @@ CX_EXPORT void cx_linked_list_insert(void **begin, void **end, * @param insert_begin a pointer to the first node of the chain that shall be inserted * @param insert_end a pointer to the last node of the chain (or NULL if the last node shall be determined) */ -cx_attr_nonnull_arg(6) -CX_EXPORT void cx_linked_list_insert_chain(void **begin, void **end, +CX_EXTERN CX_NONNULL_ARG(6) +void cx_linked_list_insert_chain(void **begin, void **end, ptrdiff_t loc_prev, ptrdiff_t loc_next, void *node, void *insert_begin, void *insert_end); /** @@ -322,8 +318,8 @@ CX_EXPORT void cx_linked_list_insert_chain(void **begin, void **end, * @param new_node a pointer to the node that shall be inserted * @param cmp_func a compare function that will receive the node pointers */ -cx_attr_nonnull_arg(1, 5, 6) -CX_EXPORT void cx_linked_list_insert_sorted(void **begin, void **end, +CX_EXTERN CX_NONNULL_ARG(1, 5, 6) +void cx_linked_list_insert_sorted(void **begin, void **end, ptrdiff_t loc_prev, ptrdiff_t loc_next, void *new_node, cx_compare_func cmp_func); /** @@ -345,8 +341,8 @@ CX_EXPORT void cx_linked_list_insert_sorted(void **begin, void **end, * @param insert_begin a pointer to the first node of the chain that shall be inserted * @param cmp_func a compare function that will receive the node pointers */ -cx_attr_nonnull_arg(1, 5, 6) -CX_EXPORT void cx_linked_list_insert_sorted_chain(void **begin, void **end, +CX_EXTERN CX_NONNULL_ARG(1, 5, 6) +void cx_linked_list_insert_sorted_chain(void **begin, void **end, ptrdiff_t loc_prev, ptrdiff_t loc_next, void *insert_begin, cx_compare_func cmp_func); /** @@ -365,8 +361,8 @@ CX_EXPORT void cx_linked_list_insert_sorted_chain(void **begin, void **end, * @retval zero when the node was inserted * @retval non-zero when a node with the same value already exists */ -cx_attr_nonnull_arg(1, 5, 6) -CX_EXPORT int cx_linked_list_insert_unique(void **begin, void **end, +CX_EXTERN CX_NONNULL_ARG(1, 5, 6) +int cx_linked_list_insert_unique(void **begin, void **end, ptrdiff_t loc_prev, ptrdiff_t loc_next, void *new_node, cx_compare_func cmp_func); /** @@ -387,8 +383,8 @@ CX_EXPORT int cx_linked_list_insert_unique(void **begin, void **end, * @param cmp_func a compare function that will receive the node pointers * @return a pointer to a new chain with all duplicates that were not inserted (or @c NULL when there were no duplicates) */ -cx_attr_nonnull_arg(1, 5, 6) cx_attr_nodiscard -CX_EXPORT void *cx_linked_list_insert_unique_chain(void **begin, void **end, +CX_EXTERN CX_NONNULL_ARG(1, 5, 6) CX_NODISCARD +void *cx_linked_list_insert_unique_chain(void **begin, void **end, ptrdiff_t loc_prev, ptrdiff_t loc_next, void *insert_begin, cx_compare_func cmp_func); /** @@ -406,8 +402,8 @@ CX_EXPORT void *cx_linked_list_insert_unique_chain(void **begin, void **end, * @param cmp_func a compare function that will receive the node pointers * @param context context for the compare function */ -cx_attr_nonnull_arg(1, 5, 6) -CX_EXPORT void cx_linked_list_insert_sorted_c(void **begin, void **end, +CX_EXTERN CX_NONNULL_ARG(1, 5, 6) +void cx_linked_list_insert_sorted_c(void **begin, void **end, ptrdiff_t loc_prev, ptrdiff_t loc_next, void *new_node, cx_compare_func2 cmp_func, void *context); /** @@ -430,8 +426,8 @@ CX_EXPORT void cx_linked_list_insert_sorted_c(void **begin, void **end, * @param cmp_func a compare function that will receive the node pointers * @param context context for the compare function */ -cx_attr_nonnull_arg(1, 5, 6) -CX_EXPORT void cx_linked_list_insert_sorted_chain_c(void **begin, void **end, +CX_EXTERN CX_NONNULL_ARG(1, 5, 6) +void cx_linked_list_insert_sorted_chain_c(void **begin, void **end, ptrdiff_t loc_prev, ptrdiff_t loc_next, void *insert_begin, cx_compare_func2 cmp_func, void *context); /** @@ -447,11 +443,12 @@ CX_EXPORT void cx_linked_list_insert_sorted_chain_c(void **begin, void **end, * @param loc_next the location of a @c next pointer within your node struct (required) * @param new_node a pointer to the node that shall be inserted * @param cmp_func a compare function that will receive the node pointers + * @param context the context for the compare function * @retval zero when the node was inserted * @retval non-zero when a node with the same value already exists */ -cx_attr_nonnull_arg(1, 5, 6) -CX_EXPORT int cx_linked_list_insert_unique_c(void **begin, void **end, +CX_EXTERN CX_NONNULL_ARG(1, 5, 6) +int cx_linked_list_insert_unique_c(void **begin, void **end, ptrdiff_t loc_prev, ptrdiff_t loc_next, void *new_node, cx_compare_func2 cmp_func, void *context); /** @@ -473,8 +470,8 @@ CX_EXPORT int cx_linked_list_insert_unique_c(void **begin, void **end, * @param context context for the compare function * @return a pointer to a new chain with all duplicates that were not inserted (or @c NULL when there were no duplicates) */ -cx_attr_nonnull_arg(1, 5, 6) cx_attr_nodiscard -CX_EXPORT void *cx_linked_list_insert_unique_chain_c(void **begin, void **end, +CX_EXTERN CX_NONNULL_ARG(1, 5, 6) CX_NODISCARD +void *cx_linked_list_insert_unique_chain_c(void **begin, void **end, ptrdiff_t loc_prev, ptrdiff_t loc_next, void *insert_begin, cx_compare_func2 cmp_func, void *context); /** @@ -498,8 +495,8 @@ CX_EXPORT void *cx_linked_list_insert_unique_chain_c(void **begin, void **end, * @param num the number of nodes to remove * @return the actual number of nodes that were removed (can be less when the list did not have enough nodes) */ -cx_attr_nonnull_arg(5) -CX_EXPORT size_t cx_linked_list_remove_chain(void **begin, void **end, +CX_EXTERN CX_NONNULL_ARG(5) +size_t cx_linked_list_remove_chain(void **begin, void **end, ptrdiff_t loc_prev, ptrdiff_t loc_next, void *node, size_t num); /** @@ -521,8 +518,8 @@ CX_EXPORT size_t cx_linked_list_remove_chain(void **begin, void **end, * @param loc_next the location of a @c next pointer within your node struct (required) * @param node the node to remove */ -cx_attr_nonnull_arg(5) -CX_EXPORT void cx_linked_list_remove(void **begin, void **end, +CX_EXTERN CX_NONNULL_ARG(5) +void cx_linked_list_remove(void **begin, void **end, ptrdiff_t loc_prev, ptrdiff_t loc_next, void *node); /** @@ -532,8 +529,8 @@ CX_EXPORT void cx_linked_list_remove(void **begin, void **end, * @param loc_next the location of the @c next pointer within the node struct * @return the size of the list or zero if @p node is @c NULL */ -cx_attr_nodiscard -CX_EXPORT size_t cx_linked_list_size(const void *node, ptrdiff_t loc_next); +CX_EXTERN CX_NODISCARD +size_t cx_linked_list_size(const void *node, ptrdiff_t loc_next); /** * Sorts a linked list based on a comparison function. @@ -547,8 +544,8 @@ CX_EXPORT size_t cx_linked_list_size(const void *node, ptrdiff_t loc_next); * @param loc_data the location of the @c data pointer within your node struct * @param cmp_func the compare function defining the sort order */ -cx_attr_nonnull_arg(1, 6) -CX_EXPORT void cx_linked_list_sort(void **begin, void **end, +CX_EXTERN CX_NONNULL_ARG(1, 6) +void cx_linked_list_sort(void **begin, void **end, ptrdiff_t loc_prev, ptrdiff_t loc_next, ptrdiff_t loc_data, cx_compare_func cmp_func); /** @@ -564,11 +561,10 @@ CX_EXPORT void cx_linked_list_sort(void **begin, void **end, * @param cmp_func the compare function defining the sort order * @param context additional context for the compare function */ -cx_attr_nonnull_arg(1, 6) -CX_EXPORT void cx_linked_list_sort_c(void **begin, void **end, +CX_EXTERN CX_NONNULL_ARG(1, 6) +void cx_linked_list_sort_c(void **begin, void **end, ptrdiff_t loc_prev, ptrdiff_t loc_next, ptrdiff_t loc_data, cx_compare_func2 cmp_func, void *context); - /** * Compares two lists element wise. * @@ -582,8 +578,8 @@ CX_EXPORT void cx_linked_list_sort_c(void **begin, void **end, * @return the first non-zero result of invoking @p cmp_func or: negative if the left list is smaller than the * right list, positive if the left list is larger than the right list, zero if both lists are equal. */ -cx_attr_nonnull_arg(5) -CX_EXPORT int cx_linked_list_compare(const void *begin_left, const void *begin_right, +CX_EXTERN CX_NONNULL_ARG(5) +int cx_linked_list_compare(const void *begin_left, const void *begin_right, ptrdiff_t loc_advance, ptrdiff_t loc_data, cx_compare_func cmp_func); /** @@ -596,11 +592,12 @@ CX_EXPORT int cx_linked_list_compare(const void *begin_left, const void *begin_r * @param loc_advance the location of the pointer to advance * @param loc_data the location of the @c data pointer within your node struct * @param cmp_func the function to compare the elements + * @param context the context for the compare function * @return the first non-zero result of invoking @p cmp_func or: negative if the left list is smaller than the * right list, positive if the left list is larger than the right list, zero if both lists are equal. */ -cx_attr_nonnull_arg(5) -CX_EXPORT int cx_linked_list_compare_c(const void *begin_left, const void *begin_right, +CX_EXTERN CX_NONNULL_ARG(5) +int cx_linked_list_compare_c(const void *begin_left, const void *begin_right, ptrdiff_t loc_advance, ptrdiff_t loc_data, cx_compare_func2 cmp_func, void *context); /** @@ -611,11 +608,7 @@ CX_EXPORT int cx_linked_list_compare_c(const void *begin_left, const void *begin * @param loc_prev the location of a @c prev pointer within your node struct (negative if your struct does not have one) * @param loc_next the location of a @c next pointer within your node struct (required) */ -cx_attr_nonnull_arg(1) -CX_EXPORT void cx_linked_list_reverse(void **begin, void **end, ptrdiff_t loc_prev, ptrdiff_t loc_next); - -#ifdef __cplusplus -} // extern "C" -#endif +CX_EXTERN CX_NONNULL_ARG(1) +void cx_linked_list_reverse(void **begin, void **end, ptrdiff_t loc_prev, ptrdiff_t loc_next); #endif // UCX_LINKED_LIST_H diff --git a/ucx/cx/list.h b/ucx/cx/list.h index 1c70e76..7ea0983 100644 --- a/ucx/cx/list.h +++ b/ucx/cx/list.h @@ -39,10 +39,6 @@ #include "common.h" #include "collection.h" -#ifdef __cplusplus -extern "C" { -#endif - /** * List class type. */ @@ -206,8 +202,8 @@ CX_EXPORT extern CxList *const cxEmptyList; * @param n the number of elements to insert * @return the number of elements actually inserted */ -cx_attr_nonnull_arg(1) -CX_EXPORT size_t cx_list_default_insert_array(struct cx_list_s *list, +CX_EXTERN CX_NONNULL_ARG(1) +size_t cx_list_default_insert_array(struct cx_list_s *list, size_t index, const void *data, size_t n); /** @@ -226,8 +222,8 @@ CX_EXPORT size_t cx_list_default_insert_array(struct cx_list_s *list, * @param n the number of elements to insert * @return the number of elements actually inserted */ -cx_attr_nonnull -CX_EXPORT size_t cx_list_default_insert_sorted(struct cx_list_s *list, +CX_EXTERN CX_NONNULL +size_t cx_list_default_insert_sorted(struct cx_list_s *list, const void *sorted_data, size_t n); /** @@ -246,8 +242,8 @@ CX_EXPORT size_t cx_list_default_insert_sorted(struct cx_list_s *list, * @param n the number of elements to insert * @return the number of elements from the @p sorted_data that are definitely present in the list after this call */ -cx_attr_nonnull -CX_EXPORT size_t cx_list_default_insert_unique(struct cx_list_s *list, +CX_EXTERN CX_NONNULL +size_t cx_list_default_insert_unique(struct cx_list_s *list, const void *sorted_data, size_t n); /** @@ -261,8 +257,8 @@ CX_EXPORT size_t cx_list_default_insert_unique(struct cx_list_s *list, * * @param list the list that shall be sorted */ -cx_attr_nonnull -CX_EXPORT void cx_list_default_sort(struct cx_list_s *list); +CX_EXTERN CX_NONNULL +void cx_list_default_sort(struct cx_list_s *list); /** * Default unoptimized swap implementation. @@ -277,8 +273,8 @@ CX_EXPORT void cx_list_default_sort(struct cx_list_s *list); * @retval non-zero when indices are out of bounds or memory * allocation for the temporary buffer fails */ -cx_attr_nonnull -CX_EXPORT int cx_list_default_swap(struct cx_list_s *list, size_t i, size_t j); +CX_EXTERN CX_NONNULL +int cx_list_default_swap(struct cx_list_s *list, size_t i, size_t j); /** * Initializes a list struct. @@ -319,8 +315,8 @@ CX_EXPORT int cx_list_default_swap(struct cx_list_s *list, size_t i, size_t j); * @param allocator the allocator for the elements * @param elem_size the size of one element */ -cx_attr_nonnull_arg(1, 2, 3) -CX_EXPORT void cx_list_init(struct cx_list_s *list, +CX_EXTERN CX_NONNULL_ARG(1, 2, 3) +void cx_list_init(struct cx_list_s *list, struct cx_list_class_s *cl, const struct cx_allocator_s *allocator, size_t elem_size); @@ -332,8 +328,8 @@ CX_EXPORT void cx_list_init(struct cx_list_s *list, * @param list the list which is comparing the elements * @return the comparison result */ -cx_attr_nonnull -CX_EXPORT int cx_list_compare_wrapper( +CX_EXTERN CX_NONNULL +int cx_list_compare_wrapper( const void *left, const void *right, void *list); /** @@ -342,8 +338,8 @@ CX_EXPORT int cx_list_compare_wrapper( * @param list the list * @return the number of currently stored elements */ -cx_attr_nonnull -CX_EXPORT size_t cxListSize(const CxList *list); +CX_EXTERN CX_NONNULL +size_t cxListSize(const CxList *list); /** * Adds an item to the end of the list. @@ -355,8 +351,8 @@ CX_EXPORT size_t cxListSize(const CxList *list); * @see cxListAddArray() * @see cxListEmplace() */ -cx_attr_nonnull -CX_EXPORT int cxListAdd(CxList *list, const void *elem); +CX_EXTERN CX_NONNULL +int cxListAdd(CxList *list, const void *elem); /** * Adds multiple items to the end of the list. @@ -375,8 +371,8 @@ CX_EXPORT int cxListAdd(CxList *list, const void *elem); * @return the number of added elements * @see cxListEmplaceArray() */ -cx_attr_nonnull -CX_EXPORT size_t cxListAddArray(CxList *list, const void *array, size_t n); +CX_EXTERN CX_NONNULL +size_t cxListAddArray(CxList *list, const void *array, size_t n); /** * Inserts an item at the specified index. @@ -392,8 +388,8 @@ CX_EXPORT size_t cxListAddArray(CxList *list, const void *array, size_t n); * @see cxListInsertBefore() * @see cxListEmplaceAt() */ -cx_attr_nonnull -CX_EXPORT int cxListInsert(CxList *list, size_t index, const void *elem); +CX_EXTERN CX_NONNULL +int cxListInsert(CxList *list, size_t index, const void *elem); /** * Allocates memory for an element at the specified index and returns a pointer to that memory. @@ -407,8 +403,8 @@ CX_EXPORT int cxListInsert(CxList *list, size_t index, const void *elem); * @see cxListEmplaceArrayAt() * @see cxListInsert() */ -cx_attr_nonnull -CX_EXPORT void *cxListEmplaceAt(CxList *list, size_t index); +CX_EXTERN CX_NONNULL CX_NODISCARD +void *cxListEmplaceAt(CxList *list, size_t index); /** * Allocates memory for an element at the end of the list and returns a pointer to that memory. @@ -420,8 +416,8 @@ CX_EXPORT void *cxListEmplaceAt(CxList *list, size_t index); * @see cxListEmplaceAt() * @see cxListAdd() */ -cx_attr_nonnull -CX_EXPORT void *cxListEmplace(CxList *list); +CX_EXTERN CX_NONNULL CX_NODISCARD +void *cxListEmplace(CxList *list); /** * Allocates memory for multiple elements and returns an iterator. @@ -440,8 +436,8 @@ CX_EXPORT void *cxListEmplace(CxList *list); * @see cxListEmplaceAt() * @see cxListInsertArray() */ -cx_attr_nonnull -CX_EXPORT CxIterator cxListEmplaceArrayAt(CxList *list, size_t index, size_t n); +CX_EXTERN CX_NONNULL CX_NODISCARD +CxIterator cxListEmplaceArrayAt(CxList *list, size_t index, size_t n); /** * Allocates memory for multiple elements and returns an iterator. @@ -459,8 +455,8 @@ CX_EXPORT CxIterator cxListEmplaceArrayAt(CxList *list, size_t index, size_t n); * @see cxListEmplace() * @see cxListAddArray() */ -cx_attr_nonnull -CX_EXPORT CxIterator cxListEmplaceArray(CxList *list, size_t n); +CX_EXTERN CX_NONNULL CX_NODISCARD +CxIterator cxListEmplaceArray(CxList *list, size_t n); /** * Inserts an item into a sorted list. @@ -472,8 +468,8 @@ CX_EXPORT CxIterator cxListEmplaceArray(CxList *list, size_t n); * @retval zero success * @retval non-zero memory allocation failure */ -cx_attr_nonnull -CX_EXPORT int cxListInsertSorted(CxList *list, const void *elem); +CX_EXTERN CX_NONNULL +int cxListInsertSorted(CxList *list, const void *elem); /** * Inserts an item into a list if it does not exist. @@ -488,8 +484,8 @@ CX_EXPORT int cxListInsertSorted(CxList *list, const void *elem); * @retval zero success (also when the element was already in the list) * @retval non-zero memory allocation failure */ -cx_attr_nonnull -CX_EXPORT int cxListInsertUnique(CxList *list, const void *elem); +CX_EXTERN CX_NONNULL +int cxListInsertUnique(CxList *list, const void *elem); /** * Inserts multiple items to the list at the specified index. @@ -511,8 +507,8 @@ CX_EXPORT int cxListInsertUnique(CxList *list, const void *elem); * @return the number of added elements * @see cxListEmplaceArrayAt() */ -cx_attr_nonnull -CX_EXPORT size_t cxListInsertArray(CxList *list, size_t index, const void *array, size_t n); +CX_EXTERN CX_NONNULL +size_t cxListInsertArray(CxList *list, size_t index, const void *array, size_t n); /** * Inserts a sorted array into a sorted list. @@ -533,8 +529,8 @@ CX_EXPORT size_t cxListInsertArray(CxList *list, size_t index, const void *array * @param n the number of elements to add * @return the number of added elements */ -cx_attr_nonnull -CX_EXPORT size_t cxListInsertSortedArray(CxList *list, const void *array, size_t n); +CX_EXTERN CX_NONNULL +size_t cxListInsertSortedArray(CxList *list, const void *array, size_t n); /** * Inserts an array into a list, skipping duplicates. @@ -568,8 +564,8 @@ CX_EXPORT size_t cxListInsertSortedArray(CxList *list, const void *array, size_t * * @return the number of elements from the @p sorted_data that are definitely present in the list after this call */ -cx_attr_nonnull -CX_EXPORT size_t cxListInsertUniqueArray(CxList *list, const void *array, size_t n); +CX_EXTERN CX_NONNULL +size_t cxListInsertUniqueArray(CxList *list, const void *array, size_t n); /** * Inserts an element after the current location of the specified iterator. @@ -587,8 +583,8 @@ CX_EXPORT size_t cxListInsertUniqueArray(CxList *list, const void *array, size_t * @see cxListInsert() * @see cxListInsertBefore() */ -cx_attr_nonnull -CX_EXPORT int cxListInsertAfter(CxIterator *iter, const void *elem); +CX_EXTERN CX_NONNULL +int cxListInsertAfter(CxIterator *iter, const void *elem); /** * Inserts an element before the current location of the specified iterator. @@ -606,8 +602,8 @@ CX_EXPORT int cxListInsertAfter(CxIterator *iter, const void *elem); * @see cxListInsert() * @see cxListInsertAfter() */ -cx_attr_nonnull -CX_EXPORT int cxListInsertBefore(CxIterator *iter, const void *elem); +CX_EXTERN CX_NONNULL +int cxListInsertBefore(CxIterator *iter, const void *elem); /** * Removes the element at the specified index. @@ -620,8 +616,8 @@ CX_EXPORT int cxListInsertBefore(CxIterator *iter, const void *elem); * @retval zero success * @retval non-zero index out of bounds */ -cx_attr_nonnull -CX_EXPORT int cxListRemove(CxList *list, size_t index); +CX_EXTERN CX_NONNULL +int cxListRemove(CxList *list, size_t index); /** * Removes and returns the element at the specified index. @@ -636,8 +632,8 @@ CX_EXPORT int cxListRemove(CxList *list, size_t index); * @retval zero success * @retval non-zero index out of bounds */ -cx_attr_nonnull cx_attr_access_w(3) -CX_EXPORT int cxListRemoveAndGet(CxList *list, size_t index, void *targetbuf); +CX_EXTERN CX_NONNULL CX_ACCESS_W(3) +int cxListRemoveAndGet(CxList *list, size_t index, void *targetbuf); /** * Removes and returns the first element of the list. @@ -653,8 +649,8 @@ CX_EXPORT int cxListRemoveAndGet(CxList *list, size_t index, void *targetbuf); * @see cxListPopFront() * @see cxListRemoveAndGetLast() */ -cx_attr_nonnull cx_attr_access_w(2) -CX_EXPORT int cxListRemoveAndGetFirst(CxList *list, void *targetbuf); +CX_EXTERN CX_NONNULL CX_ACCESS_W(2) +int cxListRemoveAndGetFirst(CxList *list, void *targetbuf); /** * Removes and returns the first element of the list. @@ -687,8 +683,8 @@ CX_EXPORT int cxListRemoveAndGetFirst(CxList *list, void *targetbuf); * @retval zero success * @retval non-zero the list is empty */ -cx_attr_nonnull cx_attr_access_w(2) -CX_EXPORT int cxListRemoveAndGetLast(CxList *list, void *targetbuf); +CX_EXTERN CX_NONNULL CX_ACCESS_W(2) +int cxListRemoveAndGetLast(CxList *list, void *targetbuf); /** * Removes and returns the last element of the list. @@ -723,8 +719,8 @@ CX_EXPORT int cxListRemoveAndGetLast(CxList *list, void *targetbuf); * @param num the number of elements to remove * @return the actual number of removed elements */ -cx_attr_nonnull -CX_EXPORT size_t cxListRemoveArray(CxList *list, size_t index, size_t num); +CX_EXTERN CX_NONNULL +size_t cxListRemoveArray(CxList *list, size_t index, size_t num); /** * Removes and returns multiple elements starting at the specified index. @@ -739,8 +735,8 @@ CX_EXPORT size_t cxListRemoveArray(CxList *list, size_t index, size_t num); * @param targetbuf a buffer where to copy the elements * @return the actual number of removed elements */ -cx_attr_nonnull cx_attr_access_w(4) -CX_EXPORT size_t cxListRemoveArrayAndGet(CxList *list, size_t index, size_t num, void *targetbuf); +CX_EXTERN CX_NONNULL CX_ACCESS_W(4) +size_t cxListRemoveArrayAndGet(CxList *list, size_t index, size_t num, void *targetbuf); /** * Removes all elements from this list. @@ -750,8 +746,8 @@ CX_EXPORT size_t cxListRemoveArrayAndGet(CxList *list, size_t index, size_t num, * * @param list the list */ -cx_attr_nonnull -CX_EXPORT void cxListClear(CxList *list); +CX_EXTERN CX_NONNULL +void cxListClear(CxList *list); /** * Swaps two items in the list. @@ -766,8 +762,8 @@ CX_EXPORT void cxListClear(CxList *list); * @retval non-zero one of the indices is out of bounds, * or the swap needed extra memory, but allocation failed */ -cx_attr_nonnull -CX_EXPORT int cxListSwap(CxList *list, size_t i, size_t j); +CX_EXTERN CX_NONNULL +int cxListSwap(CxList *list, size_t i, size_t j); /** * Returns a pointer to the element at the specified index. @@ -778,8 +774,8 @@ CX_EXPORT int cxListSwap(CxList *list, size_t i, size_t j); * @param index the index of the element * @return a pointer to the element or @c NULL if the index is out of bounds */ -cx_attr_nonnull -CX_EXPORT void *cxListAt(const CxList *list, size_t index); +CX_EXTERN CX_NONNULL +void *cxListAt(const CxList *list, size_t index); /** * Returns a pointer to the first element. @@ -789,8 +785,8 @@ CX_EXPORT void *cxListAt(const CxList *list, size_t index); * @param list the list * @return a pointer to the first element or @c NULL if the list is empty */ -cx_attr_nonnull -CX_EXPORT void *cxListFirst(const CxList *list); +CX_EXTERN CX_NONNULL +void *cxListFirst(const CxList *list); /** * Returns a pointer to the last element. @@ -800,8 +796,8 @@ CX_EXPORT void *cxListFirst(const CxList *list); * @param list the list * @return a pointer to the last element or @c NULL if the list is empty */ -cx_attr_nonnull -CX_EXPORT void *cxListLast(const CxList *list); +CX_EXTERN CX_NONNULL +void *cxListLast(const CxList *list); /** * Sets the element at the specified index in the list. @@ -815,8 +811,8 @@ CX_EXPORT void *cxListLast(const CxList *list); * @retval zero on success * @retval non-zero when index is out of bounds */ -cx_attr_nonnull -CX_EXPORT int cxListSet(CxList *list, size_t index, const void *elem); +CX_EXTERN CX_NONNULL +int cxListSet(CxList *list, size_t index, const void *elem); /** * Returns an iterator pointing to the item at the specified index. @@ -829,8 +825,8 @@ CX_EXPORT int cxListSet(CxList *list, size_t index, const void *elem); * @param index the index where the iterator shall point at * @return a new iterator */ -cx_attr_nodiscard -CX_EXPORT CxIterator cxListIteratorAt(const CxList *list, size_t index); +CX_EXTERN CX_NODISCARD +CxIterator cxListIteratorAt(const CxList *list, size_t index); /** * Returns a backwards iterator pointing to the item at the specified index. @@ -843,8 +839,8 @@ CX_EXPORT CxIterator cxListIteratorAt(const CxList *list, size_t index); * @param index the index where the iterator shall point at * @return a new iterator */ -cx_attr_nodiscard -CX_EXPORT CxIterator cxListBackwardsIteratorAt(const CxList *list, size_t index); +CX_EXTERN CX_NODISCARD +CxIterator cxListBackwardsIteratorAt(const CxList *list, size_t index); /** * Returns an iterator pointing to the first item of the list. @@ -856,8 +852,8 @@ CX_EXPORT CxIterator cxListBackwardsIteratorAt(const CxList *list, size_t index) * @param list the list * @return a new iterator */ -cx_attr_nodiscard -CX_EXPORT CxIterator cxListIterator(const CxList *list); +CX_EXTERN CX_NODISCARD +CxIterator cxListIterator(const CxList *list); /** * Returns a backwards iterator pointing to the last item of the list. @@ -869,8 +865,8 @@ CX_EXPORT CxIterator cxListIterator(const CxList *list); * @param list the list * @return a new iterator */ -cx_attr_nodiscard -CX_EXPORT CxIterator cxListBackwardsIterator(const CxList *list); +CX_EXTERN CX_NODISCARD +CxIterator cxListBackwardsIterator(const CxList *list); /** * Returns the index of the first element that equals @p elem. @@ -883,8 +879,8 @@ CX_EXPORT CxIterator cxListBackwardsIterator(const CxList *list); * @see cxListIndexValid() * @see cxListContains() */ -cx_attr_nonnull cx_attr_nodiscard -CX_EXPORT size_t cxListFind(const CxList *list, const void *elem); +CX_EXTERN CX_NONNULL CX_NODISCARD +size_t cxListFind(const CxList *list, const void *elem); /** * Checks if the list contains the specified element. @@ -897,8 +893,8 @@ CX_EXPORT size_t cxListFind(const CxList *list, const void *elem); * @retval false if the element is not contained * @see cxListFind() */ -cx_attr_nonnull cx_attr_nodiscard -CX_EXPORT bool cxListContains(const CxList* list, const void* elem); +CX_EXTERN CX_NONNULL CX_NODISCARD +bool cxListContains(const CxList* list, const void* elem); /** * Checks if the specified index is within bounds. @@ -908,8 +904,8 @@ CX_EXPORT bool cxListContains(const CxList* list, const void* elem); * @retval true if the index is within bounds * @retval false if the index is out of bounds */ -cx_attr_nonnull cx_attr_nodiscard -CX_EXPORT bool cxListIndexValid(const CxList *list, size_t index); +CX_EXTERN CX_NONNULL CX_NODISCARD +bool cxListIndexValid(const CxList *list, size_t index); /** * Removes and returns the index of the first element that equals @p elem. @@ -922,8 +918,8 @@ CX_EXPORT bool cxListIndexValid(const CxList *list, size_t index); * when the element is not found or could not be removed * @see cxListIndexValid() */ -cx_attr_nonnull -CX_EXPORT size_t cxListFindRemove(CxList *list, const void *elem); +CX_EXTERN CX_NONNULL +size_t cxListFindRemove(CxList *list, const void *elem); /** * Sorts the list. @@ -932,16 +928,16 @@ CX_EXPORT size_t cxListFindRemove(CxList *list, const void *elem); * * @param list the list */ -cx_attr_nonnull -CX_EXPORT void cxListSort(CxList *list); +CX_EXTERN CX_NONNULL +void cxListSort(CxList *list); /** * Reverses the order of the items. * * @param list the list */ -cx_attr_nonnull -CX_EXPORT void cxListReverse(CxList *list); +CX_EXTERN CX_NONNULL +void cxListReverse(CxList *list); /** * Compares a list to another list of the same type. @@ -957,8 +953,8 @@ CX_EXPORT void cxListReverse(CxList *list); * @retval positive the first list is larger * or the first non-equal element in the first list is larger */ -cx_attr_nonnull cx_attr_nodiscard -CX_EXPORT int cxListCompare(const CxList *list, const CxList *other); +CX_EXTERN CX_NONNULL CX_NODISCARD +int cxListCompare(const CxList *list, const CxList *other); /** * Deallocates the memory of the specified list structure. @@ -967,7 +963,8 @@ CX_EXPORT int cxListCompare(const CxList *list, const CxList *other); * * @param list the list that shall be freed */ -CX_EXPORT void cxListFree(CxList *list); +CX_EXTERN +void cxListFree(CxList *list); /** @@ -989,8 +986,8 @@ CX_EXPORT void cxListFree(CxList *list); * @retval non-zero when an allocation error occurred * @see cxListCloneShallow() */ -cx_attr_nonnull_arg(1, 2, 3) -CX_EXPORT int cxListClone(CxList *dst, const CxList *src, +CX_EXTERN CX_NONNULL_ARG(1, 2, 3) +int cxListClone(CxList *dst, const CxList *src, cx_clone_func clone_func, const CxAllocator *clone_allocator, void *data); /** @@ -1012,8 +1009,8 @@ CX_EXPORT int cxListClone(CxList *dst, const CxList *src, * @retval non-zero when an allocation error occurred * @see cxListDifferenceShallow() */ -cx_attr_nonnull_arg(1, 2, 3, 4) -CX_EXPORT int cxListDifference(CxList *dst, +CX_EXTERN CX_NONNULL_ARG(1, 2, 3, 4) +int cxListDifference(CxList *dst, const CxList *minuend, const CxList *subtrahend, cx_clone_func clone_func, const CxAllocator *clone_allocator, void *data); @@ -1036,8 +1033,8 @@ CX_EXPORT int cxListDifference(CxList *dst, * @retval non-zero when an allocation error occurred * @see cxListIntersectionShallow() */ -cx_attr_nonnull_arg(1, 2, 3, 4) -CX_EXPORT int cxListIntersection(CxList *dst, const CxList *src, const CxList *other, +CX_EXTERN CX_NONNULL_ARG(1, 2, 3, 4) +int cxListIntersection(CxList *dst, const CxList *src, const CxList *other, cx_clone_func clone_func, const CxAllocator *clone_allocator, void *data); /** @@ -1061,8 +1058,8 @@ CX_EXPORT int cxListIntersection(CxList *dst, const CxList *src, const CxList *o * @retval non-zero when an allocation error occurred * @see cxListUnionShallow() */ -cx_attr_nonnull_arg(1, 2, 3, 4) -CX_EXPORT int cxListUnion(CxList *dst, const CxList *src, const CxList *other, +CX_EXTERN CX_NONNULL_ARG(1, 2, 3, 4) +int cxListUnion(CxList *dst, const CxList *src, const CxList *other, cx_clone_func clone_func, const CxAllocator *clone_allocator, void *data); /** @@ -1084,8 +1081,8 @@ CX_EXPORT int cxListUnion(CxList *dst, const CxList *src, const CxList *other, * @retval non-zero when an allocation error occurred * @see cxListClone() */ -cx_attr_nonnull -CX_EXPORT int cxListCloneShallow(CxList *dst, const CxList *src); +CX_EXTERN CX_NONNULL +int cxListCloneShallow(CxList *dst, const CxList *src); /** * Clones elements from a list only if they are not present in another list. @@ -1106,8 +1103,8 @@ CX_EXPORT int cxListCloneShallow(CxList *dst, const CxList *src); * @retval non-zero when an allocation error occurred * @see cxListDifference() */ -cx_attr_nonnull -CX_EXPORT int cxListDifferenceShallow(CxList *dst, +CX_EXTERN CX_NONNULL +int cxListDifferenceShallow(CxList *dst, const CxList *minuend, const CxList *subtrahend); /** @@ -1129,8 +1126,8 @@ CX_EXPORT int cxListDifferenceShallow(CxList *dst, * @retval non-zero when an allocation error occurred * @see cxListIntersection() */ -cx_attr_nonnull -CX_EXPORT int cxListIntersectionShallow(CxList *dst, const CxList *src, const CxList *other); +CX_EXTERN CX_NONNULL +int cxListIntersectionShallow(CxList *dst, const CxList *src, const CxList *other); /** * Performs a deep clone of one list into another, skipping duplicates. @@ -1153,8 +1150,8 @@ CX_EXPORT int cxListIntersectionShallow(CxList *dst, const CxList *src, const Cx * @retval non-zero when an allocation error occurred * @see cxListUnion() */ -cx_attr_nonnull -CX_EXPORT int cxListUnionShallow(CxList *dst, const CxList *src, const CxList *other); +CX_EXTERN CX_NONNULL +int cxListUnionShallow(CxList *dst, const CxList *src, const CxList *other); /** * Asks the list to reserve enough memory for a given total number of elements. @@ -1173,8 +1170,8 @@ CX_EXPORT int cxListUnionShallow(CxList *dst, const CxList *src, const CxList *o * @retval non-zero when an allocation error occurred * @see cxListShrink() */ -cx_attr_nonnull -CX_EXPORT int cxListReserve(CxList *list, size_t capacity); +CX_EXTERN CX_NONNULL +int cxListReserve(CxList *list, size_t capacity); /** * Advises the list to free any overallocated memory. @@ -1187,11 +1184,7 @@ CX_EXPORT int cxListReserve(CxList *list, size_t capacity); * @param list the list * @return usually zero */ -cx_attr_nonnull -CX_EXPORT int cxListShrink(CxList *list); - -#ifdef __cplusplus -} // extern "C" -#endif +CX_EXTERN CX_NONNULL +int cxListShrink(CxList *list); #endif // UCX_LIST_H diff --git a/ucx/cx/map.h b/ucx/cx/map.h index 78944f5..7492b4e 100644 --- a/ucx/cx/map.h +++ b/ucx/cx/map.h @@ -46,10 +46,6 @@ typedef struct cx_list_s CxList; #endif -#ifdef __cplusplus -extern "C" { -#endif - /** Type for the UCX map. */ typedef struct cx_map_s CxMap; @@ -227,8 +223,8 @@ CX_EXPORT extern CxMap *const cxEmptyMap; * * @param map the map to be freed */ -CX_EXPORT void cxMapFree(CxMap *map); - +CX_EXTERN +void cxMapFree(CxMap *map); /** * Clears a map by removing all elements. @@ -237,8 +233,8 @@ CX_EXPORT void cxMapFree(CxMap *map); * * @param map the map to be cleared */ -cx_attr_nonnull -CX_EXPORT void cxMapClear(CxMap *map); +CX_EXTERN CX_NONNULL +void cxMapClear(CxMap *map); /** * Returns the number of elements in this map. @@ -246,8 +242,8 @@ CX_EXPORT void cxMapClear(CxMap *map); * @param map the map * @return the number of stored elements */ -cx_attr_nonnull -CX_EXPORT size_t cxMapSize(const CxMap *map); +CX_EXTERN CX_NONNULL +size_t cxMapSize(const CxMap *map); /** * Creates a value iterator for a map. @@ -262,8 +258,8 @@ CX_EXPORT size_t cxMapSize(const CxMap *map); * @param map the map to create the iterator for (can be @c NULL) * @return an iterator for the currently stored values */ -cx_attr_nodiscard -CX_EXPORT CxMapIterator cxMapIteratorValues(const CxMap *map); +CX_EXTERN CX_NODISCARD +CxMapIterator cxMapIteratorValues(const CxMap *map); /** * Creates a key iterator for a map. @@ -277,8 +273,8 @@ CX_EXPORT CxMapIterator cxMapIteratorValues(const CxMap *map); * @param map the map to create the iterator for (can be @c NULL) * @return an iterator for the currently stored keys */ -cx_attr_nodiscard -CX_EXPORT CxMapIterator cxMapIteratorKeys(const CxMap *map); +CX_EXTERN CX_NODISCARD +CxMapIterator cxMapIteratorKeys(const CxMap *map); /** * Creates an iterator for a map. @@ -294,8 +290,8 @@ CX_EXPORT CxMapIterator cxMapIteratorKeys(const CxMap *map); * @see cxMapIteratorKeys() * @see cxMapIteratorValues() */ -cx_attr_nodiscard -CX_EXPORT CxMapIterator cxMapIterator(const CxMap *map); +CX_EXTERN CX_NODISCARD +CxMapIterator cxMapIterator(const CxMap *map); /** * Puts a key/value-pair into the map. @@ -317,8 +313,8 @@ CX_EXPORT CxMapIterator cxMapIterator(const CxMap *map); * @retval non-zero value on memory allocation failure * @see cxMapPut() */ -cx_attr_nonnull -CX_EXPORT int cx_map_put(CxMap *map, CxHashKey key, void *value); +CX_EXTERN CX_NONNULL +int cx_map_put(CxMap *map, CxHashKey key, void *value); /** * Puts a key/value-pair into the map. @@ -359,8 +355,8 @@ CX_EXPORT int cx_map_put(CxMap *map, CxHashKey key, void *value); * @return the pointer to the allocated memory or @c NULL if allocation fails * @see cxMapEmplace() */ -cx_attr_nonnull -CX_EXPORT void *cx_map_emplace(CxMap *map, CxHashKey key); +CX_EXTERN CX_NONNULL CX_NODISCARD +void *cx_map_emplace(CxMap *map, CxHashKey key); /** * Allocates memory for a value in the map associated with the specified key. @@ -393,8 +389,8 @@ CX_EXPORT void *cx_map_emplace(CxMap *map, CxHashKey key); * @return the value * @see cxMapGet() */ -cx_attr_nonnull cx_attr_nodiscard -CX_EXPORT void *cx_map_get(const CxMap *map, CxHashKey key); +CX_EXTERN CX_NONNULL CX_NODISCARD +void *cx_map_get(const CxMap *map, CxHashKey key); /** * Retrieves a value by using a key. @@ -436,8 +432,8 @@ CX_EXPORT void *cx_map_get(const CxMap *map, CxHashKey key); * @see cxMapRemove() * @see cxMapRemoveAndGet() */ -cx_attr_nonnull_arg(1) -CX_EXPORT int cx_map_remove(CxMap *map, CxHashKey key, void *targetbuf); +CX_EXTERN CX_NONNULL_ARG(1) +int cx_map_remove(CxMap *map, CxHashKey key, void *targetbuf); /** * Removes a key/value-pair from the map by using the key. @@ -476,7 +472,6 @@ CX_EXPORT int cx_map_remove(CxMap *map, CxHashKey key, void *targetbuf); */ #define cxMapRemoveAndGet(map, key, targetbuf) cx_map_remove(map, CX_HASH_KEY(key), targetbuf) - /** * Performs a deep clone of one map into another. * @@ -499,11 +494,10 @@ CX_EXPORT int cx_map_remove(CxMap *map, CxHashKey key, void *targetbuf); * @retval zero when all elements were successfully cloned * @retval non-zero when an allocation error occurred */ -cx_attr_nonnull_arg(1, 2, 3) -CX_EXPORT int cxMapClone(CxMap *dst, const CxMap *src, +CX_EXTERN CX_NONNULL_ARG(1, 2, 3) +int cxMapClone(CxMap *dst, const CxMap *src, cx_clone_func clone_func, const CxAllocator *clone_allocator, void *data); - /** * Clones entries of a map if their key is not present in another map. * @@ -516,8 +510,8 @@ CX_EXPORT int cxMapClone(CxMap *dst, const CxMap *src, * @retval zero when the elements were successfully cloned * @retval non-zero when an allocation error occurred */ -cx_attr_nonnull_arg(1, 2, 3, 4) -CX_EXPORT int cxMapDifference(CxMap *dst, const CxMap *minuend, const CxMap *subtrahend, +CX_EXTERN CX_NONNULL_ARG(1, 2, 3, 4) +int cxMapDifference(CxMap *dst, const CxMap *minuend, const CxMap *subtrahend, cx_clone_func clone_func, const CxAllocator *clone_allocator, void *data); /** @@ -537,8 +531,8 @@ CX_EXPORT int cxMapDifference(CxMap *dst, const CxMap *minuend, const CxMap *sub * @retval zero when the elements were successfully cloned * @retval non-zero when an allocation error occurred */ -cx_attr_nonnull_arg(1, 2, 3, 4) -CX_EXPORT int cxMapListDifference(CxMap *dst, const CxMap *src, const CxList *keys, +CX_EXTERN CX_NONNULL_ARG(1, 2, 3, 4) +int cxMapListDifference(CxMap *dst, const CxMap *src, const CxList *keys, cx_clone_func clone_func, const CxAllocator *clone_allocator, void *data); @@ -554,8 +548,8 @@ CX_EXPORT int cxMapListDifference(CxMap *dst, const CxMap *src, const CxList *ke * @retval zero when the elements were successfully cloned * @retval non-zero when an allocation error occurred */ -cx_attr_nonnull_arg(1, 2, 3, 4) -CX_EXPORT int cxMapIntersection(CxMap *dst, const CxMap *src, const CxMap *other, +CX_EXTERN CX_NONNULL_ARG(1, 2, 3, 4) +int cxMapIntersection(CxMap *dst, const CxMap *src, const CxMap *other, cx_clone_func clone_func, const CxAllocator *clone_allocator, void *data); /** @@ -575,8 +569,8 @@ CX_EXPORT int cxMapIntersection(CxMap *dst, const CxMap *src, const CxMap *other * @retval zero when the elements were successfully cloned * @retval non-zero when an allocation error occurred */ -cx_attr_nonnull_arg(1, 2, 3, 4) -CX_EXPORT int cxMapListIntersection(CxMap *dst, const CxMap *src, const CxList *keys, +CX_EXTERN CX_NONNULL_ARG(1, 2, 3, 4) +int cxMapListIntersection(CxMap *dst, const CxMap *src, const CxList *keys, cx_clone_func clone_func, const CxAllocator *clone_allocator, void *data); /** @@ -595,8 +589,8 @@ CX_EXPORT int cxMapListIntersection(CxMap *dst, const CxMap *src, const CxList * * @retval zero when the elements were successfully cloned * @retval non-zero when an allocation error occurred */ -cx_attr_nonnull_arg(1, 2, 3) -CX_EXPORT int cxMapUnion(CxMap *dst, const CxMap *src, +CX_EXTERN CX_NONNULL_ARG(1, 2, 3) +int cxMapUnion(CxMap *dst, const CxMap *src, cx_clone_func clone_func, const CxAllocator *clone_allocator, void *data); /** @@ -622,8 +616,8 @@ CX_EXPORT int cxMapUnion(CxMap *dst, const CxMap *src, * @retval non-zero when an allocation error occurred * @see cxMapClone() */ -cx_attr_nonnull -CX_EXPORT int cxMapCloneShallow(CxMap *dst, const CxMap *src); +CX_EXTERN CX_NONNULL +int cxMapCloneShallow(CxMap *dst, const CxMap *src); /** * Clones entries of a map if their key is not present in another map. @@ -637,8 +631,8 @@ CX_EXPORT int cxMapCloneShallow(CxMap *dst, const CxMap *src); * @retval zero when the elements were successfully cloned * @retval non-zero when an allocation error occurred */ -cx_attr_nonnull -CX_EXPORT int cxMapDifferenceShallow(CxMap *dst, const CxMap *minuend, const CxMap *subtrahend); +CX_EXTERN CX_NONNULL +int cxMapDifferenceShallow(CxMap *dst, const CxMap *minuend, const CxMap *subtrahend); /** * Clones entries of a map if their key is not present in a list. @@ -658,9 +652,8 @@ CX_EXPORT int cxMapDifferenceShallow(CxMap *dst, const CxMap *minuend, const CxM * @retval non-zero when an allocation error occurred * @see cxMapListDifference() */ -cx_attr_nonnull -CX_EXPORT int cxMapListDifferenceShallow(CxMap *dst, const CxMap *src, const CxList *keys); - +CX_EXTERN CX_NONNULL +int cxMapListDifferenceShallow(CxMap *dst, const CxMap *src, const CxList *keys); /** * Clones entries of a map only if their key is present in another map. @@ -674,8 +667,8 @@ CX_EXPORT int cxMapListDifferenceShallow(CxMap *dst, const CxMap *src, const CxL * @retval zero when the elements were successfully cloned * @retval non-zero when an allocation error occurred */ -cx_attr_nonnull -CX_EXPORT int cxMapIntersectionShallow(CxMap *dst, const CxMap *src, const CxMap *other); +CX_EXTERN CX_NONNULL +int cxMapIntersectionShallow(CxMap *dst, const CxMap *src, const CxMap *other); /** * Clones entries of a map only if their key is present in a list. @@ -694,8 +687,8 @@ CX_EXPORT int cxMapIntersectionShallow(CxMap *dst, const CxMap *src, const CxMap * @retval zero when the elements were successfully cloned * @retval non-zero when an allocation error occurred */ -cx_attr_nonnull -CX_EXPORT int cxMapListIntersectionShallow(CxMap *dst, const CxMap *src, const CxList *keys); +CX_EXTERN CX_NONNULL +int cxMapListIntersectionShallow(CxMap *dst, const CxMap *src, const CxList *keys); /** * Clones entries into a map if their key does not exist yet. @@ -713,9 +706,8 @@ CX_EXPORT int cxMapListIntersectionShallow(CxMap *dst, const CxMap *src, const C * @retval zero when the elements were successfully cloned * @retval non-zero when an allocation error occurred */ -cx_attr_nonnull -CX_EXPORT int cxMapUnionShallow(CxMap *dst, const CxMap *src); - +CX_EXTERN CX_NONNULL +int cxMapUnionShallow(CxMap *dst, const CxMap *src); /** * Compares the entries of two maps. @@ -729,11 +721,7 @@ CX_EXPORT int cxMapUnionShallow(CxMap *dst, const CxMap *src); * @retval non-zero (unspecified whether positive or negative) when the size * of both maps is equal but a key or a value is different */ -cx_attr_nonnull -CX_EXPORT int cxMapCompare(const CxMap *map, const CxMap *other); - -#ifdef __cplusplus -} // extern "C" -#endif +CX_EXTERN CX_NONNULL +int cxMapCompare(const CxMap *map, const CxMap *other); #endif // UCX_MAP_H diff --git a/ucx/cx/mempool.h b/ucx/cx/mempool.h index 6530ea7..ea90ff7 100644 --- a/ucx/cx/mempool.h +++ b/ucx/cx/mempool.h @@ -39,10 +39,6 @@ #include "common.h" #include "allocator.h" -#ifdef __cplusplus -extern "C" { -#endif - /** A memory block in a simple memory pool. */ struct cx_mempool_memory_s { /** The destructor. */ @@ -156,7 +152,8 @@ typedef struct cx_mempool_s CxMempool; * * @param pool the memory pool to free */ -CX_EXPORT void cxMempoolFree(CxMempool *pool); +CX_EXTERN +void cxMempoolFree(CxMempool *pool); /** * Creates an array-based memory pool. @@ -168,8 +165,8 @@ CX_EXPORT void cxMempoolFree(CxMempool *pool); * @param type the type of memory pool * @return the created memory pool or @c NULL if allocation failed */ -cx_attr_nodiscard cx_attr_malloc cx_attr_dealloc(cxMempoolFree, 1) -CX_EXPORT CxMempool *cxMempoolCreate(size_t capacity, enum cx_mempool_type type); +CX_EXTERN CX_NODISCARD CX_MALLOC CX_DEALLOC(cxMempoolFree, 1) +CxMempool *cxMempoolCreate(size_t capacity, enum cx_mempool_type type); /** * Creates a basic array-based memory pool. @@ -207,8 +204,8 @@ CX_EXPORT CxMempool *cxMempoolCreate(size_t capacity, enum cx_mempool_type type) * @param pool the memory pool * @param fnc the destructor that shall be applied to all memory blocks */ -cx_attr_nonnull_arg(1) -CX_EXPORT void cxMempoolGlobalDestructor(CxMempool *pool, cx_destructor_func fnc); +CX_EXTERN CX_NONNULL_ARG(1) +void cxMempoolGlobalDestructor(CxMempool *pool, cx_destructor_func fnc); /** * Sets the global destructor for all memory blocks within the specified pool. @@ -217,8 +214,8 @@ CX_EXPORT void cxMempoolGlobalDestructor(CxMempool *pool, cx_destructor_func fnc * @param fnc the destructor that shall be applied to all memory blocks * @param data additional data for the destructor function */ -cx_attr_nonnull_arg(1) -CX_EXPORT void cxMempoolGlobalDestructor2(CxMempool *pool, cx_destructor_func2 fnc, void *data); +CX_EXTERN CX_NONNULL_ARG(1) +void cxMempoolGlobalDestructor2(CxMempool *pool, cx_destructor_func2 fnc, void *data); /** * Sets the destructor function for a specific allocated memory object. @@ -230,8 +227,8 @@ CX_EXPORT void cxMempoolGlobalDestructor2(CxMempool *pool, cx_destructor_func2 f * @param memory the object allocated in the pool * @param fnc the destructor function */ -cx_attr_nonnull -CX_EXPORT void cxMempoolSetDestructor(void *memory, cx_destructor_func fnc); +CX_EXTERN CX_NONNULL +void cxMempoolSetDestructor(void *memory, cx_destructor_func fnc); /** * Sets the destructor function for a specific allocated memory object. @@ -244,8 +241,8 @@ CX_EXPORT void cxMempoolSetDestructor(void *memory, cx_destructor_func fnc); * @param fnc the destructor function * @param data additional data for the destructor function */ -cx_attr_nonnull -CX_EXPORT void cxMempoolSetDestructor2(void *memory, cx_destructor_func2 fnc, void *data); +CX_EXTERN CX_NONNULL +void cxMempoolSetDestructor2(void *memory, cx_destructor_func2 fnc, void *data); /** * Removes the destructor function for a specific allocated memory object. @@ -255,8 +252,8 @@ CX_EXPORT void cxMempoolSetDestructor2(void *memory, cx_destructor_func2 fnc, vo * * @param memory the object allocated in the pool */ -cx_attr_nonnull -CX_EXPORT void cxMempoolRemoveDestructor(void *memory); +CX_EXTERN CX_NONNULL +void cxMempoolRemoveDestructor(void *memory); /** * Removes the destructor function for a specific allocated memory object. @@ -266,8 +263,8 @@ CX_EXPORT void cxMempoolRemoveDestructor(void *memory); * * @param memory the object allocated in the pool */ -cx_attr_nonnull -CX_EXPORT void cxMempoolRemoveDestructor2(void *memory); +CX_EXTERN CX_NONNULL +void cxMempoolRemoveDestructor2(void *memory); /** * Registers foreign memory with this pool. @@ -284,9 +281,8 @@ CX_EXPORT void cxMempoolRemoveDestructor2(void *memory); * @retval zero success * @retval non-zero failure */ -cx_attr_nonnull -CX_EXPORT int cxMempoolRegister(CxMempool *pool, void *memory, cx_destructor_func destr); - +CX_EXTERN CX_NONNULL +int cxMempoolRegister(CxMempool *pool, void *memory, cx_destructor_func destr); /** * Registers foreign memory with this pool. @@ -307,8 +303,8 @@ CX_EXPORT int cxMempoolRegister(CxMempool *pool, void *memory, cx_destructor_fun * @retval zero success * @retval non-zero failure */ -cx_attr_nonnull -CX_EXPORT int cxMempoolRegister2(CxMempool *pool, void *memory, cx_destructor_func2 destr, void *data); +CX_EXTERN CX_NONNULL +int cxMempoolRegister2(CxMempool *pool, void *memory, cx_destructor_func2 destr, void *data); /** * Transfers all the memory managed by one pool to another. @@ -325,8 +321,8 @@ CX_EXPORT int cxMempoolRegister2(CxMempool *pool, void *memory, cx_destructor_fu * @retval zero success * @retval non-zero allocation failure or incompatible pools */ -cx_attr_nonnull -CX_EXPORT int cxMempoolTransfer(CxMempool *source, CxMempool *dest); +CX_EXTERN CX_NONNULL +int cxMempoolTransfer(CxMempool *source, CxMempool *dest); /** * Transfers an object from one pool to another. @@ -342,11 +338,7 @@ CX_EXPORT int cxMempoolTransfer(CxMempool *source, CxMempool *dest); * @retval zero success * @retval non-zero failure, or the object was not found in the source pool, or the pools are incompatible */ -cx_attr_nonnull -CX_EXPORT int cxMempoolTransferObject(CxMempool *source, CxMempool *dest, const void *obj); - -#ifdef __cplusplus -} // extern "C" -#endif +CX_EXTERN CX_NONNULL +int cxMempoolTransferObject(CxMempool *source, CxMempool *dest, const void *obj); #endif // UCX_MEMPOOL_H diff --git a/ucx/cx/printf.h b/ucx/cx/printf.h index 7311ab4..9d4ea7f 100644 --- a/ucx/cx/printf.h +++ b/ucx/cx/printf.h @@ -45,14 +45,9 @@ * @param fmt_idx index of the format string parameter * @param arg_idx index of the first formatting argument */ -#define cx_attr_printf(fmt_idx, arg_idx) \ +#define CX_PRINTF_ARGS(fmt_idx, arg_idx) \ __attribute__((__format__(printf, fmt_idx, arg_idx))) -#ifdef __cplusplus -extern "C" { -#endif - - /** * The maximum string length that fits into stack memory. */ @@ -68,8 +63,8 @@ CX_EXPORT extern const unsigned cx_printf_sbo_size; * @param ... additional arguments * @return the total number of bytes written or an error code from stdlib printf implementation */ -cx_attr_nonnull_arg(1, 2, 3) cx_attr_printf(3, 4) cx_attr_cstr_arg(3) -CX_EXPORT int cx_fprintf(void *stream, cx_write_func wfc, const char *fmt, ...); +CX_EXTERN CX_NONNULL_ARG(1, 2, 3) CX_PRINTF_ARGS(3, 4) CX_CSTR_ARG(3) +int cx_fprintf(void *stream, cx_write_func wfc, const char *fmt, ...); /** * A @c vfprintf like function which writes the output to a stream by @@ -82,8 +77,8 @@ CX_EXPORT int cx_fprintf(void *stream, cx_write_func wfc, const char *fmt, ...); * @return the total number of bytes written or an error code from stdlib printf implementation * @see cx_fprintf() */ -cx_attr_nonnull cx_attr_cstr_arg(3) -CX_EXPORT int cx_vfprintf(void *stream, cx_write_func wfc, const char *fmt, va_list ap); +CX_EXTERN CX_NONNULL CX_CSTR_ARG(3) +int cx_vfprintf(void *stream, cx_write_func wfc, const char *fmt, va_list ap); /** * An @c asprintf like function which allocates space for a string @@ -99,8 +94,8 @@ CX_EXPORT int cx_vfprintf(void *stream, cx_write_func wfc, const char *fmt, va_l * @return the formatted string * @see cx_strfree_a() */ -cx_attr_nonnull_arg(1, 2) cx_attr_printf(2, 3) cx_attr_cstr_arg(2) -CX_EXPORT cxmutstr cx_asprintf_a(const CxAllocator *allocator, const char *fmt, ...); +CX_EXTERN CX_NONNULL_ARG(1, 2) CX_PRINTF_ARGS(2, 3) CX_CSTR_ARG(2) +cxmutstr cx_asprintf_a(const CxAllocator *allocator, const char *fmt, ...); /** * An @c asprintf like function which allocates space for a string @@ -131,8 +126,8 @@ CX_EXPORT cxmutstr cx_asprintf_a(const CxAllocator *allocator, const char *fmt, * @return the formatted string * @see cx_asprintf_a() */ -cx_attr_nonnull cx_attr_cstr_arg(2) -CX_EXPORT cxmutstr cx_vasprintf_a(const CxAllocator *allocator, const char *fmt, va_list ap); +CX_EXTERN CX_NONNULL CX_CSTR_ARG(2) +cxmutstr cx_vasprintf_a(const CxAllocator *allocator, const char *fmt, va_list ap); /** * A @c vasprintf like function which allocates space for a string @@ -193,8 +188,8 @@ CX_EXPORT cxmutstr cx_vasprintf_a(const CxAllocator *allocator, const char *fmt, * @param ... additional arguments * @return the length of the produced string or an error code from stdlib printf implementation */ -cx_attr_nonnull_arg(1, 2, 3, 4) cx_attr_printf(4, 5) cx_attr_cstr_arg(4) -CX_EXPORT int cx_sprintf_a(const CxAllocator *alloc, char **str, size_t *len, const char *fmt, ...); +CX_EXTERN CX_NONNULL_ARG(1, 2, 3, 4) CX_PRINTF_ARGS(4, 5) CX_CSTR_ARG(4) +int cx_sprintf_a(const CxAllocator *alloc, char **str, size_t *len, const char *fmt, ...); /** @@ -228,8 +223,8 @@ CX_EXPORT int cx_sprintf_a(const CxAllocator *alloc, char **str, size_t *len, co * @param ap argument list * @return the length of the produced string or an error code from stdlib printf implementation */ -cx_attr_nonnull cx_attr_cstr_arg(4) cx_attr_access_rw(2) cx_attr_access_rw(3) -CX_EXPORT int cx_vsprintf_a(const CxAllocator *alloc, char **str, size_t *len, const char *fmt, va_list ap); +CX_EXTERN CX_NONNULL CX_CSTR_ARG(4) CX_ACCESS_RW(2) CX_ACCESS_RW(3) +int cx_vsprintf_a(const CxAllocator *alloc, char **str, size_t *len, const char *fmt, va_list ap); /** @@ -275,9 +270,9 @@ CX_EXPORT int cx_vsprintf_a(const CxAllocator *alloc, char **str, size_t *len, c * @param ... additional arguments * @return the length of the produced string or an error code from stdlib printf implementation */ -cx_attr_nonnull_arg(1, 2, 4, 5) cx_attr_printf(5, 6) cx_attr_cstr_arg(5) -cx_attr_access_rw(2) cx_attr_access_rw(3) cx_attr_access_rw(4) -CX_EXPORT int cx_sprintf_sa(const CxAllocator *alloc, char *buf, size_t *len, char **str, const char *fmt, ...); +CX_EXTERN CX_NONNULL_ARG(1, 2, 4, 5) CX_PRINTF_ARGS(5, 6) CX_CSTR_ARG(5) +CX_ACCESS_RW(2) CX_ACCESS_RW(3) CX_ACCESS_RW(4) +int cx_sprintf_sa(const CxAllocator *alloc, char *buf, size_t *len, char **str, const char *fmt, ...); /** * An @c sprintf like function which allocates a new string when the buffer is not large enough. @@ -322,12 +317,7 @@ CX_EXPORT int cx_sprintf_sa(const CxAllocator *alloc, char *buf, size_t *len, ch * @param ap argument list * @return the length of the produced string or an error code from stdlib printf implementation */ -cx_attr_nonnull cx_attr_cstr_arg(5) -CX_EXPORT int cx_vsprintf_sa(const CxAllocator *alloc, char *buf, size_t *len, char **str, const char *fmt, va_list ap); - - -#ifdef __cplusplus -} // extern "C" -#endif +CX_EXTERN CX_NONNULL CX_CSTR_ARG(5) +int cx_vsprintf_sa(const CxAllocator *alloc, char *buf, size_t *len, char **str, const char *fmt, va_list ap); #endif //UCX_PRINTF_H diff --git a/ucx/cx/properties.h b/ucx/cx/properties.h index 782c651..e7bf840 100644 --- a/ucx/cx/properties.h +++ b/ucx/cx/properties.h @@ -41,10 +41,6 @@ #include "map.h" #include "buffer.h" -#ifdef __cplusplus -extern "C" { -#endif - /** * Configures the expected characters for the properties parser. */ @@ -184,8 +180,8 @@ typedef struct cx_properties_s CxProperties; * @param config the properties configuration * @see cxPropertiesInitDefault() */ -cx_attr_nonnull -CX_EXPORT void cxPropertiesInit(CxProperties *prop, CxPropertiesConfig config); +CX_EXTERN CX_NONNULL +void cxPropertiesInit(CxProperties *prop, CxPropertiesConfig config); /** * Destroys the properties interface. @@ -198,8 +194,8 @@ CX_EXPORT void cxPropertiesInit(CxProperties *prop, CxPropertiesConfig config); * * @param prop the properties interface */ -cx_attr_nonnull -CX_EXPORT void cxPropertiesDestroy(CxProperties *prop); +CX_EXTERN CX_NONNULL +void cxPropertiesDestroy(CxProperties *prop); /** * Destroys and re-initializes the properties interface. @@ -209,8 +205,8 @@ CX_EXPORT void cxPropertiesDestroy(CxProperties *prop); * * @param prop the properties interface */ -cx_attr_nonnull -CX_EXPORT void cxPropertiesReset(CxProperties *prop); +CX_EXTERN CX_NONNULL +void cxPropertiesReset(CxProperties *prop); /** * Initialize a properties parser with the default configuration. @@ -242,8 +238,8 @@ CX_EXPORT void cxPropertiesReset(CxProperties *prop); * @retval non-zero a memory allocation was necessary but failed * @see cxPropertiesFill() */ -cx_attr_nonnull cx_attr_access_r(2, 3) -CX_EXPORT int cxPropertiesFilln(CxProperties *prop, const char *buf, size_t len); +CX_EXTERN CX_NONNULL CX_ACCESS_R(2, 3) +int cxPropertiesFilln(CxProperties *prop, const char *buf, size_t len); /** * Internal function, do not use. @@ -253,8 +249,8 @@ CX_EXPORT int cxPropertiesFilln(CxProperties *prop, const char *buf, size_t len) * @retval zero success * @retval non-zero a memory allocation was necessary but failed */ -cx_attr_nonnull -CX_INLINE int cx_properties_fill(CxProperties *prop, cxstring str) { +CX_NONNULL CX_INLINE +int cx_properties_fill(CxProperties *prop, cxstring str) { return cxPropertiesFilln(prop, str.ptr, str.length); } @@ -287,8 +283,8 @@ CX_INLINE int cx_properties_fill(CxProperties *prop, cxstring str) { * @param buf a pointer to stack memory * @param capacity the capacity of the stack memory */ -cx_attr_nonnull -CX_EXPORT void cxPropertiesUseStack(CxProperties *prop, char *buf, size_t capacity); +CX_EXTERN CX_NONNULL +void cxPropertiesUseStack(CxProperties *prop, char *buf, size_t capacity); /** * Retrieves the next key/value-pair. @@ -320,8 +316,8 @@ CX_EXPORT void cxPropertiesUseStack(CxProperties *prop, char *buf, size_t capaci * @retval CX_PROPERTIES_INVALID_MISSING_DELIMITER the properties data contains a line without delimiter * @retval CX_PROPERTIES_BUFFER_ALLOC_FAILED an internal allocation was necessary but failed */ -cx_attr_nonnull cx_attr_nodiscard -CX_EXPORT CxPropertiesStatus cxPropertiesNext(CxProperties *prop, cxstring *key, cxstring *value); +CX_EXTERN CX_NONNULL CX_NODISCARD +CxPropertiesStatus cxPropertiesNext(CxProperties *prop, cxstring *key, cxstring *value); /** * The size of the stack memory that `cxPropertiesLoad()` will reserve with `cxPropertiesUseStack()`. @@ -342,8 +338,8 @@ CX_EXPORT extern const unsigned cx_properties_load_fill_size; * @param config the parser config * @return status code */ -cx_attr_nonnull_arg(3) -CX_EXPORT CxPropertiesStatus cx_properties_load(const CxAllocator *allocator, +CX_EXTERN CX_NONNULL_ARG(3) +CxPropertiesStatus cx_properties_load(const CxAllocator *allocator, cxstring filename, CxMap *target, CxPropertiesConfig config); /** @@ -401,9 +397,4 @@ CX_EXPORT CxPropertiesStatus cx_properties_load(const CxAllocator *allocator, #define cxPropertiesLoadDefault(allocator, filename, target) \ cx_properties_load(allocator, cx_strcast(filename), target, cx_properties_config_default) - -#ifdef __cplusplus -} // extern "C" -#endif - #endif // UCX_PROPERTIES_H diff --git a/ucx/cx/streams.h b/ucx/cx/streams.h index 298ca3a..c778f7e 100644 --- a/ucx/cx/streams.h +++ b/ucx/cx/streams.h @@ -41,10 +41,6 @@ #include "common.h" -#ifdef __cplusplus -extern "C" { -#endif - /** * Reads data from a stream and writes it to another stream. * @@ -61,9 +57,9 @@ extern "C" { * iterations. * @return the total number of bytes copied */ -cx_attr_nonnull_arg(1, 2, 3, 4) -cx_attr_access_r(1) cx_attr_access_w(2) cx_attr_access_w(5) -CX_EXPORT size_t cx_stream_bncopy(void *src, void *dest, +CX_EXTERN CX_NONNULL_ARG(1, 2, 3, 4) +CX_ACCESS_R(1) CX_ACCESS_W(2) CX_ACCESS_W(5) +size_t cx_stream_bncopy(void *src, void *dest, cx_read_func rfnc, cx_write_func wfnc, char *buf, size_t bufsize, size_t n); @@ -95,8 +91,8 @@ CX_EXPORT size_t cx_stream_bncopy(void *src, void *dest, * @param n the maximum number of bytes that shall be copied. * @return total number of bytes copied */ -cx_attr_nonnull cx_attr_access_r(1) cx_attr_access_w(2) -CX_EXPORT size_t cx_stream_ncopy(void *src, void *dest, +CX_EXTERN CX_NONNULL CX_ACCESS_R(1) CX_ACCESS_W(2) +size_t cx_stream_ncopy(void *src, void *dest, cx_read_func rfnc, cx_write_func wfnc, size_t n); /** @@ -113,8 +109,4 @@ CX_EXPORT size_t cx_stream_ncopy(void *src, void *dest, #define cx_stream_copy(src, dest, rfnc, wfnc) \ cx_stream_ncopy(src, dest, rfnc, wfnc, SIZE_MAX) -#ifdef __cplusplus -} -#endif - #endif // UCX_STREAMS_H diff --git a/ucx/cx/string.h b/ucx/cx/string.h index 5cc47ac..81ad00d 100644 --- a/ucx/cx/string.h +++ b/ucx/cx/string.h @@ -41,6 +41,9 @@ #include +/** Convenience macro for creating a null string */ +#define CX_NULLSTR cx_mutstr(NULL) + /** Expands a UCX string as printf arguments. */ #define CX_SFMT(s) (int) (s).length, (s).ptr @@ -156,7 +159,7 @@ typedef struct cx_strtok_ctx_s CxStrtokCtx; * * @see cx_mutstrn() */ -cx_attr_nodiscard cx_attr_cstr_arg(1) +CX_NODISCARD CX_CSTR_ARG(1) CX_INLINE cxmutstr cx_mutstr(char *cstring) { cxmutstr str; str.ptr = cstring; @@ -180,7 +183,7 @@ CX_INLINE cxmutstr cx_mutstr(char *cstring) { * * @see cx_mutstr() */ -cx_attr_nodiscard cx_attr_access_rw(1, 2) +CX_NODISCARD CX_ACCESS_RW(1, 2) CX_INLINE cxmutstr cx_mutstrn(char *cstring, size_t length) { cxmutstr str; str.ptr = cstring; @@ -205,7 +208,7 @@ CX_INLINE cxmutstr cx_mutstrn(char *cstring, size_t length) { * * @see cx_strn() */ -cx_attr_nodiscard cx_attr_cstr_arg(1) +CX_NODISCARD CX_CSTR_ARG(1) CX_INLINE cxstring cx_str(const char *cstring) { cxstring str; str.ptr = cstring; @@ -230,7 +233,7 @@ CX_INLINE cxstring cx_str(const char *cstring) { * * @see cx_str() */ -cx_attr_nodiscard cx_attr_access_r(1, 2) +CX_NODISCARD CX_ACCESS_R(1, 2) CX_INLINE cxstring cx_strn(const char *cstring, size_t length) { cxstring str; str.ptr = cstring; @@ -239,42 +242,60 @@ CX_INLINE cxstring cx_strn(const char *cstring, size_t length) { } #ifdef __cplusplus -cx_attr_nodiscard -CX_CPPDECL cxstring cx_strcast(cxmutstr str) { - return cx_strn(str.ptr, str.length); +CX_NODISCARD +CX_CPPDECL cxmutstr cx_strcast_m(cxmutstr str) { + return str; } -cx_attr_nodiscard -CX_CPPDECL cxstring cx_strcast(cxstring str) { +CX_NODISCARD +CX_CPPDECL cxstring cx_strcast_m(cxstring str) { return str; } -cx_attr_nodiscard -CX_CPPDECL cxstring cx_strcast(const char *str) { +CX_NODISCARD +CX_CPPDECL cxmutstr cx_strcast_m(char *str) { + return cx_mutstr(str); +} +CX_NODISCARD +CX_CPPDECL cxmutstr cx_strcast_m(unsigned char *str) { + return cx_mutstr(reinterpret_cast(str)); +} +CX_NODISCARD +CX_CPPDECL cxstring cx_strcast_m(const char *str) { return cx_str(str); } -cx_attr_nodiscard -CX_CPPDECL cxstring cx_strcast(const unsigned char *str) { +CX_NODISCARD +CX_CPPDECL cxstring cx_strcast_m(const unsigned char *str) { return cx_str(reinterpret_cast(str)); } -extern "C" { +CX_NODISCARD +CX_CPPDECL cxstring cx_strcast_(cxmutstr str) { + return cx_strn(str.ptr, str.length); +} +CX_NODISCARD +CX_CPPDECL cxstring cx_strcast_(cxstring str) { + return str; +} +#define cx_strcast(s) cx_strcast_(cx_strcast_m(s)) #else /** * Internal function, do not use. * @param str * @return + * @see cx_strcast_m() * @see cx_strcast() */ -cx_attr_nodiscard -CX_INLINE cxstring cx_strcast_m(cxmutstr str) { - return (cxstring) {str.ptr, str.length}; +CX_NODISCARD +CX_INLINE cxmutstr cx_strcast_cxms(cxmutstr str) { + return str; } /** * Internal function, do not use. * @param str * @return + * @see cx_strcast_m() * @see cx_strcast() */ -cx_attr_nodiscard -CX_INLINE cxstring cx_strcast_c(cxstring str) { +CX_NODISCARD +CX_INLINE cxstring cx_strcast_cxs(cxstring str) { return str; } @@ -282,10 +303,35 @@ CX_INLINE cxstring cx_strcast_c(cxstring str) { * Internal function, do not use. * @param str * @return + * @see cx_strcast_m() + * @see cx_strcast() + */ +CX_NODISCARD +CX_INLINE cxmutstr cx_strcast_uc(unsigned char *str) { + return cx_mutstr((char*)str); +} + +/** + * Internal function, do not use. + * @param str + * @return + * @see cx_strcast_m() + * @see cx_strcast() + */ +CX_NODISCARD +CX_INLINE cxmutstr cx_strcast_c(char *str) { + return cx_mutstr(str); +} + +/** + * Internal function, do not use. + * @param str + * @return + * @see cx_strcast_m() * @see cx_strcast() */ -cx_attr_nodiscard -CX_INLINE cxstring cx_strcast_u(const unsigned char *str) { +CX_NODISCARD +CX_INLINE cxstring cx_strcast_ucc(const unsigned char *str) { return cx_str((const char*)str); } @@ -293,10 +339,11 @@ CX_INLINE cxstring cx_strcast_u(const unsigned char *str) { * Internal function, do not use. * @param str * @return + * @see cx_strcast_m() * @see cx_strcast() */ -cx_attr_nodiscard -CX_INLINE cxstring cx_strcast_z(const char *str) { +CX_NODISCARD +CX_INLINE cxstring cx_strcast_cc(const char *str) { return cx_str(str); } @@ -304,17 +351,61 @@ CX_INLINE cxstring cx_strcast_z(const char *str) { * Wraps any string into an UCX string. * * @param str (any supported string type) the string to cast - * @return (@c cxstring) the string wrapped as UCX string - */ -#define cx_strcast(str) _Generic((str), \ - cxmutstr: cx_strcast_m, \ - cxstring: cx_strcast_c, \ - const unsigned char*: cx_strcast_u, \ - unsigned char *: cx_strcast_u, \ - const char*: cx_strcast_z, \ - char *: cx_strcast_z) (str) + * @return (@c cxstring) or (@c cxmutstr) the string wrapped as UCX string + */ +#define cx_strcast_m(str) _Generic((str), \ + cxstring: cx_strcast_cxs, \ + cxmutstr: cx_strcast_cxms, \ + const unsigned char*: cx_strcast_ucc, \ + unsigned char *: cx_strcast_uc, \ + const char*: cx_strcast_cc, \ + char *: cx_strcast_c) (str) + +/** + * Internal function, do not use. + * @param str + * @return + */ +CX_INLINE cxstring cx_strcast_1(cxmutstr str) { + return (cxstring){str.ptr, str.length}; +} + +/** + * Internal function, do not use. + * @param str + * @return + */ +CX_INLINE cxstring cx_strcast_2(cxstring str) { + return str; +} + +/** internal conversion macro */ +#define cx_strcast_(str) _Generic((str), \ + cxmutstr: cx_strcast_1, \ + cxstring: cx_strcast_2)(str) + +/** + * Converts any string to a cxstring. + * + * @param str (any supported string type) the string to cast + * @return he string converted to a (@c cxstring) + */ +#define cx_strcast(str) cx_strcast_(cx_strcast_m(str)) #endif +/** + * Casts away constness and converts a cxstring to a cxmutstr. + * For internal use only! + * @param str + * @return + */ +CX_INLINE cxmutstr cx_mutstrcast(cxstring str) { + cxmutstr s; + s.ptr = (char*)str.ptr; + s.length = str.length; + return s; +} + /** * Passes the pointer in this string to the cxDefaultAllocator's @c free() function. * @@ -327,7 +418,8 @@ CX_INLINE cxstring cx_strcast_z(const char *str) { * * @param str the string to free */ -CX_EXPORT void cx_strfree(cxmutstr *str); +CX_EXTERN +void cx_strfree(cxmutstr *str); /** * Passes the pointer in this string to the allocator's free function. @@ -342,8 +434,8 @@ CX_EXPORT void cx_strfree(cxmutstr *str); * @param alloc the allocator * @param str the string to free */ -cx_attr_nonnull_arg(1) -CX_EXPORT void cx_strfree_a(const CxAllocator *alloc, cxmutstr *str); +CX_EXTERN CX_NONNULL_ARG(1) +void cx_strfree_a(const CxAllocator *alloc, cxmutstr *str); /** * Copies a string. @@ -358,8 +450,8 @@ CX_EXPORT void cx_strfree_a(const CxAllocator *alloc, cxmutstr *str); * @retval non-zero if re-allocation failed * @see cx_strcpy_a() */ -cx_attr_nonnull_arg(1) -CX_EXPORT int cx_strcpy_a_(const CxAllocator *alloc, cxmutstr *dest, cxstring src); +CX_EXTERN CX_NONNULL_ARG(1) +int cx_strcpy_a_(const CxAllocator *alloc, cxmutstr *dest, cxstring src); /** * Copies a string. @@ -404,8 +496,8 @@ CX_EXPORT int cx_strcpy_a_(const CxAllocator *alloc, cxmutstr *dest, cxstring sr * @param ... all strings * @return the accumulated length of all strings */ -cx_attr_nodiscard -CX_EXPORT size_t cx_strlen(size_t count, ...); +CX_EXTERN CX_NODISCARD +size_t cx_strlen(size_t count, ...); /** * Concatenates strings. @@ -416,12 +508,10 @@ CX_EXPORT size_t cx_strlen(size_t count, ...); * If @p str already contains a string, the memory will be reallocated and * the other strings are appended. Otherwise, new memory is allocated. * - * If memory allocation fails, the pointer in the returned string will - * be @c NULL. Depending on the allocator, @c errno might be set. - * * @note It is guaranteed that there is only one allocation for the * resulting string. * It is also guaranteed that the returned string is zero-terminated. + * If allocation fails, the @c ptr in the returned string will be @c NULL. * * @param alloc the allocator to use * @param str the string the other strings shall be concatenated to @@ -429,132 +519,111 @@ CX_EXPORT size_t cx_strlen(size_t count, ...); * @param ... all other UCX strings * @return the concatenated string */ -cx_attr_nodiscard cx_attr_nonnull -CX_EXPORT cxmutstr cx_strcat_ma(const CxAllocator *alloc, +CX_EXTERN CX_NONNULL +cxmutstr cx_strcat_a(const CxAllocator *alloc, cxmutstr str, size_t count, ...); -/** - * Concatenates strings and returns a new string. - * - * The resulting string will be allocated by the specified allocator. - * So developers @em must pass the return value to cx_strfree_a() eventually. - * -* If memory allocation fails, the pointer in the returned string will - * be @c NULL. Depending on the allocator, @c errno might be set. - * - * @note It is guaranteed that there is only one allocation for the - * resulting string. - * It is also guaranteed that the returned string is zero-terminated. - * - * @param alloc (@c CxAllocator*) the allocator to use - * @param count (@c size_t) the number of the other following strings to concatenate - * @param ... all other UCX strings - * @return (@c cxmutstr) the concatenated string - */ -#define cx_strcat_a(alloc, count, ...) \ - cx_strcat_ma(alloc, cx_mutstrn(NULL, 0), count, __VA_ARGS__) - /** * Concatenates strings and returns a new string. * * The resulting string will be allocated by the cxDefaultAllocator. * So developers @em must pass the return value to cx_strfree() eventually. * -* If memory allocation fails, the pointer in the returned string will - * be @c NULL and @c errno might be set. - * * @note It is guaranteed that there is only one allocation for the * resulting string. * It is also guaranteed that the returned string is zero-terminated. + * If allocation fails, the @c ptr in the returned string will be @c NULL. * + * @param str (@c cxmutstr*) the string the other strings shall be concatenated to * @param count (@c size_t) the number of the other following strings to concatenate * @param ... all other UCX strings - * @return (@c cxmutstr) the concatenated string - */ -#define cx_strcat(count, ...) \ - cx_strcat_ma(cxDefaultAllocator, cx_mutstrn(NULL, 0), count, __VA_ARGS__) - -/** - * Concatenates strings. - * - * The resulting string will be allocated by the cxDefaultAllocator. - * So developers @em must pass the return value to cx_strfree() eventually. - * - * If @p str already contains a string, the memory will be reallocated and - * the other strings are appended. Otherwise, new memory is allocated. - * -* If memory allocation fails, the pointer in the returned string will - * be @c NULL and @c errno might be set. - * - * @note It is guaranteed that there is only one allocation for the - * resulting string. - * It is also guaranteed that the returned string is zero-terminated. - * - * @param str (@c cxmutstr) the string the other strings shall be concatenated to - * @param count (@c size_t) the number of the other following strings to concatenate - * @param ... all other strings - * @return (@c cxmutstr) the concatenated string + * @return the concatenated string */ -#define cx_strcat_m(str, count, ...) \ - cx_strcat_ma(cxDefaultAllocator, str, count, __VA_ARGS__) +#define cx_strcat(str, count, ...) \ + cx_strcat_a(cxDefaultAllocator, str, count, __VA_ARGS__) /** - * Returns a substring starting at the specified location. + * Returns a substring. * - * @attention the new string references the same memory area as the - * input string and is usually @em not zero-terminated. - * Use cx_strdup() to get a copy. + * Internal function - do not use. * * @param string input string * @param start start location of the substring + * @param length the maximum length of the returned string * @return a substring of @p string starting at @p start - * * @see cx_strsubsl() - * @see cx_strsubs_m() - * @see cx_strsubsl_m() */ -cx_attr_nodiscard -CX_EXPORT cxstring cx_strsubs(cxstring string, size_t start); +CX_EXTERN CX_NODISCARD +cxstring cx_strsubsl_(cxstring string, size_t start, size_t length); /** - * Returns a substring starting at the specified location. - * - * The returned string will be limited to @p length bytes or the number - * of bytes available in @p string, whichever is smaller. + * Returns a substring. * - * @attention the new string references the same memory area as the - * input string and is usually @em not zero-terminated. - * Use cx_strdup() to get a copy. + * Internal function - do not use. * * @param string input string * @param start start location of the substring - * @param length the maximum length of the returned string * @return a substring of @p string starting at @p start - * * @see cx_strsubs() - * @see cx_strsubs_m() - * @see cx_strsubsl_m() */ -cx_attr_nodiscard -CX_EXPORT cxstring cx_strsubsl(cxstring string, size_t start, size_t length); +CX_EXTERN CX_NODISCARD +cxstring cx_strsubs_(cxstring string, size_t start); + +/** + * Internal conversion function - do not use. + * @param string + * @param start + * @return + */ +CX_INLINE +cxmutstr cx_strsubs_m_(cxmutstr string, size_t start) { + return cx_mutstrcast(cx_strsubs_(cx_strcast(string), start)); +} +/** + * Internal conversion function - do not use. + * @param string + * @param start + * @param length + * @return + */ +CX_INLINE +cxmutstr cx_strsubsl_m_(cxmutstr string, size_t start, size_t length) { + return cx_mutstrcast(cx_strsubsl_(cx_strcast(string), start, length)); +} + +#ifdef __cplusplus +CX_CPPDECL cxstring cx_strsubs_cpp_(cxstring string, size_t start) { + return cx_strsubs_(string, start); +} +CX_CPPDECL cxstring cx_strsubsl_cpp_(cxstring string, size_t start, size_t length) { + return cx_strsubsl_(string, start, length); +} +CX_CPPDECL cxmutstr cx_strsubs_cpp_(cxmutstr string, size_t start) { + return cx_strsubs_m_(string, start); +} +CX_CPPDECL cxmutstr cx_strsubsl_cpp_(cxmutstr string, size_t start, size_t length) { + return cx_strsubsl_m_(string, start, length); +} +#define cx_strsubs(string, start) cx_strsubs_cpp_(cx_strcast_m(string), start) +#define cx_strsubsl(string, start, length) cx_strsubsl_cpp_(cx_strcast_m(string), start, length) +#else /** * Returns a substring starting at the specified location. * * @attention the new string references the same memory area as the - * input string and is usually @em not zero-terminated. + * input string and is @em not zero-terminated. * Use cx_strdup() to get a copy. * * @param string input string - * @param start start location of the substring - * @return a substring of @p string starting at @p start + * @param start (@c size_t) start location of the substring + * @return (@c cxstring or @c cxmutstr) a substring of @p string starting at @p start * - * @see cx_strsubsl_m() - * @see cx_strsubs() * @see cx_strsubsl() */ -cx_attr_nodiscard -CX_EXPORT cxmutstr cx_strsubs_m(cxmutstr string, size_t start); +#define cx_strsubs(string, start) _Generic(cx_strcast_m(string), \ + cxstring: cx_strsubs_, \ + cxmutstr: cx_strsubs_m_)(cx_strcast_m(string), start) /** * Returns a substring starting at the specified location. @@ -571,57 +640,123 @@ CX_EXPORT cxmutstr cx_strsubs_m(cxmutstr string, size_t start); * @param length the maximum length of the returned string * @return a substring of @p string starting at @p start * - * @see cx_strsubs_m() * @see cx_strsubs() - * @see cx_strsubsl() */ -cx_attr_nodiscard -CX_EXPORT cxmutstr cx_strsubsl_m(cxmutstr string, size_t start, size_t length); +#define cx_strsubsl(string, start, length) _Generic(cx_strcast_m(string), \ + cxstring: cx_strsubsl_, \ + cxmutstr: cx_strsubsl_m_)(cx_strcast_m(string), start, length) +#endif /** - * Returns a substring starting at the location of the first occurrence of the - * specified character. - * - * If the string does not contain the character, an empty string is returned. + * Returns the character at the specified index offset. * - * @param string the string where to locate the character - * @param chr the character to locate - * @return a substring starting at the first location of @p chr + * Internal function - do not use. * - * @see cx_strchr_m() - */ -cx_attr_nodiscard -CX_EXPORT cxstring cx_strchr(cxstring string, int chr); + * @param str the string + * @param index the index offset + * @return the character at the index + * @see cx_strat() + */ +CX_INLINE +char cx_strat_(cxstring str, off_t index) { + size_t i; + if (index >= 0) { + i = index; + } else { + i = (size_t) (str.length + index); + } + if (i >= str.length) { + return '\0'; + } + return str.ptr[i]; +} /** - * Returns a substring starting at the location of the first occurrence of the - * specified character. + * Returns the character at the specified index offset. * - * If the string does not contain the character, an empty string is returned. + * When the @p index is negative, the character is counted from the end of the + * string where -1 denotes the last character in the string. * - * @param string the string where to locate the character - * @param chr the character to locate - * @return a substring starting at the first location of @p chr + * When the @p index is out of bounds, the function returns zero. * + * @param str the string + * @param index the index offset + * @return the character at the index + * @see cx_strat() + */ +#define cx_strat(str, index) cx_strat_(cx_strcast(str), index) + +/** + * Searches for a character in a string. + * Internal function - do not use. + * @param string + * @param chr + * @return * @see cx_strchr() */ -cx_attr_nodiscard -CX_EXPORT cxmutstr cx_strchr_m(cxmutstr string, int chr); +CX_EXTERN CX_NODISCARD +cxstring cx_strchr_(cxstring string, int chr); /** - * Returns a substring starting at the location of the last occurrence of the + * Searches for a character in a string. + * Internal function - do not use. + * @param string + * @param chr + * @return + * @see cx_strrchr() + */ +CX_EXTERN CX_NODISCARD +cxstring cx_strrchr_(cxstring string, int chr); + +#ifdef __cplusplus +CX_CPPDECL cxstring cx_strchr_cpp_(cxstring string, int chr) { + return cx_strchr_(string, chr); +} +CX_CPPDECL cxmutstr cx_strchr_cpp_(cxmutstr string, int chr) { + return cx_mutstrcast(cx_strchr_(cx_strcast(string), chr)); +} +#define cx_strchr(s, chr) cx_strchr_cpp_(cx_strcast_m(s), chr) +CX_CPPDECL cxstring cx_strrchr_cpp_(cxstring string, int chr) { + return cx_strrchr_(string, chr); +} +CX_CPPDECL cxmutstr cx_strrchr_cpp_(cxmutstr string, int chr) { + return cx_mutstrcast(cx_strrchr_(cx_strcast(string), chr)); +} +#define cx_strrchr(s, chr) cx_strrchr_cpp_(cx_strcast_m(s), chr) +#else +/** + * Internal conversion function - do not use. + * @param string + * @param chr + * @return + */ +CX_INLINE cxmutstr cx_strchr_m_(cxmutstr string, int chr) { + return cx_mutstrcast(cx_strchr_(cx_strcast(string), chr)); +} +/** + * Internal conversion function - do not use. + * @param string + * @param chr + * @return + */ +CX_INLINE cxmutstr cx_strrchr_m_(cxmutstr string, int chr) { + return cx_mutstrcast(cx_strrchr_(cx_strcast(string), chr)); +} + +/** + * Returns a substring starting at the location of the first occurrence of the * specified character. * * If the string does not contain the character, an empty string is returned. * * @param string the string where to locate the character - * @param chr the character to locate - * @return a substring starting at the last location of @p chr - * - * @see cx_strrchr_m() + * @param chr (@c int) the character to locate + * @return (@c cxstring or @c cxmutstr) a substring starting at the first + * location of @p chr */ -cx_attr_nodiscard -CX_EXPORT cxstring cx_strrchr(cxstring string, int chr); +#define cx_strchr(string, chr) _Generic(cx_strcast_m(string), \ + cxstring: cx_strchr_, \ + cxmutstr: cx_strchr_m_)(cx_strcast_m(string), chr) /** * Returns a substring starting at the location of the last occurrence of the @@ -630,13 +765,14 @@ CX_EXPORT cxstring cx_strrchr(cxstring string, int chr); * If the string does not contain the character, an empty string is returned. * * @param string the string where to locate the character - * @param chr the character to locate - * @return a substring starting at the last location of @p chr - * - * @see cx_strrchr() + * @param chr (@c int) the character to locate + * @return (@c cxstring or @c cxmutstr) a substring starting at the last + * location of @p chr */ -cx_attr_nodiscard -CX_EXPORT cxmutstr cx_strrchr_m(cxmutstr string, int chr); +#define cx_strrchr(string, chr) _Generic(cx_strcast_m(string), \ + cxstring: cx_strrchr_, \ + cxmutstr: cx_strrchr_m_)(cx_strcast_m(string), chr) +#endif /** * Searches for a specific substring. @@ -649,39 +785,27 @@ CX_EXPORT cxmutstr cx_strrchr_m(cxmutstr string, int chr); * or an empty string, if the sequence is not contained * @see cx_strstr() */ -cx_attr_nodiscard -CX_EXPORT cxstring cx_strstr_(cxstring haystack, cxstring needle); - -/** - * Returns a substring starting at the location of the first occurrence of the - * specified string. - * - * If @p haystack does not contain @p needle, an empty string is returned. - * - * If @p needle is an empty string, the complete @p haystack is - * returned. - * - * @param haystack (@c cxstring) the string to be scanned - * @param needle string containing the sequence of characters to match - * @return (@c cxstring) a substring starting at the first occurrence of - * @p needle, or an empty string, if the sequence is not contained - * @see cx_strstr_m() - */ -#define cx_strstr(haystack, needle) cx_strstr_(haystack, cx_strcast(needle)) +CX_EXTERN CX_NODISCARD +cxstring cx_strstr_(cxstring haystack, cxstring needle); +#ifdef __cplusplus +CX_CPPDECL cxstring cx_strstr_cpp_(cxstring haystack, cxstring needle) { + return cx_strstr_(haystack, needle); +} +CX_CPPDECL cxmutstr cx_strstr_cpp_(cxmutstr haystack, cxstring needle) { + return cx_mutstrcast(cx_strstr_(cx_strcast(haystack), needle)); +} +#define cx_strstr(h,n) cx_strstr_cpp_(cx_strcast_m(h), cx_strcast(n)) +#else /** - * Searches for a specific substring. - * - * Internal function - do not use. - * - * @param haystack the string to be scanned - * @param needle string containing the sequence of characters to match - * @return a substring starting at the first occurrence of @p needle, - * or an empty string, if the sequence is not contained - * @see cx_strstr_m() + * Internal conversion - do not use. + * @param haystack + * @param needle + * @return */ -cx_attr_nodiscard -CX_EXPORT cxmutstr cx_strstr_m_(cxmutstr haystack, cxstring needle); +CX_INLINE cxmutstr cx_strstr_m_(cxmutstr haystack, cxstring needle) { + return cx_mutstrcast(cx_strstr_(cx_strcast(haystack), needle)); +} /** * Returns a substring starting at the location of the first occurrence of the @@ -692,13 +816,15 @@ CX_EXPORT cxmutstr cx_strstr_m_(cxmutstr haystack, cxstring needle); * If @p needle is an empty string, the complete @p haystack is * returned. * - * @param haystack (@c cxmutstr) the string to be scanned + * @param haystack the string to be scanned * @param needle string containing the sequence of characters to match - * @return (@c cxmutstr) a substring starting at the first occurrence of - * @p needle, or an empty string, if the sequence is not contained - * @see cx_strstr() + * @return (@c cxstring or @c cxmutstr) a substring starting at the first + * occurrence of @p needle, or an empty string, if the sequence is not contained */ -#define cx_strstr_m(haystack, needle) cx_strstr_m_(haystack, cx_strcast(needle)) +#define cx_strstr(haystack, needle) _Generic(cx_strcast_m(haystack), \ + cxstring: cx_strstr_,\ + cxmutstr: cx_strstr_m_)(cx_strcast_m(haystack), cx_strcast(needle)) +#endif /** * Splits a given string using a delimiter string. @@ -712,8 +838,8 @@ CX_EXPORT cxmutstr cx_strstr_m_(cxmutstr haystack, cxstring needle); * @return the actual number of split items * @see cx_strsplit() */ -cx_attr_nodiscard cx_attr_nonnull cx_attr_access_w(4, 3) -CX_EXPORT size_t cx_strsplit_(cxstring string, cxstring delim, +CX_EXTERN CX_NODISCARD CX_NONNULL CX_ACCESS_W(4, 3) +size_t cx_strsplit_(cxstring string, cxstring delim, size_t limit, cxstring *output); /** @@ -729,8 +855,8 @@ CX_EXPORT size_t cx_strsplit_(cxstring string, cxstring delim, * @return the actual number of split items * @see cx_strsplit_a() */ -cx_attr_nodiscard cx_attr_nonnull cx_attr_access_w(5) -CX_EXPORT size_t cx_strsplit_a_(const CxAllocator *allocator, +CX_EXTERN CX_NODISCARD CX_NONNULL CX_ACCESS_W(5) +size_t cx_strsplit_a_(const CxAllocator *allocator, cxstring string, cxstring delim, size_t limit, cxstring **output); @@ -747,8 +873,8 @@ CX_EXPORT size_t cx_strsplit_a_(const CxAllocator *allocator, * @return the actual number of split items * @see cx_strsplit_m() */ -cx_attr_nodiscard cx_attr_nonnull cx_attr_access_w(4, 3) -CX_EXPORT size_t cx_strsplit_m_(cxmutstr string, cxstring delim, +CX_EXTERN CX_NODISCARD CX_NONNULL CX_ACCESS_W(4, 3) +size_t cx_strsplit_m_(cxmutstr string, cxstring delim, size_t limit, cxmutstr *output); /** @@ -764,25 +890,51 @@ CX_EXPORT size_t cx_strsplit_m_(cxmutstr string, cxstring delim, * @return the actual number of split items * @see cx_strsplit_ma() */ -cx_attr_nodiscard cx_attr_nonnull cx_attr_access_w(5) -CX_EXPORT size_t cx_strsplit_ma_(const CxAllocator *allocator, +CX_EXTERN CX_NODISCARD CX_NONNULL CX_ACCESS_W(5) +size_t cx_strsplit_ma_(const CxAllocator *allocator, cxmutstr string, cxstring delim, size_t limit, cxmutstr **output); +#ifdef __cplusplus +CX_CPPDECL size_t cx_strsplit_cpp_(cxstring string, cxstring delim, + size_t limit, cxstring *output) { + return cx_strsplit_(string, delim, limit, output); +} +CX_CPPDECL size_t cx_strsplit_cpp_(cxmutstr string, cxstring delim, + size_t limit, cxmutstr *output) { + return cx_strsplit_m_(string, delim, limit, output); +} +CX_CPPDECL size_t cx_strsplit_a_cpp_(const CxAllocator *allocator, + cxstring string, cxstring delim, size_t limit, cxstring **output) { + return cx_strsplit_a_(allocator, string, delim, limit, output); +} +CX_CPPDECL size_t cx_strsplit_a_cpp_(const CxAllocator *allocator, + cxmutstr string, cxstring delim, size_t limit, cxmutstr **output) { + return cx_strsplit_ma_(allocator, string, delim, limit, output); +} +#define cx_strsplit(string, delim, limit, output) \ + cx_strsplit_cpp_(cx_strcast_m(string), cx_strcast(delim), limit, output) +#define cx_strsplit_a(allocator, string, delim, limit, output) \ + cx_strsplit_a_cpp_(allocator, cx_strcast_m(string), cx_strcast(delim), limit, output) +#else /** * Splits a given string using a delimiter string. * * @note The resulting array contains strings that point to the source * @p string. Use cx_strdup() to get copies. * - * @param string (@c cxstring) the string to split + * @param string the string to split * @param delim the delimiter * @param limit (@c size_t) the maximum number of split items - * @param output (@c cxstring*) a preallocated array of at least @p limit length + * @param output (@c cxstring* or @c cxmutstr*) a preallocated array of at + * least @p limit length * @return the actual number of split items */ #define cx_strsplit(string, delim, limit, output) \ - cx_strsplit_(string, cx_strcast(delim), limit, output) + _Generic(cx_strcast_m(string), \ + cxstring: cx_strsplit_, \ + cxmutstr: cx_strsplit_m_)\ + (cx_strcast_m(string), cx_strcast(delim), limit, output) /** * Splits a given string using a delimiter string. @@ -796,53 +948,19 @@ CX_EXPORT size_t cx_strsplit_ma_(const CxAllocator *allocator, * @p output and the number returned will be zero. * * @param allocator (@c CxAllocator*) the allocator to use for allocating the resulting array - * @param string (@c cxstring) the string to split + * @param string the string to split * @param delim the delimiter * @param limit (@c size_t) the maximum number of split items - * @param output (@c cxstring**) a pointer where the address of the allocated - * array shall be written to + * @param output (@c cxstring** or @c cxmutstr**) a pointer where the address + * of the allocated array shall be written to * @return the actual number of split items */ #define cx_strsplit_a(allocator, string, delim, limit, output) \ - cx_strsplit_a_(allocator, string, cx_strcast(delim), limit, output) - - -/** - * Splits a given string using a delimiter string. - * - * @note The resulting array contains strings that point to the source - * @p string. Use cx_strdup() to get copies. - * - * @param string (@c cxmutstr) the string to split - * @param delim the delimiter - * @param limit (@c size_t) the maximum number of split items - * @param output (@c cxmutstr*) a preallocated array of at least @p limit length - * @return the actual number of split items - */ -#define cx_strsplit_m(string, delim, limit, output) \ - cx_strsplit_m_(string, cx_strcast(delim), limit, output) - -/** - * Splits a given string using a delimiter string. - * - * The array pointed to by @p output will be allocated by @p allocator. - * - * @note The resulting array contains strings that point to the source - * @p string. Use cx_strdup() to get copies. - * - * @attention If allocation fails, the @c NULL pointer will be written to - * @p output and the number returned will be zero. - * - * @param allocator (@c CxAllocator*) the allocator to use for allocating the resulting array - * @param string (@c cxmutstr) the string to split - * @param delim the delimiter - * @param limit (@c size_t) the maximum number of split items - * @param output (@c cxmutstr**) a pointer where the address of the allocated - * array shall be written to - * @return the actual number of split items - */ -#define cx_strsplit_ma(allocator, string, delim, limit, output) \ - cx_strsplit_ma_(allocator, string, cx_strcast(delim), limit, output) + _Generic(cx_strcast_m(string), \ + cxstring: cx_strsplit_a_, \ + cxmutstr: cx_strsplit_ma_)\ + (allocator, cx_strcast_m(string), cx_strcast(delim), limit, output) +#endif /** * Compares two strings. @@ -852,8 +970,8 @@ CX_EXPORT size_t cx_strsplit_ma_(const CxAllocator *allocator, * @return negative if @p s1 is smaller than @p s2, positive if @p s1 is larger * than @p s2, zero if both strings equal */ -cx_attr_nodiscard -CX_EXPORT int cx_strcmp_(cxstring s1, cxstring s2); +CX_EXTERN CX_NODISCARD +int cx_strcmp_(cxstring s1, cxstring s2); /** * Compares two strings. @@ -873,8 +991,8 @@ CX_EXPORT int cx_strcmp_(cxstring s1, cxstring s2); * @return negative if @p s1 is smaller than @p s2, positive if @p s1 is larger * than @p s2, zero if both strings equal ignoring case */ -cx_attr_nodiscard -CX_EXPORT int cx_strcasecmp_(cxstring s1, cxstring s2); +CX_EXTERN CX_NODISCARD +int cx_strcasecmp_(cxstring s1, cxstring s2); /** * Compares two strings ignoring case. @@ -899,8 +1017,8 @@ CX_EXPORT int cx_strcasecmp_(cxstring s1, cxstring s2); * @return negative if @p s1 is smaller than @p s2, positive if @p s1 is larger * than @p s2, zero if both strings equal */ -cx_attr_nodiscard cx_attr_nonnull -CX_EXPORT int cx_strcmp_p(const void *s1, const void *s2); +CX_EXTERN CX_NODISCARD CX_NONNULL +int cx_strcmp_p(const void *s1, const void *s2); /** * Compares two strings ignoring case. @@ -912,9 +1030,8 @@ CX_EXPORT int cx_strcmp_p(const void *s1, const void *s2); * @return negative if @p s1 is smaller than @p s2, positive if @p s1 is larger * than @p s2, zero if both strings equal ignoring case */ -cx_attr_nodiscard cx_attr_nonnull -CX_EXPORT int cx_strcasecmp_p(const void *s1, const void *s2); - +CX_EXTERN CX_NODISCARD CX_NONNULL +int cx_strcasecmp_p(const void *s1, const void *s2); /** * Creates a duplicate of the specified string. @@ -928,8 +1045,8 @@ CX_EXPORT int cx_strcasecmp_p(const void *s1, const void *s2); * @return a duplicate of the string * @see cx_strdup() */ -cx_attr_nodiscard cx_attr_nonnull -CX_EXPORT cxmutstr cx_strdup_a_(const CxAllocator *allocator, cxstring string); +CX_EXTERN CX_NODISCARD CX_NONNULL +cxmutstr cx_strdup_a_(const CxAllocator *allocator, cxstring string); /** * Creates a duplicate of the specified string. @@ -962,16 +1079,31 @@ CX_EXPORT cxmutstr cx_strdup_a_(const CxAllocator *allocator, cxstring string); #define cx_strdup(string) cx_strdup_a(cxDefaultAllocator, string) /** - * Omits leading and trailing spaces. - * - * @note the returned string references the same memory, thus you - * must @em not free the returned memory. - * - * @param string the string that shall be trimmed - * @return the trimmed string + * Trims a string. + * Internal function - do not use. + * @param string + * @return + */ +CX_EXTERN CX_NODISCARD +cxstring cx_strtrim_(cxstring string); + +#ifdef __cplusplus +CX_CPPDECL cxstring cx_strtrim_cpp_(cxstring string) { + return cx_strtrim_(string); +} +CX_CPPDECL cxmutstr cx_strtrim_cpp_(cxmutstr string) { + return cx_mutstrcast(cx_strtrim_(cx_strcast(string))); +} +#define cx_strtrim(string) cx_strtrim_cpp_(cx_strcast_m(string)) +#else +/** + * Internal conversion function. + * @param string + * @return */ -cx_attr_nodiscard -CX_EXPORT cxstring cx_strtrim(cxstring string); +CX_INLINE cxmutstr cx_strtrim_m_(cxmutstr string) { + return cx_mutstrcast(cx_strtrim_(cx_strcast(string))); +} /** * Omits leading and trailing spaces. @@ -980,10 +1112,12 @@ CX_EXPORT cxstring cx_strtrim(cxstring string); * must @em not free the returned memory. * * @param string the string that shall be trimmed - * @return the trimmed string + * @return (@c cxstring or @c cxmutstr) the trimmed string */ -cx_attr_nodiscard -CX_EXPORT cxmutstr cx_strtrim_m(cxmutstr string); +#define cx_strtrim(string) _Generic(cx_strcast_m(string), \ + cxstring: cx_strtrim_, \ + cxmutstr: cx_strtrim_m_)(cx_strcast_m(string)) +#endif /** * Checks if a string has a specific prefix. @@ -993,8 +1127,8 @@ CX_EXPORT cxmutstr cx_strtrim_m(cxmutstr string); * @return @c true, if and only if the string has the specified prefix, * @c false otherwise */ -cx_attr_nodiscard -CX_EXPORT bool cx_strprefix_(cxstring string, cxstring prefix); +CX_EXTERN CX_NODISCARD +bool cx_strprefix_(cxstring string, cxstring prefix); /** * Checks if a string has a specific prefix. @@ -1014,8 +1148,8 @@ CX_EXPORT bool cx_strprefix_(cxstring string, cxstring prefix); * @return @c true, if and only if the string has the specified suffix, * @c false otherwise */ -cx_attr_nodiscard -CX_EXPORT bool cx_strsuffix_(cxstring string, cxstring suffix); +CX_EXTERN CX_NODISCARD +bool cx_strsuffix_(cxstring string, cxstring suffix); /** * Checks if a string has a specific suffix. @@ -1035,8 +1169,8 @@ CX_EXPORT bool cx_strsuffix_(cxstring string, cxstring suffix); * @return @c true, if and only if the string has the specified prefix, * @c false otherwise */ -cx_attr_nodiscard -CX_EXPORT bool cx_strcaseprefix_(cxstring string, cxstring prefix); +CX_EXTERN CX_NODISCARD +bool cx_strcaseprefix_(cxstring string, cxstring prefix); /** * Checks if a string has a specific prefix, ignoring the case. @@ -1056,8 +1190,8 @@ CX_EXPORT bool cx_strcaseprefix_(cxstring string, cxstring prefix); * @return @c true, if and only if the string has the specified suffix, * @c false otherwise */ -cx_attr_nodiscard -CX_EXPORT bool cx_strcasesuffix_(cxstring string, cxstring suffix); +CX_EXTERN CX_NODISCARD +bool cx_strcasesuffix_(cxstring string, cxstring suffix); /** * Checks, if a string has a specific suffix, ignoring the case. @@ -1069,7 +1203,6 @@ CX_EXPORT bool cx_strcasesuffix_(cxstring string, cxstring suffix); */ #define cx_strcasesuffix(string, suffix) cx_strcasesuffix_(cx_strcast(string), cx_strcast(suffix)) - /** * Replaces a string with another string. * @@ -1086,8 +1219,8 @@ CX_EXPORT bool cx_strcasesuffix_(cxstring string, cxstring suffix); * @see cx_strreplacen_a() * @see cx_strreplacen() */ -cx_attr_nodiscard cx_attr_nonnull -CX_EXPORT cxmutstr cx_strreplace_(const CxAllocator *allocator, +CX_EXTERN CX_NODISCARD CX_NONNULL +cxmutstr cx_strreplace_(const CxAllocator *allocator, cxstring str, cxstring search, cxstring replacement, size_t replmax); /** @@ -1174,8 +1307,8 @@ CX_EXPORT cxmutstr cx_strreplace_(const CxAllocator *allocator, * @param limit the maximum number of tokens that shall be returned * @return a new string tokenization context */ -cx_attr_nodiscard -CX_EXPORT CxStrtokCtx cx_strtok_(cxstring str, cxstring delim, size_t limit); +CX_EXTERN CX_NODISCARD +CxStrtokCtx cx_strtok_(cxstring str, cxstring delim, size_t limit); /** * Creates a string tokenization context. @@ -1198,25 +1331,34 @@ CX_EXPORT CxStrtokCtx cx_strtok_(cxstring str, cxstring delim, size_t limit); * @return true if successful, false if the limit or the end of the string * has been reached */ -cx_attr_nonnull cx_attr_nodiscard cx_attr_access_w(2) -CX_EXPORT bool cx_strtok_next(CxStrtokCtx *ctx, cxstring *token); +CX_EXTERN CX_NONNULL CX_NODISCARD CX_ACCESS_W(2) +bool cx_strtok_next_(CxStrtokCtx *ctx, cxstring *token); +#ifdef __cplusplus +CX_CPPDECL cx_strtok_next(CxStrtokCtx *ctx, cxstring *token) { + return cx_strtok_next_(ctx, token); +} +CX_CPPDECL cx_strtok_next(CxStrtokCtx *ctx, cxmutstr *token) { + // Note: this is actually UB - fixed with start_lifetime_as() in C++23 + // but it works on all supported platforms + return cx_strtok_next_(ctx, reinterpret_cast(token)); +} +#else // ! __cplusplus /** - * Returns the next token of a mutable string. + * Returns the next token. * * The token will point to the source string. * - * @attention - * If the context was not initialized over a mutable string, modifying - * the data of the returned token is undefined behavior. - * - * @param ctx the tokenization context - * @param token a pointer to memory where the next token shall be stored + * @param ctx (@c CxStrtokCtx*) the tokenization context + * @param token a pointer to either a @c cxstring or @c cxmutstr + * where the next token shall be stored * @return true if successful, false if the limit or the end of the string * has been reached */ -cx_attr_nonnull cx_attr_nodiscard cx_attr_access_w(2) -CX_EXPORT bool cx_strtok_next_m(CxStrtokCtx *ctx, cxmutstr *token); +#define cx_strtok_next(ctx, token) _Generic((token), \ + cxstring*: cx_strtok_next_, \ + cxmutstr*: cx_strtok_next_)(ctx, (cxstring*)token) +#endif /** * Defines an array of more delimiters for the specified tokenization context. @@ -1225,8 +1367,8 @@ CX_EXPORT bool cx_strtok_next_m(CxStrtokCtx *ctx, cxmutstr *token); * @param delim array of more delimiters * @param count number of elements in the array */ -cx_attr_nonnull cx_attr_access_r(2, 3) -CX_EXPORT void cx_strtok_delim(CxStrtokCtx *ctx, const cxstring *delim, size_t count); +CX_EXTERN CX_NONNULL CX_ACCESS_R(2, 3) +void cx_strtok_delim(CxStrtokCtx *ctx, const cxstring *delim, size_t count); /* ------------------------------------------------------------------------- * * string to number conversion functions * @@ -1246,8 +1388,8 @@ CX_EXPORT void cx_strtok_delim(CxStrtokCtx *ctx, const cxstring *delim, size_t c * @retval zero success * @retval non-zero conversion was not possible */ -cx_attr_access_w(2) cx_attr_nonnull_arg(2) -CX_EXPORT int cx_strtos_lc_(cxstring str, short *output, int base, const char *groupsep); +CX_EXTERN CX_ACCESS_W(2) CX_NONNULL_ARG(2) +int cx_strtos_lc_(cxstring str, short *output, int base, const char *groupsep); /** * Converts a string to a number. @@ -1263,8 +1405,8 @@ CX_EXPORT int cx_strtos_lc_(cxstring str, short *output, int base, const char *g * @retval zero success * @retval non-zero conversion was not possible */ -cx_attr_access_w(2) cx_attr_nonnull_arg(2) -CX_EXPORT int cx_strtoi_lc_(cxstring str, int *output, int base, const char *groupsep); +CX_EXTERN CX_ACCESS_W(2) CX_NONNULL_ARG(2) +int cx_strtoi_lc_(cxstring str, int *output, int base, const char *groupsep); /** * Converts a string to a number. @@ -1280,8 +1422,8 @@ CX_EXPORT int cx_strtoi_lc_(cxstring str, int *output, int base, const char *gro * @retval zero success * @retval non-zero conversion was not possible */ -cx_attr_access_w(2) cx_attr_nonnull_arg(2) -CX_EXPORT int cx_strtol_lc_(cxstring str, long *output, int base, const char *groupsep); +CX_EXTERN CX_ACCESS_W(2) CX_NONNULL_ARG(2) +int cx_strtol_lc_(cxstring str, long *output, int base, const char *groupsep); /** * Converts a string to a number. @@ -1297,8 +1439,8 @@ CX_EXPORT int cx_strtol_lc_(cxstring str, long *output, int base, const char *gr * @retval zero success * @retval non-zero conversion was not possible */ -cx_attr_access_w(2) cx_attr_nonnull_arg(2) -CX_EXPORT int cx_strtoll_lc_(cxstring str, long long *output, int base, const char *groupsep); +CX_EXTERN CX_ACCESS_W(2) CX_NONNULL_ARG(2) +int cx_strtoll_lc_(cxstring str, long long *output, int base, const char *groupsep); /** * Converts a string to a number. @@ -1314,8 +1456,8 @@ CX_EXPORT int cx_strtoll_lc_(cxstring str, long long *output, int base, const ch * @retval zero success * @retval non-zero conversion was not possible */ -cx_attr_access_w(2) cx_attr_nonnull_arg(2) -CX_EXPORT int cx_strtoi8_lc_(cxstring str, int8_t *output, int base, const char *groupsep); +CX_EXTERN CX_ACCESS_W(2) CX_NONNULL_ARG(2) +int cx_strtoi8_lc_(cxstring str, int8_t *output, int base, const char *groupsep); /** * Converts a string to a number. @@ -1331,8 +1473,8 @@ CX_EXPORT int cx_strtoi8_lc_(cxstring str, int8_t *output, int base, const char * @retval zero success * @retval non-zero conversion was not possible */ -cx_attr_access_w(2) cx_attr_nonnull_arg(2) -CX_EXPORT int cx_strtoi16_lc_(cxstring str, int16_t *output, int base, const char *groupsep); +CX_EXTERN CX_ACCESS_W(2) CX_NONNULL_ARG(2) +int cx_strtoi16_lc_(cxstring str, int16_t *output, int base, const char *groupsep); /** * Converts a string to a number. @@ -1348,8 +1490,8 @@ CX_EXPORT int cx_strtoi16_lc_(cxstring str, int16_t *output, int base, const cha * @retval zero success * @retval non-zero conversion was not possible */ -cx_attr_access_w(2) cx_attr_nonnull_arg(2) -CX_EXPORT int cx_strtoi32_lc_(cxstring str, int32_t *output, int base, const char *groupsep); +CX_EXTERN CX_ACCESS_W(2) CX_NONNULL_ARG(2) +int cx_strtoi32_lc_(cxstring str, int32_t *output, int base, const char *groupsep); /** * Converts a string to a number. @@ -1365,8 +1507,8 @@ CX_EXPORT int cx_strtoi32_lc_(cxstring str, int32_t *output, int base, const cha * @retval zero success * @retval non-zero conversion was not possible */ -cx_attr_access_w(2) cx_attr_nonnull_arg(2) -CX_EXPORT int cx_strtoi64_lc_(cxstring str, int64_t *output, int base, const char *groupsep); +CX_EXTERN CX_ACCESS_W(2) CX_NONNULL_ARG(2) +int cx_strtoi64_lc_(cxstring str, int64_t *output, int base, const char *groupsep); /** * Converts a string to a number. @@ -1382,8 +1524,8 @@ CX_EXPORT int cx_strtoi64_lc_(cxstring str, int64_t *output, int base, const cha * @retval zero success * @retval non-zero conversion was not possible */ -cx_attr_access_w(2) cx_attr_nonnull_arg(2) -CX_EXPORT int cx_strtous_lc_(cxstring str, unsigned short *output, int base, const char *groupsep); +CX_EXTERN CX_ACCESS_W(2) CX_NONNULL_ARG(2) +int cx_strtous_lc_(cxstring str, unsigned short *output, int base, const char *groupsep); /** * Converts a string to a number. @@ -1399,8 +1541,8 @@ CX_EXPORT int cx_strtous_lc_(cxstring str, unsigned short *output, int base, con * @retval zero success * @retval non-zero conversion was not possible */ -cx_attr_access_w(2) cx_attr_nonnull_arg(2) -CX_EXPORT int cx_strtou_lc_(cxstring str, unsigned int *output, int base, const char *groupsep); +CX_EXTERN CX_ACCESS_W(2) CX_NONNULL_ARG(2) +int cx_strtou_lc_(cxstring str, unsigned int *output, int base, const char *groupsep); /** * Converts a string to a number. @@ -1416,8 +1558,8 @@ CX_EXPORT int cx_strtou_lc_(cxstring str, unsigned int *output, int base, const * @retval zero success * @retval non-zero conversion was not possible */ -cx_attr_access_w(2) cx_attr_nonnull_arg(2) -CX_EXPORT int cx_strtoul_lc_(cxstring str, unsigned long *output, int base, const char *groupsep); +CX_EXTERN CX_ACCESS_W(2) CX_NONNULL_ARG(2) +int cx_strtoul_lc_(cxstring str, unsigned long *output, int base, const char *groupsep); /** * Converts a string to a number. @@ -1433,8 +1575,8 @@ CX_EXPORT int cx_strtoul_lc_(cxstring str, unsigned long *output, int base, cons * @retval zero success * @retval non-zero conversion was not possible */ -cx_attr_access_w(2) cx_attr_nonnull_arg(2) -CX_EXPORT int cx_strtoull_lc_(cxstring str, unsigned long long *output, int base, const char *groupsep); +CX_EXTERN CX_ACCESS_W(2) CX_NONNULL_ARG(2) +int cx_strtoull_lc_(cxstring str, unsigned long long *output, int base, const char *groupsep); /** * Converts a string to a number. @@ -1450,8 +1592,8 @@ CX_EXPORT int cx_strtoull_lc_(cxstring str, unsigned long long *output, int base * @retval zero success * @retval non-zero conversion was not possible */ -cx_attr_access_w(2) cx_attr_nonnull_arg(2) -CX_EXPORT int cx_strtou8_lc_(cxstring str, uint8_t *output, int base, const char *groupsep); +CX_EXTERN CX_ACCESS_W(2) CX_NONNULL_ARG(2) +int cx_strtou8_lc_(cxstring str, uint8_t *output, int base, const char *groupsep); /** * Converts a string to a number. @@ -1467,8 +1609,8 @@ CX_EXPORT int cx_strtou8_lc_(cxstring str, uint8_t *output, int base, const char * @retval zero success * @retval non-zero conversion was not possible */ -cx_attr_access_w(2) cx_attr_nonnull_arg(2) -CX_EXPORT int cx_strtou16_lc_(cxstring str, uint16_t *output, int base, const char *groupsep); +CX_EXTERN CX_ACCESS_W(2) CX_NONNULL_ARG(2) +int cx_strtou16_lc_(cxstring str, uint16_t *output, int base, const char *groupsep); /** * Converts a string to a number. @@ -1484,8 +1626,8 @@ CX_EXPORT int cx_strtou16_lc_(cxstring str, uint16_t *output, int base, const ch * @retval zero success * @retval non-zero conversion was not possible */ -cx_attr_access_w(2) cx_attr_nonnull_arg(2) -CX_EXPORT int cx_strtou32_lc_(cxstring str, uint32_t *output, int base, const char *groupsep); +CX_EXTERN CX_ACCESS_W(2) CX_NONNULL_ARG(2) +int cx_strtou32_lc_(cxstring str, uint32_t *output, int base, const char *groupsep); /** * Converts a string to a number. @@ -1501,8 +1643,8 @@ CX_EXPORT int cx_strtou32_lc_(cxstring str, uint32_t *output, int base, const ch * @retval zero success * @retval non-zero conversion was not possible */ -cx_attr_access_w(2) cx_attr_nonnull_arg(2) -CX_EXPORT int cx_strtou64_lc_(cxstring str, uint64_t *output, int base, const char *groupsep); +CX_EXTERN CX_ACCESS_W(2) CX_NONNULL_ARG(2) +int cx_strtou64_lc_(cxstring str, uint64_t *output, int base, const char *groupsep); /** * Converts a string to a number. @@ -1518,8 +1660,8 @@ CX_EXPORT int cx_strtou64_lc_(cxstring str, uint64_t *output, int base, const ch * @retval zero success * @retval non-zero conversion was not possible */ -cx_attr_access_w(2) cx_attr_nonnull_arg(2) -CX_EXPORT int cx_strtoz_lc_(cxstring str, size_t *output, int base, const char *groupsep); +CX_EXTERN CX_ACCESS_W(2) CX_NONNULL_ARG(2) +int cx_strtoz_lc_(cxstring str, size_t *output, int base, const char *groupsep); /** * Converts a string to a single precision floating-point number. @@ -1535,8 +1677,8 @@ CX_EXPORT int cx_strtoz_lc_(cxstring str, size_t *output, int base, const char * * @retval zero success * @retval non-zero conversion was not possible */ -cx_attr_access_w(2) cx_attr_nonnull_arg(2) -CX_EXPORT int cx_strtof_lc_(cxstring str, float *output, char decsep, const char *groupsep); +CX_EXTERN CX_ACCESS_W(2) CX_NONNULL_ARG(2) +int cx_strtof_lc_(cxstring str, float *output, char decsep, const char *groupsep); /** * Converts a string to a double precision floating-point number. @@ -1552,8 +1694,8 @@ CX_EXPORT int cx_strtof_lc_(cxstring str, float *output, char decsep, const char * @retval zero success * @retval non-zero conversion was not possible */ -cx_attr_access_w(2) cx_attr_nonnull_arg(2) -CX_EXPORT int cx_strtod_lc_(cxstring str, double *output, char decsep, const char *groupsep); +CX_EXTERN CX_ACCESS_W(2) CX_NONNULL_ARG(2) +int cx_strtod_lc_(cxstring str, double *output, char decsep, const char *groupsep); /** * Converts a string to a number. @@ -2199,8 +2341,4 @@ CX_EXPORT int cx_strtod_lc_(cxstring str, double *output, char decsep, const cha */ #define cx_strtod(str, output) cx_strtod_lc_(cx_strcast(str), output, '.', ",") -#ifdef __cplusplus -} // extern "C" -#endif - #endif //UCX_STRING_H diff --git a/ucx/cx/test.h b/ucx/cx/test.h index 211c50f..5980f49 100644 --- a/ucx/cx/test.h +++ b/ucx/cx/test.h @@ -73,10 +73,6 @@ #include #include -#ifdef __cplusplus -extern "C" { -#endif - #ifndef __FUNCTION__ /** * Alias for the __func__ preprocessor macro. @@ -136,7 +132,7 @@ struct CxTestSuite { * @param name optional name of the suite * @return a new test suite */ -cx_attr_nonnull cx_attr_nodiscard cx_attr_cstr_arg(1) cx_attr_malloc +CX_NONNULL CX_NODISCARD CX_CSTR_ARG(1) CX_MALLOC static inline CxTestSuite* cx_test_suite_new(const char *name) { CxTestSuite* suite = (CxTestSuite*) malloc(sizeof(CxTestSuite)); if (suite != NULL) { @@ -173,7 +169,7 @@ CX_INLINE void cx_test_suite_free(CxTestSuite* suite) { * @retval zero success * @retval non-zero failure */ -cx_attr_nonnull +CX_NONNULL CX_INLINE int cx_test_register(CxTestSuite* suite, CxTest test) { CxTestSet *t = (CxTestSet*) malloc(sizeof(CxTestSet)); if (t) { @@ -200,7 +196,7 @@ CX_INLINE int cx_test_register(CxTestSuite* suite, CxTest test) { * @param out_target the target buffer or file to write the output to * @param out_writer the write function writing to @p out_target */ -cx_attr_nonnull +CX_NONNULL CX_INLINE void cx_test_run(CxTestSuite *suite, void *out_target, cx_write_func out_writer) { if (suite->name == NULL) { out_writer("*** Test Suite ***\n", 1, 19, out_target); @@ -326,9 +322,5 @@ CX_INLINE void cx_test_run(CxTestSuite *suite, void *out_target, cx_write_func o #define CX_TEST_CALL_SUBROUTINE(name,...) \ name(_suite_,_output_,_writefnc_,_env_,__VA_ARGS__) -#ifdef __cplusplus -} -#endif - #endif /* UCX_TEST_H */ diff --git a/ucx/cx/tree.h b/ucx/cx/tree.h index 23ab58e..d9e6fe1 100644 --- a/ucx/cx/tree.h +++ b/ucx/cx/tree.h @@ -40,93 +40,6 @@ #include "collection.h" -#ifdef __cplusplus -extern "C" { -#endif - -/** - * A depth-first tree iterator. - * - * This iterator is not position-aware in a strict sense, as it does not assume - * a particular order of elements in the tree. However, the iterator keeps track - * of the number of nodes it has passed in a counter-variable. - * Each node, regardless of the number of passes, is counted only once. - * - * @note Objects that are pointed to by an iterator are mutable through that - * iterator. However, if the - * underlying data structure is mutated by other means than this iterator (e.g., - * elements added or removed), the iterator becomes invalid (regardless of what - * cxIteratorValid() returns). - * - * @see CxIterator - */ -typedef struct cx_tree_iterator_s { - /** - * Base members. - */ - CX_ITERATOR_BASE; - /** - * Indicates whether the subtree below the current node shall be skipped. - */ - bool skip; - /** - * Set to true, when the iterator shall visit a node again - * when all its children have been processed. - */ - bool visit_on_exit; - /** - * True, if this iterator is currently leaving the node. - */ - bool exiting; - /** - * Offset in the node struct for the children linked list. - */ - ptrdiff_t loc_children; - /** - * Offset in the node struct for the next pointer. - */ - ptrdiff_t loc_next; - /** - * The total number of distinct nodes that have been passed so far. - * This includes the current node. - */ - size_t counter; - /** - * The currently observed node. - * - * This is the same what cxIteratorCurrent() would return. - */ - void *node; - /** - * Stores a copy of the pointer to the successor of the visited node. - * Allows freeing a node on exit without corrupting the iteration. - */ - void *node_next; - /** - * Internal stack. - * Will be automatically freed once the iterator becomes invalid. - * - * If you want to discard the iterator before, you need to manually - * call cxTreeIteratorDispose(). - */ - void **stack; - /** - * Internal capacity of the stack. - */ - size_t stack_capacity; - union { - /** - * Internal stack size. - */ - size_t stack_size; - /** - * The current depth in the tree. - * The node with which the iteration starts has depth 1. - */ - size_t depth; - }; -} CxTreeIterator; - /** * An element in a visitor queue. */ @@ -147,35 +60,13 @@ struct cx_tree_visitor_queue_s { }; /** - * A breadth-first tree iterator. - * - * This iterator needs to maintain a visitor queue that will be automatically - * freed once the iterator becomes invalid. - * If you want to discard the iterator before, you MUST manually call - * cxTreeVisitorDispose(). - * - * This iterator is not position-aware in a strict sense, as it does not assume - * a particular order of elements in the tree. However, the iterator keeps track - * of the number of nodes it has passed in a counter-variable. - * Each node, regardless of the number of passes, is counted only once. - * - * @note Objects that are pointed to by an iterator are mutable through that - * iterator. However, if the - * underlying data structure is mutated by other means than this iterator (e.g., - * elements added or removed), the iterator becomes invalid (regardless of what - * cxIteratorValid() returns). - * - * @see CxIterator + * An iterator (DFS) or visitor (BFS) for a tree. */ -typedef struct cx_tree_visitor_s { +typedef struct cx_tree_combined_iterator_s { /** * Base members. */ CX_ITERATOR_BASE; - /** - * Indicates whether the subtree below the current node shall be skipped. - */ - bool skip; /** * Offset in the node struct for the children linked list. */ @@ -189,6 +80,10 @@ typedef struct cx_tree_visitor_s { * This includes the currently visited node. */ size_t counter; + /** + * The current depth in the tree. + */ + size_t depth; /** * The currently observed node. * @@ -196,32 +91,64 @@ typedef struct cx_tree_visitor_s { */ void *node; /** - * The current depth in the tree. + * Memory for BFS or DFS-specific data. */ - size_t depth; + union { + struct { + /** + * Stores a copy of the pointer to the successor of the visited node. + * Allows freeing a node on exit without corrupting the iteration. + */ + void *node_next; + /** + * Internal stack. + * Will be automatically freed once the iterator becomes invalid. + * + * If you want to discard the iterator before, you need to manually + * call cxTreeIteratorDispose(). + */ + void **stack; + /** + * Internal capacity of the stack. + */ + size_t stack_capacity; + }; + struct { + /** + * The next element in the visitor queue. + */ + struct cx_tree_visitor_queue_s *queue_next; + /** + * The last element in the visitor queue. + */ + struct cx_tree_visitor_queue_s *queue_last; + }; + }; /** - * The next element in the visitor queue. + * Indicates whether the subtree below the current node shall be skipped. */ - struct cx_tree_visitor_queue_s *queue_next; + bool skip; /** - * The last element in the visitor queue. + * Set to true, when the iterator shall visit a node again + * when all its children have been processed. */ - struct cx_tree_visitor_queue_s *queue_last; -} CxTreeVisitor; + bool visit_on_exit; + /** + * True, if this iterator is currently leaving the node. + */ + bool exiting; + /** + * Indicates whether the @c iterator (true) or the @c visitor (false) aspect is active. + */ + bool use_dfs; +} CxTreeIterator; /** * Releases internal memory of the given tree iterator. * @param iter the iterator */ -cx_attr_nonnull -CX_EXPORT void cxTreeIteratorDispose(CxTreeIterator *iter); - -/** - * Releases internal memory of the given tree visitor. - * @param visitor the visitor - */ -cx_attr_nonnull -CX_EXPORT void cxTreeVisitorDispose(CxTreeVisitor *visitor); +CX_EXTERN CX_NONNULL +void cxTreeIteratorDispose(CxTreeIterator *iter); /** * Advises the iterator to skip the subtree below the current node and @@ -231,14 +158,6 @@ CX_EXPORT void cxTreeVisitorDispose(CxTreeVisitor *visitor); */ #define cxTreeIteratorContinue(iterator) (iterator).skip = true; continue -/** - * Advises the visitor to skip the subtree below the current node and - * also continues the current loop. - * - * @param visitor (@c CxTreeVisitor) the visitor - */ -#define cxTreeVisitorContinue(visitor) cxTreeIteratorContinue(visitor) - /** * Links a node to a (new) parent. * @@ -254,10 +173,10 @@ CX_EXPORT void cxTreeVisitorDispose(CxTreeVisitor *visitor); * the last child in the linked list (negative if there is no such pointer) * @param loc_prev optional offset in the node struct for the prev pointer * @param loc_next offset in the node struct for the next pointer - * @see cx_tree_unlink() + * @see cx_tree_remove() */ -cx_attr_nonnull -CX_EXPORT void cx_tree_link(void *parent, void *node, +CX_EXTERN CX_NONNULL +void cx_tree_add(void *parent, void *node, ptrdiff_t loc_parent, ptrdiff_t loc_children, ptrdiff_t loc_last_child, ptrdiff_t loc_prev, ptrdiff_t loc_next); @@ -273,10 +192,10 @@ CX_EXPORT void cx_tree_link(void *parent, void *node, * the last child in the linked list (negative if there is no such pointer) * @param loc_prev optional offset in the node struct for the prev pointer * @param loc_next offset in the node struct for the next pointer - * @see cx_tree_link() + * @see cx_tree_add() */ -cx_attr_nonnull -CX_EXPORT void cx_tree_unlink(void *node, +CX_EXTERN CX_NONNULL +void cx_tree_remove(void *node, ptrdiff_t loc_parent, ptrdiff_t loc_children, ptrdiff_t loc_last_child, ptrdiff_t loc_prev, ptrdiff_t loc_next); @@ -311,43 +230,14 @@ CX_EXPORT void cx_tree_unlink(void *node, * positive if one of the children might contain the data, * negative if neither the node nor the children contains the data */ -typedef int (*cx_tree_search_data_func)(const void *node, const void *data); - - -/** - * Function pointer for a search function. - * - * A function of this kind shall check if the specified @p node - * contains the same @p data as @p new_node or if one of the children might - * contain the data. - * - * The function should use the returned integer to indicate how close the - * match is, where a negative number means that it does not match at all. - * Zero means exact match and a positive number is an implementation defined - * measure for the distance to an exact match. - * - * For example, consider a tree that stores file path information. - * A node which is describing a parent directory of a searched file shall - * return a positive number to indicate that a child node might contain the - * searched item. On the other hand, if the node denotes a path that is not a - * prefix of the searched filename, the function would return -1 to indicate - * that the search does not need to be continued in that branch. - * - * @param node the node that is currently investigated - * @param new_node a new node with the information which is searched - * - * @return 0 if @p node contains the same data as @p new_node, - * positive if one of the children might contain the data, - * negative if neither the node nor the children contains the data - */ -typedef int (*cx_tree_search_func)(const void *node, const void *new_node); +typedef int (*cx_tree_search_func)(const void *node, const void *data); /** * Searches for data in a tree. * * When the data cannot be found exactly, the search function might return the * closest result, which might be a good starting point for adding a new node - * to the tree (see also #cx_tree_add()). + * to the tree. * * Depending on the tree structure, it is not necessarily guaranteed that the * "closest" match is uniquely defined. This function will search for a node @@ -356,7 +246,7 @@ typedef int (*cx_tree_search_func)(const void *node, const void *new_node); * node matching the criteria is returned. * * @param root the root node - * @param depth the maximum depth (zero=indefinite, one=just root) + * @param max_depth the maximum depth (zero=indefinite, one=just root) * @param data the data to search for * @param sfunc the search function * @param result where the result shall be stored @@ -366,39 +256,10 @@ typedef int (*cx_tree_search_func)(const void *node, const void *new_node); * could contain the node (but doesn't right now), negative if the tree does not * contain any node that might be related to the searched data */ -cx_attr_nonnull cx_attr_access_w(5) -CX_EXPORT int cx_tree_search_data(const void *root, size_t depth, - const void *data, cx_tree_search_data_func sfunc, - void **result, ptrdiff_t loc_children, ptrdiff_t loc_next); - -/** - * Searches for a node in a tree. - * - * When no node with the same data can be found, the search function might - * return the closest result, which might be a good starting point for adding the - * new node to the tree (see also #cx_tree_add()). - * - * Depending on the tree structure, it is not necessarily guaranteed that the - * "closest" match is uniquely defined. This function will search for a node - * with the best match according to the @p sfunc (meaning: the return value of - * @p sfunc which is closest to zero). If that is also ambiguous, an arbitrary - * node matching the criteria is returned. - * - * @param root the root node -* @param depth the maximum depth (zero=indefinite, one=just root) - * @param node the node to search for - * @param sfunc the search function - * @param result where the result shall be stored - * @param loc_children offset in the node struct for the children linked list - * @param loc_next offset in the node struct for the next pointer - * @return zero if the node was found exactly, positive if a node was found that - * could contain the node (but doesn't right now), negative if the tree does not - * contain any node that might be related to the searched data - */ -cx_attr_nonnull cx_attr_access_w(5) -CX_EXPORT int cx_tree_search(const void *root, size_t depth, - const void *node, cx_tree_search_func sfunc, - void **result, ptrdiff_t loc_children, ptrdiff_t loc_next); +CX_EXTERN CX_NONNULL_ARG(4, 5) CX_ACCESS_W(5) +int cx_tree_search(const void *root, size_t max_depth, + const void *data, cx_tree_search_func sfunc, void **result, + ptrdiff_t loc_children, ptrdiff_t loc_next); /** * Creates a depth-first iterator for a tree with the specified root node. @@ -420,8 +281,8 @@ CX_EXPORT int cx_tree_search(const void *root, size_t depth, * @return the new tree iterator * @see cxTreeIteratorDispose() */ -cx_attr_nodiscard -CX_EXPORT CxTreeIterator cx_tree_iterator(void *root, bool visit_on_exit, +CX_EXTERN CX_NODISCARD +CxTreeIterator cx_tree_iterator(void *root, bool visit_on_exit, ptrdiff_t loc_children, ptrdiff_t loc_next); /** @@ -431,7 +292,7 @@ CX_EXPORT CxTreeIterator cx_tree_iterator(void *root, bool visit_on_exit, * is allocated using the cxDefaultAllocator. * When the visitor becomes invalid, this memory is automatically released. * However, if you wish to cancel the iteration before the visitor becomes - * invalid by itself, you MUST call cxTreeVisitorDispose() manually to release + * invalid by itself, you MUST call cxTreeIteratorDispose() manually to release * the memory. * * @remark The returned iterator does not support cxIteratorFlagRemoval(). @@ -440,179 +301,12 @@ CX_EXPORT CxTreeIterator cx_tree_iterator(void *root, bool visit_on_exit, * @param loc_children offset in the node struct for the children linked list * @param loc_next offset in the node struct for the next pointer * @return the new tree visitor - * @see cxTreeVisitorDispose() + * @see cxTreeIteratorDispose() */ -cx_attr_nodiscard -CX_EXPORT CxTreeVisitor cx_tree_visitor(void *root, +CX_EXTERN CX_NODISCARD +CxTreeIterator cx_tree_visitor(void *root, ptrdiff_t loc_children, ptrdiff_t loc_next); -/** - * Describes a function that creates a tree node from the specified data. - * The first argument points to the data the node shall contain, and - * the second argument may be used for additional data (e.g., an allocator). - * Functions of this type shall either return a new pointer to a newly - * created node or @c NULL when allocation fails. - * - * @note the function may leave the node pointers in the struct uninitialized. - * The caller is responsible to set them according to the intended use case. - */ -typedef void *(*cx_tree_node_create_func)(const void *, void *); - -/** - * The local search depth for a new subtree when adding multiple elements. - * The default value is 3. - * This variable is used by #cx_tree_add_array() and #cx_tree_add_iter() to - * implement optimized insertion of multiple elements into a tree. - */ -CX_EXPORT extern unsigned int cx_tree_add_look_around_depth; - -/** - * Adds multiple elements efficiently to a tree. - * - * Once an element cannot be added to the tree, this function returns, leaving - * the iterator in a valid state pointing to the element that could not be - * added. - * Also, the pointer of the created node will be stored to @p failed. - * The integer returned by this function denotes the number of elements obtained - * from the @p iter that have been successfully processed. - * When all elements could be processed, a @c NULL pointer will be written to - * @p failed. - * - * The advantage of this function compared to multiple invocations of - * #cx_tree_add() is that the search for the insert locations is not always - * started from the root node. - * Instead, the function checks #cx_tree_add_look_around_depth many parent nodes - * of the current insert location before starting from the root node again. - * When the variable is set to zero, only the last found location is checked - * again. - * - * Refer to the documentation of #cx_tree_add() for more details. - * - * @param iter a pointer to an arbitrary iterator - * @param num the maximum number of elements to obtain from the iterator - * @param sfunc a search function - * @param cfunc a node creation function - * @param cdata optional additional data - * @param root the root node of the tree - * @param failed location where the pointer to a failed node shall be stored - * @param loc_parent offset in the node struct for the parent pointer - * @param loc_children offset in the node struct for the children linked list - * @param loc_last_child optional offset in the node struct for the pointer to - * the last child in the linked list (negative if there is no such pointer) - * @param loc_prev optional offset in the node struct for the prev pointer - * @param loc_next offset in the node struct for the next pointer - * @return the number of nodes created and added - * @see cx_tree_add() - */ -cx_attr_nonnull_arg(1, 3, 4, 6, 7) cx_attr_access_w(6) -CX_EXPORT size_t cx_tree_add_iter(struct cx_iterator_base_s *iter, size_t num, - cx_tree_search_func sfunc, cx_tree_node_create_func cfunc, - void *cdata, void **failed, void *root, - ptrdiff_t loc_parent, ptrdiff_t loc_children, ptrdiff_t loc_last_child, - ptrdiff_t loc_prev, ptrdiff_t loc_next); - -/** - * Adds multiple elements efficiently to a tree. - * - * Once an element cannot be added to the tree, this function returns, storing - * the pointer of the created node to @p failed. - * The integer returned by this function denotes the number of elements from - * the @p src array that have been successfully processed. - * When all elements could be processed, a @c NULL pointer will be written to - * @p failed. - * - * The advantage of this function compared to multiple invocations of - * #cx_tree_add() is that the search for the insert locations is not always - * started from the root node. - * Instead, the function checks #cx_tree_add_look_around_depth many parent nodes - * of the current insert location before starting from the root node again. - * When the variable is set to zero, only the last found location is checked - * again. - * - * Refer to the documentation of #cx_tree_add() for more details. - * - * @param src a pointer to the source data array - * @param num the number of elements in the @p src array - * @param elem_size the size of each element in the @p src array - * @param sfunc a search function - * @param cfunc a node creation function - * @param cdata optional additional data - * @param failed location where the pointer to a failed node shall be stored - * @param root the root node of the tree - * @param loc_parent offset in the node struct for the parent pointer - * @param loc_children offset in the node struct for the children linked list - * @param loc_last_child optional offset in the node struct for the pointer to - * the last child in the linked list (negative if there is no such pointer) - * @param loc_prev optional offset in the node struct for the prev pointer - * @param loc_next offset in the node struct for the next pointer - * @return the number of array elements successfully processed - * @see cx_tree_add() - */ -cx_attr_nonnull_arg(1, 4, 5, 7, 8) cx_attr_access_w(7) -CX_EXPORT size_t cx_tree_add_array(const void *src, size_t num, size_t elem_size, - cx_tree_search_func sfunc, cx_tree_node_create_func cfunc, - void *cdata, void **failed, void *root, - ptrdiff_t loc_parent, ptrdiff_t loc_children, ptrdiff_t loc_last_child, - ptrdiff_t loc_prev, ptrdiff_t loc_next); - -/** - * Adds data to a tree. - * - * An adequate location where to add the new tree node is searched with the - * specified @p sfunc. - * - * When a location is found, the @p cfunc will be invoked with @p cdata. - * - * The node returned by @p cfunc will be linked into the tree. - * When @p sfunc returns a positive integer, the new node will be linked as a - * child. The other children (now siblings of the new node) are then checked - * with @p sfunc, whether they could be children of the new node and re-linked - * accordingly. - * - * When @p sfunc returns zero and the found node has a parent, the new - * node will be added as a sibling - otherwise, the new node will be added - * as a child. - * - * When @p sfunc returns a negative value, the new node will not be added to - * the tree, and this function returns a non-zero value. - * The caller should check if @p cnode contains a node pointer and deal with the - * node that could not be added. - * - * This function also returns a non-zero value when @p cfunc tries to allocate - * a new node but fails to do so. In that case, the pointer stored to @p cnode - * will be @c NULL. - * - * Multiple elements can be added more efficiently with - * #cx_tree_add_array() or #cx_tree_add_iter(). - * - * @param src a pointer to the data - * @param sfunc a search function - * @param cfunc a node creation function - * @param cdata optional additional data - * @param cnode the location where a pointer to the new node is stored - * @param root the root node of the tree - * @param loc_parent offset in the node struct for the parent pointer - * @param loc_children offset in the node struct for the children linked list - * @param loc_last_child optional offset in the node struct for the pointer to - * the last child in the linked list (negative if there is no such pointer) - * @param loc_prev optional offset in the node struct for the prev pointer - * @param loc_next offset in the node struct for the next pointer - * @return zero when a new node was created and added to the tree, - * non-zero otherwise - */ -cx_attr_nonnull_arg(1, 2, 3, 5, 6) cx_attr_access_w(5) -CX_EXPORT int cx_tree_add(const void *src, - cx_tree_search_func sfunc, cx_tree_node_create_func cfunc, - void *cdata, void **cnode, void *root, - ptrdiff_t loc_parent, ptrdiff_t loc_children, ptrdiff_t loc_last_child, - ptrdiff_t loc_prev, ptrdiff_t loc_next); - - -/** - * Tree class type. - */ -typedef struct cx_tree_class_s cx_tree_class; - /** * Base structure that can be used for tree nodes in a #CxTree. */ @@ -642,13 +336,9 @@ struct cx_tree_node_base_s { /** * Structure for holding the base data of a tree. */ -struct cx_tree_s { +typedef struct cx_tree_s { + /** Base attributes. */ CX_COLLECTION_BASE; - /** - * The tree class definition. - */ - const cx_tree_class *cl; - /** * A pointer to the root node. * @@ -657,24 +347,9 @@ struct cx_tree_s { void *root; /** - * A function to create new nodes. - * - * Invocations to this function will receive a pointer to this tree - * structure as the second argument. - * - * Nodes MAY use #cx_tree_node_base_s as the base layout, but do not need to. - */ - cx_tree_node_create_func node_create; - - /** - * A function to compare two nodes. + * The size of the node structure. */ - cx_tree_search_func search; - - /** - * A function to compare a node with data. - */ - cx_tree_search_data_func search_data; + size_t node_size; /** * Offset in the node struct for the parent pointer. @@ -701,7 +376,12 @@ struct cx_tree_s { * Offset in the node struct for the next sibling pointer. */ ptrdiff_t loc_next; -}; + + /** + * Offset in the node struct where the payload is located. + */ + ptrdiff_t loc_data; +} CxTree; /** * Macro to roll out the #cx_tree_node_base_s structure with a custom @@ -711,7 +391,7 @@ struct cx_tree_s { * * @param type the data type for the nodes */ -#define CX_TREE_NODE_BASE(type) \ +#define CX_TREE_NODE(type) \ type *parent; \ type *children;\ type *last_child;\ @@ -719,51 +399,20 @@ struct cx_tree_s { type *next /** - * Macro for specifying the layout of a base node tree. + * Macro for specifying the layout of a tree node. * - * When your tree uses #CX_TREE_NODE_BASE, you can use this + * When your tree uses #CX_TREE_NODE, you can use this * macro in all tree functions that expect the layout parameters * @c loc_parent, @c loc_children, @c loc_last_child, @c loc_prev, * and @c loc_next. + * @param struct_name the name of the node structure */ -#define cx_tree_node_base_layout \ - offsetof(struct cx_tree_node_base_s, parent),\ - offsetof(struct cx_tree_node_base_s, children),\ - offsetof(struct cx_tree_node_base_s, last_child),\ - offsetof(struct cx_tree_node_base_s, prev), \ - offsetof(struct cx_tree_node_base_s, next) - -/** - * The class definition for arbitrary trees. - */ -struct cx_tree_class_s { - /** - * Member function for inserting a single element. - * - * Implementations SHALL NOT simply invoke @p insert_many as this comes - * with too much overhead. - */ - int (*insert_element)(struct cx_tree_s *tree, const void *data); - - /** - * Member function for inserting multiple elements. - * - * Implementations SHALL avoid performing a full search in the tree for - * every element even though the source data MAY be unsorted. - */ - size_t (*insert_many)(struct cx_tree_s *tree, struct cx_iterator_base_s *iter, size_t n); - - /** - * Member function for finding a node. - */ - void *(*find)(struct cx_tree_s *tree, const void *subtree, const void *data, size_t depth); -}; - -/** - * Common type for all tree implementations. - */ -typedef struct cx_tree_s CxTree; - +#define cx_tree_node_layout(struct_name) \ + offsetof(struct_name, parent),\ + offsetof(struct_name, children),\ + offsetof(struct_name, last_child),\ + offsetof(struct_name, prev), \ + offsetof(struct_name, next) /** * Destroys a node and its subtree. @@ -783,11 +432,11 @@ typedef struct cx_tree_s CxTree; * and would therefore result in a double-free. * * @param tree the tree - * @param node the node to remove + * @param node the node being the root of the subtree to remove * @see cxTreeFree() */ -cx_attr_nonnull -CX_EXPORT void cxTreeDestroySubtree(CxTree *tree, void *node); +CX_EXTERN CX_NONNULL +void cxTreeDestroySubtree(CxTree *tree, void *node); /** @@ -807,7 +456,12 @@ CX_EXPORT void cxTreeDestroySubtree(CxTree *tree, void *node); * @param tree the tree * @see cxTreeDestroySubtree() */ -#define cxTreeClear(tree) cxTreeDestroySubtree(tree, tree->root) +CX_INLINE +void cxTreeClear(CxTree *tree) { + if (tree->root != NULL) { + cxTreeDestroySubtree(tree, tree->root); + } +} /** * Deallocates the tree structure. @@ -825,71 +479,29 @@ CX_EXPORT void cxTreeDestroySubtree(CxTree *tree, void *node); * * @param tree the tree to free */ -CX_EXPORT void cxTreeFree(CxTree *tree); +CX_EXTERN +void cxTreeFree(CxTree *tree); /** - * Creates a new tree structure based on the specified layout. + * Creates a new tree. * * The specified @p allocator will be used for creating the tree struct - * and SHALL be used by @p create_func to allocate memory for the nodes. + * @em and the nodes. * - * @note This function will also register an advanced destructor which - * will free the nodes with the allocator's free() method. + * When you do not specify an existing @p root, the tree will be created + * empty. Additionally, cxFree() is registered as the advanced destructor for + * the tree so that all nodes that you will add to the tree are automatically + * freed together with the tree. + * When @p root is not @c NULL, no destructors are registered automatically. * - * @param allocator the allocator that shall be used - * (if @c NULL, the cxDefaultAllocator will be used) - * @param create_func a function that creates new nodes - * @param search_func a function that compares two nodes - * @param search_data_func a function that compares a node with data - * @param loc_parent offset in the node struct for the parent pointer - * @param loc_children offset in the node struct for the children linked list - * @param loc_last_child optional offset in the node struct for the pointer to - * the last child in the linked list (negative if there is no such pointer) - * @param loc_prev optional offset in the node struct for the prev pointer - * @param loc_next offset in the node struct for the next pointer - * @return the new tree - * @see cxTreeCreateSimple() - * @see cxTreeCreateWrapped() - */ -cx_attr_nonnull_arg(2, 3, 4) cx_attr_nodiscard cx_attr_malloc cx_attr_dealloc(cxTreeFree, 1) -CX_EXPORT CxTree *cxTreeCreate(const CxAllocator *allocator, cx_tree_node_create_func create_func, - cx_tree_search_func search_func, cx_tree_search_data_func search_data_func, - ptrdiff_t loc_parent, ptrdiff_t loc_children, ptrdiff_t loc_last_child, - ptrdiff_t loc_prev, ptrdiff_t loc_next); - -/** - * Creates a new tree structure based on a default layout. - * - * Nodes created by @p create_func MUST contain #cx_tree_node_base_s as the first - * member (or at least respect the default offsets specified in the tree - * struct), and they MUST be allocated with the specified allocator. - * - * @note This function will also register an advanced destructor which - * will free the nodes with the allocator's free() method. - * - * @param allocator (@c CxAllocator*) the allocator that shall be used - * @param create_func (@c cx_tree_node_create_func) a function that creates new nodes - * @param search_func (@c cx_tree_search_func) a function that compares two nodes - * @param search_data_func (@c cx_tree_search_data_func) a function that compares a node with data - * @return (@c CxTree*) the new tree - * @see cxTreeCreate() - */ -#define cxTreeCreateSimple(allocator, create_func, search_func, search_data_func) \ - cxTreeCreate(allocator, create_func, search_func, search_data_func, cx_tree_node_base_layout) - -/** - * Creates a new tree structure based on an existing tree. - * - * The specified @p allocator will be used for creating the tree struct. - * - * @attention This function will create an incompletely defined tree structure - * where neither the create function, the search function, nor a destructor - * will be set. If you wish to use any of this functionality for the wrapped - * tree, you need to specify those functions afterward. - * - * @param allocator the allocator that was used for nodes of the wrapped tree + * @param allocator the allocator to use * (if @c NULL, the cxDefaultAllocator is assumed) - * @param root the root node of the tree that shall be wrapped + * @param node_size the complete size of one node + * @param elem_size the size of the payload stored in the node + * (@c CX_STORE_POINTERS is also supported) + * @param root an optional already existing root node + * @param loc_data optional offset in the node struct for the payload + * (when negative, cxTreeAddData() is not supported) * @param loc_parent offset in the node struct for the parent pointer * @param loc_children offset in the node struct for the children linked list * @param loc_last_child optional offset in the node struct for the pointer to @@ -899,92 +511,91 @@ CX_EXPORT CxTree *cxTreeCreate(const CxAllocator *allocator, cx_tree_node_create * @return the new tree * @see cxTreeCreate() */ -cx_attr_nonnull_arg(2) cx_attr_nodiscard cx_attr_malloc cx_attr_dealloc(cxTreeFree, 1) -CX_EXPORT CxTree *cxTreeCreateWrapped(const CxAllocator *allocator, void *root, +CX_EXTERN CX_NODISCARD CX_MALLOC CX_DEALLOC(cxTreeFree, 1) +CxTree *cxTreeCreate(const CxAllocator *allocator, + size_t node_size, size_t elem_size, void *root, ptrdiff_t loc_data, ptrdiff_t loc_parent, ptrdiff_t loc_children, ptrdiff_t loc_last_child, ptrdiff_t loc_prev, ptrdiff_t loc_next); /** - * Inserts data into the tree. - * - * @remark For this function to work, the tree needs specified search and - * create functions, which might not be available for wrapped trees - * (see #cxTreeCreateWrapped()). - * - * @param tree the tree - * @param data the data to insert - * @retval zero success - * @retval non-zero failure - */ -cx_attr_nonnull -CX_EXPORT int cxTreeInsert(CxTree *tree, const void *data); - -/** - * Inserts elements provided by an iterator efficiently into the tree. + * Searches the data in the specified subtree. * - * @remark For this function to work, the tree needs specified search and - * create functions, which might not be available for wrapped trees - * (see #cxTreeCreateWrapped()). + * When @p max_depth is zero, the depth is not limited. + * The @p subtree_root itself is on depth 1 and its children have depth 2. * - * @param tree the tree - * @param iter the iterator providing the elements - * @param n the maximum number of elements to insert - * @return the number of elements that could be successfully inserted - */ -cx_attr_nonnull -CX_EXPORT size_t cxTreeInsertIter(CxTree *tree, CxIteratorBase *iter, size_t n); - -/** - * Inserts an array of data efficiently into the tree. + * @note When @p subtree_root is not @c NULL and not part of the @p tree, + * the behavior is undefined. * - * @remark For this function to work, the tree needs specified search and - * create functions, which might not be available for wrapped trees - * (see #cxTreeCreateWrapped()). + * @attention When @p loc_data is not available, this function immediately returns + * @c NULL. * * @param tree the tree - * @param data the array of data to insert - * @param elem_size the size of each element in the array - * @param n the number of elements in the array - * @return the number of elements that could be successfully inserted + * @param data the data to search for + * @param subtree_root the node where to start (@c NULL to start from root) + * @param max_depth the maximum search depth + * @param use_dfs @c true when depth-first search should be used; + * @c false when breadth-first search should be used + * @return the first matching node, or @c NULL when the data cannot be found + * @see cxTreeFind() */ -cx_attr_nonnull -CX_EXPORT size_t cxTreeInsertArray(CxTree *tree, const void *data, size_t elem_size, size_t n); +CX_EXTERN CX_NONNULL_ARG(1, 2) CX_NODISCARD +void *cxTreeFindInSubtree(CxTree *tree, const void *data, void *subtree_root, + size_t max_depth, bool use_dfs); /** * Searches the data in the specified tree. * - * @remark For this function to work, the tree needs a specified @c search_data - * function, which might not be available wrapped trees - * (see #cxTreeCreateWrapped()). + * @attention When @p loc_data is not available, this function immediately returns + * @c NULL. * * @param tree the tree * @param data the data to search for + * @param use_dfs @c true when depth-first search should be used; + * @c false when breadth-first search should be used * @return the first matching node, or @c NULL when the data cannot be found + * @see cxTreeFindInSubtree() + * @see cxTreeFindFast() */ -cx_attr_nonnull cx_attr_nodiscard -CX_EXPORT void *cxTreeFind(CxTree *tree, const void *data); +CX_INLINE CX_NONNULL CX_NODISCARD +void *cxTreeFind(CxTree *tree, const void *data, bool use_dfs) { + if (tree->root == NULL) return NULL; + return cxTreeFindInSubtree(tree, data, tree->root, 0, use_dfs); +} /** - * Searches the data in the specified subtree. + * Performs an efficient depth-first search in a branch of the specified tree. * * When @p max_depth is zero, the depth is not limited. * The @p subtree_root itself is on depth 1 and its children have depth 2. * - * @note When @p subtree_root is not part of the @p tree, the behavior is - * undefined. - * - * @remark For this function to work, the tree needs a specified @c search_data - * function, which might not be the case for wrapped trees - * (see #cxTreeCreateWrapped()). + * @note When @p subtree_root is not @c NULL and not part of the @p tree, + * the behavior is undefined. * * @param tree the tree * @param data the data to search for - * @param subtree_root the node where to start + * @param sfunc the search function + * @param subtree_root the node where to start (@c NULL to start from root) * @param max_depth the maximum search depth * @return the first matching node, or @c NULL when the data cannot be found + * @see cxTreeFindInSubtree() + */ +CX_EXTERN CX_NONNULL CX_NODISCARD +void *cxTreeFindFastInSubtree(CxTree *tree, const void *data, + cx_tree_search_func sfunc, void *subtree_root, size_t max_depth); + +/** + * Performs an efficient depth-first search in the tree. + * + * @param tree the tree + * @param data the data to search for + * @param sfunc the search function + * @return the first matching node, or @c NULL when the data cannot be found + * @see cxTreeFind() */ -cx_attr_nonnull cx_attr_nodiscard -CX_EXPORT void *cxTreeFindInSubtree(CxTree *tree, const void *data, void *subtree_root, size_t max_depth); +CX_INLINE CX_NONNULL CX_NODISCARD +void *cxTreeFindFast(CxTree *tree, const void *data, cx_tree_search_func sfunc) { + return cxTreeFindFastInSubtree(tree, data, sfunc, tree->root, 0); +} /** * Determines the size of the specified subtree. @@ -993,8 +604,8 @@ CX_EXPORT void *cxTreeFindInSubtree(CxTree *tree, const void *data, void *subtre * @param subtree_root the root node of the subtree * @return the number of nodes in the specified subtree */ -cx_attr_nonnull cx_attr_nodiscard -CX_EXPORT size_t cxTreeSubtreeSize(CxTree *tree, void *subtree_root); +CX_EXTERN CX_NONNULL CX_NODISCARD +size_t cxTreeSubtreeSize(CxTree *tree, void *subtree_root); /** * Determines the depth of the specified subtree. @@ -1003,8 +614,8 @@ CX_EXPORT size_t cxTreeSubtreeSize(CxTree *tree, void *subtree_root); * @param subtree_root the root node of the subtree * @return the tree depth including the @p subtree_root */ -cx_attr_nonnull cx_attr_nodiscard -CX_EXPORT size_t cxTreeSubtreeDepth(CxTree *tree, void *subtree_root); +CX_EXTERN CX_NONNULL CX_NODISCARD +size_t cxTreeSubtreeDepth(CxTree *tree, void *subtree_root); /** * Determines the size of the entire tree. @@ -1012,8 +623,8 @@ CX_EXPORT size_t cxTreeSubtreeDepth(CxTree *tree, void *subtree_root); * @param tree the tree * @return the tree size, counting the root as one */ -cx_attr_nonnull cx_attr_nodiscard -CX_EXPORT size_t cxTreeSize(CxTree *tree); +CX_EXTERN CX_NONNULL CX_NODISCARD +size_t cxTreeSize(CxTree *tree); /** * Determines the depth of the entire tree. @@ -1021,8 +632,8 @@ CX_EXPORT size_t cxTreeSize(CxTree *tree); * @param tree the tree * @return the tree depth, counting the root as one */ -cx_attr_nonnull cx_attr_nodiscard -CX_EXPORT size_t cxTreeDepth(CxTree *tree); +CX_EXTERN CX_NONNULL CX_NODISCARD +size_t cxTreeDepth(CxTree *tree); /** * Creates a depth-first iterator for the specified tree starting in @p node. @@ -1036,8 +647,8 @@ CX_EXPORT size_t cxTreeDepth(CxTree *tree); * @return a tree iterator (depth-first) * @see cxTreeVisit() */ -cx_attr_nonnull cx_attr_nodiscard -CX_EXPORT CxTreeIterator cxTreeIterateSubtree(CxTree *tree, void *node, bool visit_on_exit); +CX_EXTERN CX_NONNULL CX_NODISCARD +CxTreeIterator cxTreeIterateSubtree(CxTree *tree, void *node, bool visit_on_exit); /** * Creates a breadth-first iterator for the specified tree starting in @p node. @@ -1049,8 +660,8 @@ CX_EXPORT CxTreeIterator cxTreeIterateSubtree(CxTree *tree, void *node, bool vis * @return a tree visitor (a.k.a. breadth-first iterator) * @see cxTreeIterate() */ -cx_attr_nonnull cx_attr_nodiscard -CX_EXPORT CxTreeVisitor cxTreeVisitSubtree(CxTree *tree, void *node); +CX_EXTERN CX_NONNULL CX_NODISCARD +CxTreeIterator cxTreeVisitSubtree(CxTree *tree, void *node); /** * Creates a depth-first iterator for the specified tree. @@ -1061,8 +672,8 @@ CX_EXPORT CxTreeVisitor cxTreeVisitSubtree(CxTree *tree, void *node); * @return a tree iterator (depth-first) * @see cxTreeVisit() */ -cx_attr_nonnull cx_attr_nodiscard -CX_EXPORT CxTreeIterator cxTreeIterate(CxTree *tree, bool visit_on_exit); +CX_EXTERN CX_NONNULL CX_NODISCARD +CxTreeIterator cxTreeIterate(CxTree *tree, bool visit_on_exit); /** * Creates a breadth-first iterator for the specified tree. @@ -1071,22 +682,22 @@ CX_EXPORT CxTreeIterator cxTreeIterate(CxTree *tree, bool visit_on_exit); * @return a tree visitor (a.k.a. breadth-first iterator) * @see cxTreeIterate() */ -cx_attr_nonnull cx_attr_nodiscard -CX_EXPORT CxTreeVisitor cxTreeVisit(CxTree *tree); +CX_EXTERN CX_NONNULL CX_NODISCARD +CxTreeIterator cxTreeVisit(CxTree *tree); /** * Sets the (new) parent of the specified child. * * If the @p child is not already a member of the tree, this function behaves - * as #cxTreeAddChildNode(). + * as #cxTreeAddNode(). * * @param tree the tree * @param parent the (new) parent of the child * @param child the node to add - * @see cxTreeAddChildNode() + * @see cxTreeAddNode() */ -cx_attr_nonnull -CX_EXPORT void cxTreeSetParent(CxTree *tree, void *parent, void *child); +CX_EXTERN CX_NONNULL +void cxTreeSetParent(CxTree *tree, void *parent, void *child); /** * Adds a new node to the tree. @@ -1095,36 +706,81 @@ CX_EXPORT void cxTreeSetParent(CxTree *tree, void *parent, void *child); * Use #cxTreeSetParent() if you want to move a subtree to another location. * * @attention The node may be externally created, but MUST obey the same rules - * as if it was created by the tree itself with #cxTreeAddChild() (e.g., use - * the same allocator). + * as if it was created by the tree itself with #cxTreeAddData() (e.g., use + * the tree's allocator). * * @param tree the tree * @param parent the parent of the node to add * @param child the node to add * @see cxTreeSetParent() + * @see cxTreeAddData() */ -cx_attr_nonnull -CX_EXPORT void cxTreeAddChildNode(CxTree *tree, void *parent, void *child); +CX_EXTERN CX_NONNULL +void cxTreeAddNode(CxTree *tree, void *parent, void *child); /** * Creates a new node and adds it to the tree. * - * With this function you can decide where exactly the new node shall be added. - * If you specified an appropriate search function, you may want to consider - * leaving this task to the tree by using #cxTreeInsert(). - * - * Be aware that adding nodes at arbitrary locations in the tree might cause - * wrong or undesired results when subsequently invoking #cxTreeInsert(), and - * the invariant imposed by the search function does not hold any longer. - * * @param tree the tree * @param parent the parent node of the new node * @param data the data that will be submitted to the create function - * @return zero when the new node was created, non-zero on allocation failure - * @see cxTreeInsert() + * @return the added node or @c NULL when the allocation failed + * @see cxTreeAdd() + */ +CX_EXTERN CX_NONNULL +void *cxTreeAddData(CxTree *tree, void *parent, const void *data); + +/** + * Creates a new node and adds it to the tree. + * + * @param tree the tree + * @param parent the parent node of the new node + * @return the added node or @c NULL when the allocation failed */ -cx_attr_nonnull -CX_EXPORT int cxTreeAddChild(CxTree *tree, void *parent, const void *data); +CX_EXTERN CX_NODISCARD CX_NONNULL +void *cxTreeCreateNode(CxTree *tree, void *parent); + +/** + * Creates a new root node or returns the existing root node. + * + * @param tree the tree + * @return the new root node, the existing root node, or @c NULL when the allocation failed + * @see cxTreeCreateRootData() + */ +CX_EXTERN CX_NODISCARD CX_NONNULL +void *cxTreeCreateRoot(CxTree *tree); + +/** + * Creates a new root node or uses the existing root node and writes the specified data to that node. + * + * @note This function immediately returns @c NULL when @c loc_data was not initialized with a positive value. + * + * @param tree the tree + * @param data the data for the root node + * @return the new root node, the existing root node, + * or @c NULL when the allocation failed or the data location is not known + * @see cxTreeCreateRoot() + */ +CX_EXTERN CX_NODISCARD CX_NONNULL +void *cxTreeCreateRootData(CxTree *tree, const void *data); + +/** + * Exchanges the root of the tree. + * + * @attention The old tree nodes might need to be deallocated by the caller. + * On the other hand, when the tree has destructors registered, keep in mind + * that they will be applied to the new tree. + * In particular, using cxTreeCreate() with a @c NULL root and setting the + * root with this function is @em not equivalent to creating the tree with + * a reference to an existing root because trees created without a root will + * have destructors registered. + * + * @param tree the tree + * @param new_root the new root node + * @return the old root node (or @c NULL when the tree was empty) + */ +CX_EXTERN CX_NONNULL_ARG(1) CX_NODISCARD +void *cxTreeSetRoot(CxTree *tree, void *new_root); /** * A function that is invoked when a node needs to be re-linked to a new parent. @@ -1158,8 +814,8 @@ typedef void (*cx_tree_relink_func)( * node * @return zero on success, non-zero if @p node is the root node of the tree */ -cx_attr_nonnull_arg(1, 2) -CX_EXPORT int cxTreeRemoveNode(CxTree *tree, void *node, cx_tree_relink_func relink_func); +CX_EXTERN CX_NONNULL_ARG(1, 2) +int cxTreeRemoveNode(CxTree *tree, void *node, cx_tree_relink_func relink_func); /** * Removes a node and its subtree from the tree. @@ -1172,8 +828,8 @@ CX_EXPORT int cxTreeRemoveNode(CxTree *tree, void *node, cx_tree_relink_func rel * @param tree the tree * @param node the node to remove */ -cx_attr_nonnull -CX_EXPORT void cxTreeRemoveSubtree(CxTree *tree, void *node); +CX_EXTERN CX_NONNULL +void cxTreeRemoveSubtree(CxTree *tree, void *node); /** * Destroys a node and re-links its children to its former parent. @@ -1193,11 +849,7 @@ CX_EXPORT void cxTreeRemoveSubtree(CxTree *tree, void *node); * node * @return zero on success, non-zero if @p node is the root node of the tree */ -cx_attr_nonnull_arg(1, 2) -CX_EXPORT int cxTreeDestroyNode(CxTree *tree, void *node, cx_tree_relink_func relink_func); - -#ifdef __cplusplus -} // extern "C" -#endif +CX_EXTERN CX_NONNULL_ARG(1, 2) +int cxTreeDestroyNode(CxTree *tree, void *node, cx_tree_relink_func relink_func); #endif //UCX_TREE_H diff --git a/ucx/hash_key.c b/ucx/hash_key.c index f58c690..5884b1f 100644 --- a/ucx/hash_key.c +++ b/ucx/hash_key.c @@ -63,14 +63,14 @@ void cx_hash_murmur(CxHashKey *key) { switch (len) { case 3: h ^= (data[i + 2] & 0xFF) << 16; - cx_attr_fallthrough; + CX_FALLTHROUGH; case 2: h ^= (data[i + 1] & 0xFF) << 8; - cx_attr_fallthrough; + CX_FALLTHROUGH; case 1: h ^= (data[i + 0] & 0xFF); h *= m; - cx_attr_fallthrough; + CX_FALLTHROUGH; default: // do nothing ; } @@ -82,56 +82,6 @@ void cx_hash_murmur(CxHashKey *key) { key->hash = h; } - -uint32_t cx_hash_u32(uint32_t x) { - x = ((x >> 16) ^ x) * 0x45d9f3bu; - x = ((x >> 16) ^ x) * 0x45d9f3bu; - x = (x >> 16) ^ x; - return x; -} - -uint64_t cx_hash_u64(uint64_t x) { - x = (x ^ (x >> 30)) * UINT64_C(0xbf58476d1ce4e5b9); - x = (x ^ (x >> 27)) * UINT64_C(0x94d049bb133111eb); - x = x ^ (x >> 31); - return x; -} - -CxHashKey cx_hash_key_str(const char *str) { - CxHashKey key; - key.data = str; - key.len = str == NULL ? 0 : strlen(str); - cx_hash_murmur(&key); - return key; -} - -CxHashKey cx_hash_key_ustr(unsigned const char *str) { - CxHashKey key; - key.data = str; - key.len = str == NULL ? 0 : strlen((const char*)str); - cx_hash_murmur(&key); - return key; -} - -CxHashKey cx_hash_key_cxstr(cxstring str) { - return cx_hash_key(str.ptr, str.length); -} - -CxHashKey cx_hash_key_mutstr(cxmutstr str) { - return cx_hash_key(str.ptr, str.length); -} - -CxHashKey cx_hash_key_bytes( - const unsigned char *bytes, - size_t len -) { - CxHashKey key; - key.data = bytes; - key.len = len; - cx_hash_murmur(&key); - return key; -} - CxHashKey cx_hash_key( const void *obj, size_t len @@ -143,22 +93,6 @@ CxHashKey cx_hash_key( return key; } -CxHashKey cx_hash_key_u32(uint32_t x) { - CxHashKey key; - key.data = NULL; - key.len = 0; - key.hash = cx_hash_u32(x); - return key; -} - -CxHashKey cx_hash_key_u64(uint64_t x) { - CxHashKey key; - key.data = NULL; - key.len = 0; - key.hash = cx_hash_u64(x); - return key; -} - int cx_hash_key_cmp(const void *l, const void *r) { const CxHashKey *left = l; const CxHashKey *right = r; diff --git a/ucx/json.c b/ucx/json.c index 2d9cf70..b9b3d7c 100644 --- a/ucx/json.c +++ b/ucx/json.c @@ -98,21 +98,21 @@ static CxJsonTokenType token_numbertype(const char *content, size_t length) { static CxJsonToken token_create(CxJson *json, bool isstring, size_t start, size_t end) { cxmutstr str = cx_mutstrn(json->buffer.space + start, end - start); bool allocated = false; - if (json->uncompleted.tokentype != CX_JSON_NO_TOKEN) { + if (json->uncompleted_tokentype != CX_JSON_NO_TOKEN) { allocated = true; - str = cx_strcat_m(json->uncompleted.content, 1, str); - if (str.ptr == NULL) { // LCOV_EXCL_START - return (CxJsonToken){CX_JSON_NO_TOKEN, false, {NULL, 0}}; - } // LCOV_EXCL_STOP + str = cx_strcat(json->uncompleted_content, 1, str); + if (str.ptr == NULL) { + return (CxJsonToken){CX_JSON_NO_TOKEN, false, CX_NULLSTR}; // LCOV_EXCL_LINE + } + json->uncompleted_content = CX_NULLSTR; + json->uncompleted_tokentype = CX_JSON_NO_TOKEN; } - json->uncompleted = (CxJsonToken){0}; CxJsonTokenType ttype; if (isstring) { ttype = CX_JSON_TOKEN_STRING; } else { - cxstring s = cx_strcast(str); - if (!cx_strcmp(s, "true") || !cx_strcmp(s, "false") - || !cx_strcmp(s, "null")) { + if (!cx_strcmp(str, "true") || !cx_strcmp(str, "false") + || !cx_strcmp(str, "null")) { ttype = CX_JSON_TOKEN_LITERAL; } else { ttype = token_numbertype(str.ptr, str.length); @@ -122,7 +122,7 @@ static CxJsonToken token_create(CxJson *json, bool isstring, size_t start, size_ if (allocated) { cx_strfree(&str); } - return (CxJsonToken){CX_JSON_TOKEN_ERROR, false, {NULL, 0}}; + return (CxJsonToken){CX_JSON_TOKEN_ERROR, false, CX_NULLSTR}; } return (CxJsonToken){ttype, allocated, str}; } @@ -162,16 +162,16 @@ static CxJsonTokenType char2ttype(char c) { static enum cx_json_status token_parse_next(CxJson *json, CxJsonToken *result) { // check if there is data in the buffer if (cxBufferEof(&json->buffer)) { - return json->uncompleted.tokentype == CX_JSON_NO_TOKEN ? + return json->uncompleted_tokentype == CX_JSON_NO_TOKEN ? CX_JSON_NO_DATA : CX_JSON_INCOMPLETE_DATA; } // current token type and start index - CxJsonTokenType ttype = json->uncompleted.tokentype; + CxJsonTokenType ttype = json->uncompleted_tokentype; size_t token_part_start = json->buffer.pos; bool escape_end_of_string = ttype == CX_JSON_TOKEN_STRING - && json->uncompleted.content.ptr[json->uncompleted.content.length-1] == '\\'; + && cx_strat(json->uncompleted_content, -1) == '\\'; for (size_t i = json->buffer.pos; i < json->buffer.size; i++) { char c = json->buffer.space[i]; @@ -189,7 +189,7 @@ static enum cx_json_status token_parse_next(CxJson *json, CxJsonToken *result) { } else if (ctype != CX_JSON_NO_TOKEN) { // single-char token json->buffer.pos = i + 1; - *result = (CxJsonToken){ctype, false, {NULL, 0}}; + *result = (CxJsonToken){ctype, false, CX_NULLSTR}; return CX_JSON_NO_ERROR; } else { ttype = CX_JSON_TOKEN_LITERAL; // number or literal @@ -232,31 +232,25 @@ static enum cx_json_status token_parse_next(CxJson *json, CxJsonToken *result) { return CX_JSON_NO_DATA; } else { // uncompleted token - size_t uncompleted_len = json->buffer.size - token_part_start; - if (json->uncompleted.tokentype == CX_JSON_NO_TOKEN) { - // current token is uncompleted - // save current token content - CxJsonToken uncompleted = { - ttype, true, - cx_strdup(cx_strn(json->buffer.space + token_part_start, uncompleted_len)) - }; - if (uncompleted.content.ptr == NULL) { + cxstring uncompleted = cx_strn(json->buffer.space + token_part_start, json->buffer.size - token_part_start); + if (json->uncompleted_tokentype == CX_JSON_NO_TOKEN) { + assert(json->uncompleted_content.ptr == NULL); + json->uncompleted_content = cx_strdup(uncompleted); + if (json->uncompleted_content.ptr == NULL) { return CX_JSON_BUFFER_ALLOC_FAILED; // LCOV_EXCL_LINE } - json->uncompleted = uncompleted; + json->uncompleted_tokentype = ttype; } else { - // previously we also had an uncompleted token + // previously we already had an uncompleted token // combine the uncompleted token with the current token - assert(json->uncompleted.allocated); - cxmutstr str = cx_strcat_m(json->uncompleted.content, 1, - cx_strn(json->buffer.space + token_part_start, uncompleted_len)); - if (str.ptr == NULL) { + cxmutstr s = cx_strcat(json->uncompleted_content, 1, uncompleted); + if (s.ptr == NULL) { return CX_JSON_BUFFER_ALLOC_FAILED; // LCOV_EXCL_LINE } - json->uncompleted.content = str; + json->uncompleted_content = s; } // advance the buffer position - we saved the stuff in the uncompleted token - json->buffer.pos += uncompleted_len; + json->buffer.pos += uncompleted.length; return CX_JSON_INCOMPLETE_DATA; } } @@ -564,7 +558,8 @@ void cxJsonDestroy(CxJson *json) { } cxJsonValueFree(json->parsed); json->parsed = NULL; - token_destroy(&json->uncompleted); + json->uncompleted_tokentype = CX_JSON_NO_TOKEN; + cx_strfree(&json->uncompleted_content); cx_strfree_a(json->allocator, &json->uncompleted_member_name); } @@ -1432,14 +1427,14 @@ static cxmutstr cx_json_to_string(CxJsonValue *value, const CxAllocator *allocat CxBuffer buffer; if (cxBufferInit(&buffer, allocator, NULL, 128, CX_BUFFER_AUTO_EXTEND | CX_BUFFER_DO_NOT_FREE)) { - return (cxmutstr){NULL, 0}; + return CX_NULLSTR; // LCOV_EXCL_LINE } if (cx_json_write_rec(&buffer, value, cxBufferWriteFunc, writer, 0) || cxBufferTerminate(&buffer)) { // LCOV_EXCL_START buffer.flags &= ~CX_BUFFER_DO_NOT_FREE; cxBufferDestroy(&buffer); - return (cxmutstr){NULL, 0}; + return CX_NULLSTR; // LCOV_EXCL_STOP } else { cxmutstr str = cx_bstr_m(&buffer); @@ -1490,8 +1485,7 @@ int cxJsonCompare(const CxJsonValue *json, const CxJsonValue *other) { return cx_vcmp_double(json->number, cxJsonAsDouble(other)); case CX_JSON_LITERAL: return json->literal == other->literal ? 0 : -1; - default: - // LCOV_EXCL_START + default: // LCOV_EXCL_START // unreachable assert(false); return -1; @@ -1504,7 +1498,7 @@ CxJsonValue* cxJsonClone(const CxJsonValue* value, const CxAllocator* allocator) } CxJsonValue* cx_json_clone_func(CxJsonValue* target, const CxJsonValue* source, - const CxAllocator* allocator, cx_attr_unused void *data) { + const CxAllocator* allocator, CX_UNUSED void *data) { if (source == NULL || source->type == CX_JSON_NOTHING) { return &cx_json_value_nothing; } @@ -1516,7 +1510,8 @@ CxJsonValue* cx_json_clone_func(CxJsonValue* target, const CxJsonValue* source, return ret; \ } else { \ *target = *ret; \ - cxFree(allocator, ret); \ + ret->type = CX_JSON_UNINITIALIZED; \ + cxJsonValueFree(ret); \ return target; \ } \ } @@ -1540,8 +1535,7 @@ CxJsonValue* cx_json_clone_func(CxJsonValue* target, const CxJsonValue* source, arr->array.size = elem_count; for (size_t i = 0 ; i < elem_count ; i++) { CxJsonValue *e = cx_json_clone_func(NULL, source->array.data[i], allocator, NULL); - if (e == NULL) { - // LCOV_EXCL_START + if (e == NULL) { // LCOV_EXCL_START cxJsonValueFree(arr); return NULL; // LCOV_EXCL_STOP @@ -1558,8 +1552,7 @@ CxJsonValue* cx_json_clone_func(CxJsonValue* target, const CxJsonValue* source, return_value(cxJsonCreateNumber(allocator, source->number)); case CX_JSON_LITERAL: return_value(cxJsonCreateLiteral(allocator, source->literal)); - default: - // LCOV_EXCL_START + default: // LCOV_EXCL_START // unreachable assert(false); return NULL; diff --git a/ucx/kv_list.c b/ucx/kv_list.c index a2a520f..d1ee515 100644 --- a/ucx/kv_list.c +++ b/ucx/kv_list.c @@ -515,7 +515,7 @@ static CxMapIterator cx_kvl_map_iterator(const CxMap *map, enum cx_map_iterator_ } static int cx_kvl_change_capacity(struct cx_list_s *list, - cx_attr_unused size_t cap) { + CX_UNUSED size_t cap) { // since our backing list is a linked list, we don't need to do much here, // but rehashing the map is quite useful cx_kv_list *kv_list = (cx_kv_list*)list; diff --git a/ucx/linked_list.c b/ucx/linked_list.c index 0ce9a22..5ee5ade 100644 --- a/ucx/linked_list.c +++ b/ucx/linked_list.c @@ -1384,8 +1384,8 @@ CxList *cxLinkedListCreate( void cx_linked_list_extra_data(cx_linked_list *list, size_t len) { list->extra_data_len = len; - off_t loc_extra = list->loc_data + list->base.collection.elem_size; + off_t loc_extra = list->loc_data + (off_t) list->base.collection.elem_size; size_t alignment = alignof(void*); - size_t padding = alignment - (loc_extra % alignment); - list->loc_extra = loc_extra + padding; + size_t padding = alignment - ((size_t)loc_extra % alignment); + list->loc_extra = loc_extra + (off_t) padding; } diff --git a/ucx/list.c b/ucx/list.c index c1e779b..769a9cc 100644 --- a/ucx/list.c +++ b/ucx/list.c @@ -63,33 +63,33 @@ int cx_list_compare_wrapper(const void *l, const void *r, void *c) { // -static void cx_emptyl_noop(cx_attr_unused CxList *list) { +static void cx_emptyl_noop(CX_UNUSED CxList *list) { // this is a noop, but MUST be implemented } static void *cx_emptyl_at( - cx_attr_unused const struct cx_list_s *list, - cx_attr_unused size_t index + CX_UNUSED const struct cx_list_s *list, + CX_UNUSED size_t index ) { return NULL; } static size_t cx_emptyl_find_remove( - cx_attr_unused struct cx_list_s *list, - cx_attr_unused const void *elem, - cx_attr_unused bool remove + CX_UNUSED struct cx_list_s *list, + CX_UNUSED const void *elem, + CX_UNUSED bool remove ) { return 0; } -static bool cx_emptyl_iter_valid(cx_attr_unused const void *iter) { +static bool cx_emptyl_iter_valid(CX_UNUSED const void *iter) { return false; } static CxIterator cx_emptyl_iterator( const struct cx_list_s *list, size_t index, - cx_attr_unused bool backwards + CX_UNUSED bool backwards ) { CxIterator iter = {0}; iter.src_handle = (void*) list; diff --git a/ucx/map.c b/ucx/map.c index 7eb561f..eeb98c2 100644 --- a/ucx/map.c +++ b/ucx/map.c @@ -33,24 +33,24 @@ // -static void cx_empty_map_noop(cx_attr_unused CxMap *map) { +static void cx_empty_map_noop(CX_UNUSED CxMap *map) { // this is a noop, but MUST be implemented } static void *cx_empty_map_get( - cx_attr_unused const CxMap *map, - cx_attr_unused CxHashKey key + CX_UNUSED const CxMap *map, + CX_UNUSED CxHashKey key ) { return NULL; } -static bool cx_empty_map_iter_valid(cx_attr_unused const void *iter) { +static bool cx_empty_map_iter_valid(CX_UNUSED const void *iter) { return false; } static CxMapIterator cx_empty_map_iterator( const struct cx_map_s *map, - cx_attr_unused enum cx_map_iterator_type type + CX_UNUSED enum cx_map_iterator_type type ) { CxMapIterator iter = {0}; iter.map = (CxMap*) map; diff --git a/ucx/properties.c b/ucx/properties.c index 21611b7..5a32828 100644 --- a/ucx/properties.c +++ b/ucx/properties.c @@ -112,7 +112,7 @@ CxPropertiesStatus cxPropertiesNext( cxstring nl = cx_strchr(input, '\n'); while (nl.length > 0) { // check for line continuation - char previous = nl.ptr > input.ptr ? nl.ptr[-1] : prop->buffer.space[prop->buffer.size-1]; + char previous = nl.ptr > input.ptr ? nl.ptr[-1] : cx_strat(cx_bstr(&prop->buffer), -1); if (previous == continuation) { // this nl is a line continuation, check the next newline nl = cx_strchr(cx_strsubs(nl, 1), '\n'); @@ -128,7 +128,7 @@ CxPropertiesStatus cxPropertiesNext( if (cxBufferAppend(input.ptr, 1, len_until_nl, &prop->buffer) < len_until_nl) { - return CX_PROPERTIES_BUFFER_ALLOC_FAILED; + return CX_PROPERTIES_BUFFER_ALLOC_FAILED; // LCOV_EXCL_LINE } // advance the position in the input buffer @@ -197,7 +197,7 @@ CxPropertiesStatus cxPropertiesNext( cxBufferReset(&prop->buffer); } if (cxBufferAppend(buf, 1, len, &prop->buffer) < len) { - return CX_PROPERTIES_BUFFER_ALLOC_FAILED; + return CX_PROPERTIES_BUFFER_ALLOC_FAILED; // LCOV_EXCL_LINE } // reset the input buffer (make way for a re-fill) cxBufferReset(&prop->input); @@ -256,7 +256,7 @@ CxPropertiesStatus cxPropertiesNext( prop->buffer.size = 0; prop->buffer.pos = 0; if (cxBufferWrite(val.ptr, 1, val.length, &prop->buffer) != val.length) { - return CX_PROPERTIES_BUFFER_ALLOC_FAILED; + return CX_PROPERTIES_BUFFER_ALLOC_FAILED; // LCOV_EXCL_LINE } val.ptr = prop->buffer.space; ptr = prop->buffer.space; @@ -338,12 +338,12 @@ CxPropertiesStatus cx_properties_load(const CxAllocator *allocator, } // initialize the parser - char linebuf[cx_properties_load_buf_size]; - char fillbuf[cx_properties_load_fill_size]; + char linebuf[CX_PROPERTIES_LOAD_BUF_SIZE]; + char fillbuf[CX_PROPERTIES_LOAD_FILL_SIZE]; CxPropertiesStatus status; CxProperties parser; cxPropertiesInit(&parser, config); - cxPropertiesUseStack(&parser, linebuf, cx_properties_load_buf_size); + cxPropertiesUseStack(&parser, linebuf, CX_PROPERTIES_LOAD_BUF_SIZE); // read/fill/parse loop status = CX_PROPERTIES_NO_DATA; @@ -351,15 +351,19 @@ CxPropertiesStatus cx_properties_load(const CxAllocator *allocator, while (true) { size_t r = fread(fillbuf, 1, cx_properties_load_fill_size, f); if (ferror(f)) { + // LCOV_EXCL_START status = CX_PROPERTIES_FILE_ERROR; break; + // LCOV_EXCL_STOP } if (r == 0) { break; } if (cxPropertiesFilln(&parser, fillbuf, r)) { + // LCOV_EXCL_START status = CX_PROPERTIES_BUFFER_ALLOC_FAILED; break; + // LCOV_EXCL_STOP } cxstring key, value; while (true) { @@ -368,15 +372,19 @@ CxPropertiesStatus cx_properties_load(const CxAllocator *allocator, break; } else { cxmutstr v = cx_strdup_a(allocator, value); + // LCOV_EXCL_START if (v.ptr == NULL) { status = CX_PROPERTIES_MAP_ERROR; break; } + // LCOV_EXCL_STOP void *mv = use_cstring ? (void*)v.ptr : &v; if (cxMapPut(target, key, mv)) { + // LCOV_EXCL_START cx_strfree(&v); status = CX_PROPERTIES_MAP_ERROR; break; + // LCOV_EXCL_STOP } keys_found++; } diff --git a/ucx/string.c b/ucx/string.c index e9bb43d..70c0f03 100644 --- a/ucx/string.c +++ b/ucx/string.c @@ -41,7 +41,12 @@ #include #ifdef _WIN32 -#define cx_strcasecmp_impl _strnicmp +static int cx_fixed_strnicmp(const char* s1, const char* s2, size_t count) { + // Microsoft's implementation crashes when count == 0 and either string is NULL + if (count == 0) return 0; + return _strnicmp(s1, s2, count); +} +#define cx_strcasecmp_impl cx_fixed_strnicmp #else #include #define cx_strcasecmp_impl strncasecmp @@ -99,13 +104,19 @@ size_t cx_strlen( return size; } -cxmutstr cx_strcat_ma( +cxmutstr cx_strcat_a( const CxAllocator *alloc, cxmutstr str, size_t count, ... ) { - if (count == 0) return str; + if (count == 0) { + if (cxReallocate(alloc, &str.ptr, str.length + 1)) { + return CX_NULLSTR; // LCOV_EXCL_LINE + } + str.ptr[str.length] = '\0'; + return str; + } va_list ap; va_start(ap, count); va_list ap2; @@ -125,21 +136,16 @@ cxmutstr cx_strcat_ma( if (overflow) { va_end(ap2); errno = EOVERFLOW; - return (cxmutstr) { NULL, 0 }; + return CX_NULLSTR; } - // reallocate or create new string - char *newstr; - if (str.ptr == NULL) { - newstr = cxMalloc(alloc, slen + 1); - } else { - newstr = cxRealloc(alloc, str.ptr, slen + 1); - } - if (newstr == NULL) { // LCOV_EXCL_START + // reallocate or create a new string + if (cxReallocate(alloc, &str.ptr, slen + 1)) { + // LCOV_EXCL_START va_end(ap2); - return (cxmutstr) {NULL, 0}; - } // LCOV_EXCL_STOP - str.ptr = newstr; + return CX_NULLSTR; + // LCOV_EXCL_STOP + } // concatenate strings size_t pos = str.length; @@ -157,21 +163,14 @@ cxmutstr cx_strcat_ma( return str; } -cxstring cx_strsubs( +cxstring cx_strsubs_( cxstring string, size_t start ) { - return cx_strsubsl(string, start, string.length - start); + return cx_strsubsl_(string, start, string.length); } -cxmutstr cx_strsubs_m( - cxmutstr string, - size_t start -) { - return cx_strsubsl_m(string, start, string.length - start); -} - -cxstring cx_strsubsl( +cxstring cx_strsubsl_( cxstring string, size_t start, size_t length @@ -188,16 +187,7 @@ cxstring cx_strsubsl( return (cxstring) {string.ptr + start, length}; } -cxmutstr cx_strsubsl_m( - cxmutstr string, - size_t start, - size_t length -) { - cxstring result = cx_strsubsl(cx_strcast(string), start, length); - return (cxmutstr) {(char *) result.ptr, result.length}; -} - -cxstring cx_strchr( +cxstring cx_strchr_( cxstring string, int chr ) { @@ -206,15 +196,7 @@ cxstring cx_strchr( return (cxstring) {ret, string.length - (ret - string.ptr)}; } -cxmutstr cx_strchr_m( - cxmutstr string, - int chr -) { - cxstring result = cx_strchr(cx_strcast(string), chr); - return (cxmutstr) {(char *) result.ptr, result.length}; -} - -cxstring cx_strrchr( +cxstring cx_strrchr_( cxstring string, int chr ) { @@ -235,14 +217,6 @@ cxstring cx_strrchr( #endif } -cxmutstr cx_strrchr_m( - cxmutstr string, - int chr -) { - cxstring result = cx_strrchr(cx_strcast(string), chr); - return (cxmutstr) {(char *) result.ptr, result.length}; -} - #ifndef CX_STRSTR_SBO_SIZE #define CX_STRSTR_SBO_SIZE 128 #endif @@ -318,14 +292,6 @@ cxstring cx_strstr_(cxstring haystack, cxstring needle) { return result; } -cxmutstr cx_strstr_m_( - cxmutstr haystack, - cxstring needle -) { - cxstring result = cx_strstr(cx_strcast(haystack), needle); - return (cxmutstr) {(char *) result.ptr, result.length}; -} - size_t cx_strsplit_( cxstring string, cxstring delim, @@ -508,23 +474,18 @@ cxmutstr cx_strdup_a_( return result; } -cxstring cx_strtrim(cxstring string) { +cxstring cx_strtrim_(cxstring string) { cxstring result = string; - while (result.length > 0 && isspace((unsigned char)(result.ptr[0]))) { + while (isspace((unsigned char)cx_strat(result, 0))) { result.ptr++; result.length--; } - while (result.length > 0 && isspace((unsigned char)result.ptr[result.length - 1])) { + while (isspace((unsigned char)cx_strat(result, -1))) { result.length--; } return result; } -cxmutstr cx_strtrim_m(cxmutstr string) { - cxstring result = cx_strtrim(cx_strcast(string)); - return (cxmutstr) {(char *) result.ptr, result.length}; -} - bool cx_strprefix_( cxstring string, cxstring prefix @@ -649,7 +610,7 @@ CxStrtokCtx cx_strtok_( return ctx; } -bool cx_strtok_next( +bool cx_strtok_next_( CxStrtokCtx *ctx, cxstring *token ) { @@ -692,13 +653,6 @@ bool cx_strtok_next( return true; } -bool cx_strtok_next_m( - CxStrtokCtx *ctx, - cxmutstr *token -) { - return cx_strtok_next(ctx, (cxstring *) token); -} - void cx_strtok_delim( CxStrtokCtx *ctx, const cxstring *delim, diff --git a/ucx/tree.c b/ucx/tree.c index de3ab2a..37dab50 100644 --- a/ucx/tree.c +++ b/ucx/tree.c @@ -29,6 +29,7 @@ #include "cx/tree.h" #include +#include #define CX_TREE_PTR(cur, off) (*(void**)(((char*)(cur))+(off))) #define tree_parent(node) CX_TREE_PTR(node, loc_parent) @@ -37,36 +38,14 @@ #define tree_prev(node) CX_TREE_PTR(node, loc_prev) #define tree_next(node) CX_TREE_PTR(node, loc_next) -#define cx_tree_ptr_locations \ - loc_parent, loc_children, loc_last_child, loc_prev, loc_next - -#define cx_tree_node_layout(tree) \ +#define tree_layout(tree) \ (tree)->loc_parent,\ (tree)->loc_children,\ (tree)->loc_last_child,\ (tree)->loc_prev, \ (tree)->loc_next -static void cx_tree_zero_pointers( - void *node, - ptrdiff_t loc_parent, - ptrdiff_t loc_children, - ptrdiff_t loc_last_child, - ptrdiff_t loc_prev, - ptrdiff_t loc_next -) { - tree_parent(node) = NULL; - if (loc_prev >= 0) { - tree_prev(node) = NULL; - } - tree_next(node) = NULL; - tree_children(node) = NULL; - if (loc_last_child >= 0) { - tree_last_child(node) = NULL; - } -} - -void cx_tree_link( +void cx_tree_add( void *parent, void *node, ptrdiff_t loc_parent, @@ -82,7 +61,8 @@ void cx_tree_link( void *current_parent = tree_parent(node); if (current_parent == parent) return; if (current_parent != NULL) { - cx_tree_unlink(node, cx_tree_ptr_locations); + cx_tree_remove(node, loc_parent, loc_children, + loc_last_child, loc_prev, loc_next); } if (tree_children(parent) == NULL) { @@ -128,7 +108,7 @@ static void *cx_tree_node_prev( } } -void cx_tree_unlink( +void cx_tree_remove( void *node, ptrdiff_t loc_parent, ptrdiff_t loc_children, @@ -175,21 +155,20 @@ void cx_tree_unlink( } } -int cx_tree_search( - const void *root, - size_t depth, - const void *node, - cx_tree_search_func sfunc, - void **result, - ptrdiff_t loc_children, - ptrdiff_t loc_next -) { +int cx_tree_search(const void *root, size_t max_depth, + const void *data, cx_tree_search_func sfunc, void **result, + ptrdiff_t loc_children, ptrdiff_t loc_next) { // help avoiding bugs due to uninitialized memory assert(result != NULL); *result = NULL; + // NULL root? exit! + if (root == NULL) { + return -1; + } + // remember return value for best match - int ret = sfunc(root, node); + int ret = sfunc(root, data); if (ret < 0) { // not contained, exit return -1; @@ -201,13 +180,13 @@ int cx_tree_search( } // when depth is one, we are already done - if (depth == 1) { + if (max_depth == 1) { return ret; } // special case: indefinite depth - if (depth == 0) { - depth = SIZE_MAX; + if (max_depth == 0) { + max_depth = SIZE_MAX; } // create an iterator @@ -221,7 +200,7 @@ int cx_tree_search( // loop through the remaining tree cx_foreach(void *, elem, iter) { // investigate the current node - int ret_elem = sfunc(elem, node); + int ret_elem = sfunc(elem, data); if (ret_elem == 0) { // if found, exit the search *result = elem; @@ -237,47 +216,30 @@ int cx_tree_search( } // when we reached the max depth, skip the subtree - if (iter.depth == depth) { + if (iter.depth == max_depth) { cxTreeIteratorContinue(iter); } } - // dispose the iterator as we might have exited the loop early + // dispose of the iterator as we might have exited the loop early cxTreeIteratorDispose(&iter); assert(ret < 0 || *result != NULL); return ret; } -int cx_tree_search_data( - const void *root, - size_t depth, - const void *data, - cx_tree_search_data_func sfunc, - void **result, - ptrdiff_t loc_children, - ptrdiff_t loc_next -) { - // it is basically the same implementation - return cx_tree_search( - root, depth, data, - (cx_tree_search_func) sfunc, - result, - loc_children, loc_next); -} - static bool cx_tree_iter_valid(const void *it) { - const struct cx_tree_iterator_s *iter = it; + const CxTreeIterator *iter = it; return iter->node != NULL; } static void *cx_tree_iter_current(const void *it) { - const struct cx_tree_iterator_s *iter = it; + const CxTreeIterator *iter = it; return iter->node; } static void cx_tree_iter_next(void *it) { - struct cx_tree_iterator_s *iter = it; + CxTreeIterator *iter = it; ptrdiff_t const loc_next = iter->loc_next; ptrdiff_t const loc_children = iter->loc_children; // protect us from misuse @@ -350,16 +312,16 @@ static void cx_tree_iter_next(void *it) { } } else { // node has children, push the first child onto the stack and enter it - if (iter->stack_size >= iter->stack_capacity) { + if (iter->depth >= iter->stack_capacity) { const size_t newcap = iter->stack_capacity + 8; - if (cxReallocArrayDefault(&iter->stack, newcap, sizeof(void*))) { + if (cxReallocateArrayDefault(&iter->stack, newcap, sizeof(void*))) { // we cannot return an error in this function abort(); // LCOV_EXCL_LINE } iter->stack_capacity = newcap; } - iter->stack[iter->stack_size] = children; - iter->stack_size++; + iter->stack[iter->depth] = children; + iter->depth++; iter->node = children; iter->counter++; } @@ -371,55 +333,56 @@ CxTreeIterator cx_tree_iterator( ptrdiff_t loc_children, ptrdiff_t loc_next ) { - CxTreeIterator iter; - iter.loc_children = loc_children; - iter.loc_next = loc_next; - iter.visit_on_exit = visit_on_exit; + CxTreeIterator ret; + ret.use_dfs = true; + ret.loc_children = loc_children; + ret.loc_next = loc_next; + ret.visit_on_exit = visit_on_exit; // initialize members - iter.node_next = NULL; - iter.exiting = false; - iter.skip = false; + ret.node_next = NULL; + ret.exiting = false; + ret.skip = false; // assign base iterator functions - iter.base.allow_remove = false; - iter.base.remove = false; - iter.base.current_impl = NULL; - iter.base.valid = cx_tree_iter_valid; - iter.base.next = cx_tree_iter_next; - iter.base.current = cx_tree_iter_current; + ret.base.allow_remove = false; + ret.base.remove = false; + ret.base.current_impl = NULL; + ret.base.valid = cx_tree_iter_valid; + ret.base.next = cx_tree_iter_next; + ret.base.current = cx_tree_iter_current; // visit the root node - iter.node = root; + ret.node = root; if (root != NULL) { - iter.stack_capacity = 16; - iter.stack = cxMallocDefault(sizeof(void *) * 16); - iter.stack[0] = root; - iter.counter = 1; - iter.depth = 1; + ret.stack_capacity = 16; + ret.stack = cxMallocDefault(sizeof(void *) * 16); + ret.stack[0] = root; + ret.counter = 1; + ret.depth = 1; } else { - iter.stack_capacity = 0; - iter.stack = NULL; - iter.counter = 0; - iter.depth = 0; + ret.stack_capacity = 0; + ret.stack = NULL; + ret.counter = 0; + ret.depth = 0; } - return iter; + return ret; } static bool cx_tree_visitor_valid(const void *it) { - const struct cx_tree_visitor_s *iter = it; + const CxTreeIterator *iter = it; return iter->node != NULL; } static void *cx_tree_visitor_current(const void *it) { - const struct cx_tree_visitor_s *iter = it; + const CxTreeIterator *iter = it; return iter->node; } -cx_attr_nonnull +CX_NONNULL static void cx_tree_visitor_enqueue_siblings( - struct cx_tree_visitor_s *iter, void *node, ptrdiff_t loc_next) { + CxTreeIterator *iter, void *node, ptrdiff_t loc_next) { node = tree_next(node); while (node != NULL) { struct cx_tree_visitor_queue_s *q; @@ -434,7 +397,7 @@ static void cx_tree_visitor_enqueue_siblings( } static void cx_tree_visitor_next(void *it) { - struct cx_tree_visitor_s *iter = it; + CxTreeIterator *iter = it; // protect us from misuse if (!iter->base.valid(iter)) return; @@ -488,358 +451,98 @@ static void cx_tree_visitor_next(void *it) { iter->counter++; } -CxTreeVisitor cx_tree_visitor( +CxTreeIterator cx_tree_visitor( void *root, ptrdiff_t loc_children, ptrdiff_t loc_next ) { - CxTreeVisitor iter; - iter.loc_children = loc_children; - iter.loc_next = loc_next; + CxTreeIterator ret; + ret.visit_on_exit = false; + ret.exiting = false; + ret.use_dfs = false; + ret.loc_children = loc_children; + ret.loc_next = loc_next; // initialize members - iter.skip = false; - iter.queue_next = NULL; - iter.queue_last = NULL; + ret.skip = false; + ret.queue_next = NULL; + ret.queue_last = NULL; // assign base iterator functions - iter.base.allow_remove = false; - iter.base.remove = false; - iter.base.current_impl = NULL; - iter.base.valid = cx_tree_visitor_valid; - iter.base.next = cx_tree_visitor_next; - iter.base.current = cx_tree_visitor_current; + ret.base.allow_remove = false; + ret.base.remove = false; + ret.base.current_impl = NULL; + ret.base.valid = cx_tree_visitor_valid; + ret.base.next = cx_tree_visitor_next; + ret.base.current = cx_tree_visitor_current; // visit the root node - iter.node = root; + ret.node = root; if (root != NULL) { - iter.counter = 1; - iter.depth = 1; - } else { - iter.counter = 0; - iter.depth = 0; - } - - return iter; -} - -static void cx_tree_add_link_duplicate( - void *original, void *duplicate, - ptrdiff_t loc_parent, ptrdiff_t loc_children, ptrdiff_t loc_last_child, - ptrdiff_t loc_prev, ptrdiff_t loc_next -) { - void *shared_parent = tree_parent(original); - if (shared_parent == NULL) { - cx_tree_link(original, duplicate, cx_tree_ptr_locations); - } else { - cx_tree_link(shared_parent, duplicate, cx_tree_ptr_locations); - } -} - -static void cx_tree_add_link_new( - void *parent, void *node, cx_tree_search_func sfunc, - ptrdiff_t loc_parent, ptrdiff_t loc_children, ptrdiff_t loc_last_child, - ptrdiff_t loc_prev, ptrdiff_t loc_next -) { - // check the current children one by one, - // if they could be children of the new node - void *child = tree_children(parent); - while (child != NULL) { - void *next = tree_next(child); - - if (sfunc(node, child) > 0) { - // the sibling could be a child -> re-link - cx_tree_link(node, child, cx_tree_ptr_locations); - } - - child = next; - } - - // add new node as new child - cx_tree_link(parent, node, cx_tree_ptr_locations); -} - -int cx_tree_add( - const void *src, - cx_tree_search_func sfunc, - cx_tree_node_create_func cfunc, - void *cdata, - void **cnode, - void *root, - ptrdiff_t loc_parent, - ptrdiff_t loc_children, - ptrdiff_t loc_last_child, - ptrdiff_t loc_prev, - ptrdiff_t loc_next -) { - *cnode = cfunc(src, cdata); - if (*cnode == NULL) return 1; // LCOV_EXCL_LINE - cx_tree_zero_pointers(*cnode, cx_tree_ptr_locations); - - void *match = NULL; - int result = cx_tree_search( - root, - 0, - *cnode, - sfunc, - &match, - loc_children, - loc_next - ); - - if (result < 0) { - // node does not fit into the tree - return non-zero value - return 1; - } else if (result == 0) { - // data already found in the tree, link duplicate - cx_tree_add_link_duplicate(match, *cnode, cx_tree_ptr_locations); + ret.counter = 1; + ret.depth = 1; } else { - // closest match found, add new node - cx_tree_add_link_new(match, *cnode, sfunc, cx_tree_ptr_locations); + ret.counter = 0; + ret.depth = 0; } - return 0; + return ret; } -unsigned int cx_tree_add_look_around_depth = 3; - -size_t cx_tree_add_iter( - struct cx_iterator_base_s *iter, - size_t num, - cx_tree_search_func sfunc, - cx_tree_node_create_func cfunc, - void *cdata, - void **failed, - void *root, - ptrdiff_t loc_parent, - ptrdiff_t loc_children, - ptrdiff_t loc_last_child, - ptrdiff_t loc_prev, - ptrdiff_t loc_next -) { - // erase the failed pointer - *failed = NULL; - - // iter not valid? cancel... - if (!iter->valid(iter)) return 0; - - size_t processed = 0; - void *current_node = root; - const void *elem; - - for (void **eptr; processed < num && - iter->valid(iter) && (eptr = iter->current(iter)) != NULL; - iter->next(iter)) { - elem = *eptr; - - // create the new node - void *new_node = cfunc(elem, cdata); - if (new_node == NULL) return processed; // LCOV_EXCL_LINE - cx_tree_zero_pointers(new_node, cx_tree_ptr_locations); - - // start searching from current node - void *match; - int result; - unsigned int look_around_retries = cx_tree_add_look_around_depth; - cx_tree_add_look_around_retry: - result = cx_tree_search( - current_node, - 0, - new_node, - sfunc, - &match, - loc_children, - loc_next - ); - - if (result < 0) { - // traverse upwards and try to find better parents - void *parent = tree_parent(current_node); - if (parent != NULL) { - if (look_around_retries > 0) { - look_around_retries--; - current_node = parent; - } else { - // look around retries exhausted, start from the root - current_node = root; - } - goto cx_tree_add_look_around_retry; - } else { - // no parents. so we failed - *failed = new_node; - return processed; - } - } else if (result == 0) { - // data already found in the tree, link duplicate - cx_tree_add_link_duplicate(match, new_node, cx_tree_ptr_locations); - // but stick with the original match, in case we needed a new root - current_node = match; - } else { - // closest match found, add new node as child - cx_tree_add_link_new(match, new_node, sfunc, - cx_tree_ptr_locations); - current_node = match; - } - - processed++; +size_t cx_tree_size(void *root, ptrdiff_t loc_children, ptrdiff_t loc_next) { + CxTreeIterator iter = cx_tree_iterator(root, false, loc_children, loc_next); + while (cxIteratorValid(iter)) { + cxIteratorNext(iter); } - return processed; + return iter.counter; } -size_t cx_tree_add_array( - const void *src, - size_t num, - size_t elem_size, - cx_tree_search_func sfunc, - cx_tree_node_create_func cfunc, - void *cdata, - void **failed, - void *root, - ptrdiff_t loc_parent, - ptrdiff_t loc_children, - ptrdiff_t loc_last_child, - ptrdiff_t loc_prev, - ptrdiff_t loc_next -) { - // erase failed pointer - *failed = NULL; - - // super special case: zero elements - if (num == 0) { - return 0; - } - - // special case: one element does not need an iterator - if (num == 1) { - void *node; - if (0 == cx_tree_add( - src, sfunc, cfunc, cdata, &node, root, - loc_parent, loc_children, loc_last_child, - loc_prev, loc_next)) { - return 1; - } else { - *failed = node; - return 0; +size_t cx_tree_depth(void *root, ptrdiff_t loc_children, ptrdiff_t loc_next) { + CxTreeIterator iter = cx_tree_iterator(root, false, loc_children, loc_next); + size_t depth = 0; + while (cxIteratorValid(iter)) { + if (iter.depth > depth) { + depth = iter.depth; } + cxIteratorNext(iter); } - - // otherwise, create iterator and hand over to other function - CxIterator iter = cxIterator(src, elem_size, num); - return cx_tree_add_iter(cxIteratorRef(iter), num, sfunc, - cfunc, cdata, failed, root, - loc_parent, loc_children, loc_last_child, - loc_prev, loc_next); -} - -static int cx_tree_default_insert_element( - CxTree *tree, - const void *data -) { - void *node; - if (tree->root == NULL) { - node = tree->node_create(data, tree); - if (node == NULL) return 1; // LCOV_EXCL_LINE - cx_tree_zero_pointers(node, cx_tree_node_layout(tree)); - tree->root = node; - tree->collection.size = 1; - return 0; - } - int result = cx_tree_add(data, tree->search, tree->node_create, - tree, &node, tree->root, cx_tree_node_layout(tree)); - if (0 == result) { - tree->collection.size++; - } else { - cxFree(tree->collection.allocator, node); - } - return result; + return depth; } -static size_t cx_tree_default_insert_many( - CxTree *tree, - CxIteratorBase *iter, - size_t n -) { - size_t ins = 0; - if (!iter->valid(iter)) return 0; - if (tree->root == NULL) { - // use the first element from the iter to create the root node - void **eptr = iter->current(iter); - void *node = tree->node_create(*eptr, tree); - if (node == NULL) return 0; // LCOV_EXCL_LINE - cx_tree_zero_pointers(node, cx_tree_node_layout(tree)); - tree->root = node; - ins = 1; - iter->next(iter); - } - void *failed; - ins += cx_tree_add_iter(iter, n, tree->search, tree->node_create, - tree, &failed, tree->root, cx_tree_node_layout(tree)); - tree->collection.size += ins; - if (ins < n) { - cxFree(tree->collection.allocator, failed); - } - return ins; -} - -static void *cx_tree_default_find( - CxTree *tree, - const void *subtree, - const void *data, - size_t depth -) { - if (tree->root == NULL) return NULL; // LCOV_EXCL_LINE - - void *found; - if (0 == cx_tree_search_data( - subtree, - depth, - data, - tree->search_data, - &found, - tree->loc_children, - tree->loc_next - )) { - return found; - } else { - return NULL; - } -} - -static cx_tree_class cx_tree_default_class = { - cx_tree_default_insert_element, - cx_tree_default_insert_many, - cx_tree_default_find -}; - CxTree *cxTreeCreate(const CxAllocator *allocator, - cx_tree_node_create_func create_func, - cx_tree_search_func search_func, - cx_tree_search_data_func search_data_func, + size_t node_size, size_t elem_size, void *root, ptrdiff_t loc_data, ptrdiff_t loc_parent, ptrdiff_t loc_children, ptrdiff_t loc_last_child, - ptrdiff_t loc_prev, ptrdiff_t loc_next -) { + ptrdiff_t loc_prev, ptrdiff_t loc_next) { + if (allocator == NULL) { allocator = cxDefaultAllocator; } - assert(create_func != NULL); - assert(search_func != NULL); - assert(search_data_func != NULL); CxTree *tree = cxZalloc(allocator, sizeof(CxTree)); if (tree == NULL) return NULL; // LCOV_EXCL_LINE - - tree->cl = &cx_tree_default_class; tree->collection.allocator = allocator; - tree->node_create = create_func; - tree->search = search_func; - tree->search_data = search_data_func; - tree->collection.advanced_destructor = (cx_destructor_func2) cxFree; - tree->collection.destructor_data = (void *) allocator; + + if (elem_size == CX_STORE_POINTERS) { + tree->collection.store_pointer = true; + tree->collection.elem_size = sizeof(void*); + } else { + tree->collection.elem_size = elem_size; + } + + tree->root = root; + tree->node_size = node_size; tree->loc_parent = loc_parent; tree->loc_children = loc_children; tree->loc_last_child = loc_last_child; tree->loc_prev = loc_prev; tree->loc_next = loc_next; + tree->loc_data = loc_data; + + if (root == NULL) { + cxSetAdvancedDestructor(tree, cxFree, (void*)allocator); + } else { + tree->collection.size = cx_tree_size(root, loc_children, loc_next); + } return tree; } @@ -852,97 +555,120 @@ void cxTreeFree(CxTree *tree) { cxFree(tree->collection.allocator, tree); } -CxTree *cxTreeCreateWrapped(const CxAllocator *allocator, void *root, - ptrdiff_t loc_parent, ptrdiff_t loc_children, ptrdiff_t loc_last_child, - ptrdiff_t loc_prev, ptrdiff_t loc_next) { - if (allocator == NULL) { - allocator = cxDefaultAllocator; - } - assert(root != NULL); - - CxTree *tree = cxZalloc(allocator, sizeof(CxTree)); - if (tree == NULL) return NULL; // LCOV_EXCL_LINE - - tree->cl = &cx_tree_default_class; - // set the allocator anyway, just in case... - tree->collection.allocator = allocator; - tree->loc_parent = loc_parent; - tree->loc_children = loc_children; - tree->loc_last_child = loc_last_child; - tree->loc_prev = loc_prev; - tree->loc_next = loc_next; - tree->root = root; - tree->collection.size = cxTreeSubtreeSize(tree, root); - return tree; -} - void cxTreeSetParent(CxTree *tree, void *parent, void *child) { size_t loc_parent = tree->loc_parent; if (tree_parent(child) == NULL) { tree->collection.size++; } - cx_tree_link(parent, child, cx_tree_node_layout(tree)); + cx_tree_add(parent, child, tree_layout(tree)); } -void cxTreeAddChildNode(CxTree *tree, void *parent, void *child) { - cx_tree_link(parent, child, cx_tree_node_layout(tree)); +void cxTreeAddNode(CxTree *tree, void *parent, void *child) { + cx_tree_add(parent, child, tree_layout(tree)); tree->collection.size++; } -int cxTreeAddChild(CxTree *tree, void *parent, const void *data) { - void *node = tree->node_create(data, tree); - if (node == NULL) return 1; // LCOV_EXCL_LINE - cx_tree_zero_pointers(node, cx_tree_node_layout(tree)); - cx_tree_link(parent, node, cx_tree_node_layout(tree)); +void *cxTreeCreateNode(CxTree *tree, void *parent) { + void *node = cxZalloc(tree->collection.allocator, tree->node_size); + if (node == NULL) return NULL; // LCOV_EXCL_LINE + cx_tree_add(parent, node, tree_layout(tree)); tree->collection.size++; - return 0; + return node; } -int cxTreeInsert(CxTree *tree, const void *data) { - return tree->cl->insert_element(tree, data); +void *cxTreeAddData(CxTree *tree, void *parent, const void *data) { + if (tree->loc_data < 0) return NULL; + + void *node = cxTreeCreateNode(tree, parent); + if (node == NULL) return NULL; // LCOV_EXCL_LINE + + char *dst = node; + dst += tree->loc_data; + const void *src = cxCollectionStoresPointers(tree) ? (const void*)&data : data; + memcpy(dst, src, tree->collection.elem_size); + + return node; } -size_t cxTreeInsertIter(CxTree *tree, CxIteratorBase *iter, size_t n) { - return tree->cl->insert_many(tree, iter, n); +void *cxTreeCreateRoot(CxTree *tree) { + if (tree->root != NULL) { + return tree->root; + } + + void *node = cxZalloc(tree->collection.allocator, tree->node_size); + if (node == NULL) return NULL; // LCOV_EXCL_LINE + tree->root = node; + tree->collection.size = 1; + return node; } -size_t cxTreeInsertArray(CxTree *tree, const void *data, size_t elem_size, size_t n) { - if (n == 0) return 0; - if (n == 1) return 0 == cxTreeInsert(tree, data) ? 1 : 0; - CxIterator iter = cxIterator(data, elem_size, n); - return cxTreeInsertIter(tree, cxIteratorRef(iter), n); +void *cxTreeCreateRootData(CxTree *tree, const void *data) { + if (tree->loc_data < 0) return NULL; + + void *node = cxTreeCreateRoot(tree); + if (node == NULL) return NULL; // LCOV_EXCL_LINE + + char *dst = node; + dst += tree->loc_data; + const void *src = cxCollectionStoresPointers(tree) ? (const void*)&data : data; + memcpy(dst, src, tree->collection.elem_size); + + return node; } -void *cxTreeFind( CxTree *tree, const void *data) { - return tree->cl->find(tree, tree->root, data, 0); +void *cxTreeSetRoot(CxTree *tree, void *new_root) { + void *old_root = tree->root; + tree->root = new_root; + return old_root; } -void *cxTreeFindInSubtree(CxTree *tree, const void *data, void *subtree_root, size_t max_depth) { - return tree->cl->find(tree, subtree_root, data, max_depth); +void *cxTreeFindInSubtree(CxTree *tree, const void *data, + void *subtree_root, size_t max_depth, bool use_dfs) { + if (tree->loc_data < 0 || subtree_root == NULL) { + return NULL; + } + + CxTreeIterator iter = use_dfs + ? cx_tree_iterator(subtree_root, false, tree->loc_children, tree->loc_next) + : cx_tree_visitor(subtree_root, tree->loc_children, tree->loc_next); + + cx_foreach(char*, node, iter) { + char *node_data = node + tree->loc_data; + if (cxCollectionStoresPointers(tree)) { + node_data = *(void**)node_data; + } + if (cx_invoke_compare_func(tree, node_data, data) == 0) { + cxTreeIteratorDispose(&iter); + return node; + } + if (iter.depth == max_depth) { + cxTreeIteratorContinue(iter); + } + } + return NULL; +} + +void *cxTreeFindFastInSubtree(CxTree *tree, const void *data, + cx_tree_search_func sfunc, void *root, size_t max_depth) { + void *result; + int ret = cx_tree_search(root, max_depth, data, sfunc, &result, + tree->loc_children, tree->loc_next); + if (ret == 0) { + return result; + } else { + return NULL; + } } size_t cxTreeSubtreeSize(CxTree *tree, void *subtree_root) { - CxTreeVisitor visitor = cx_tree_visitor( - subtree_root, - tree->loc_children, - tree->loc_next - ); - while (cxIteratorValid(visitor)) { - cxIteratorNext(visitor); + if (subtree_root == tree->root) { + return tree->collection.size; } - return visitor.counter; + return cx_tree_size(subtree_root, tree->loc_children, tree->loc_next); } size_t cxTreeSubtreeDepth(CxTree *tree, void *subtree_root) { - CxTreeVisitor visitor = cx_tree_visitor( - subtree_root, - tree->loc_children, - tree->loc_next - ); - while (cxIteratorValid(visitor)) { - cxIteratorNext(visitor); - } - return visitor.depth; + return cx_tree_depth(subtree_root, tree->loc_children, tree->loc_next); } size_t cxTreeSize(CxTree *tree) { @@ -950,13 +676,7 @@ size_t cxTreeSize(CxTree *tree) { } size_t cxTreeDepth(CxTree *tree) { - CxTreeVisitor visitor = cx_tree_visitor( - tree->root, tree->loc_children, tree->loc_next - ); - while (cxIteratorValid(visitor)) { - cxIteratorNext(visitor); - } - return visitor.depth; + return cx_tree_depth(tree->root, tree->loc_children, tree->loc_next); } int cxTreeRemoveNode( @@ -971,7 +691,7 @@ int cxTreeRemoveNode( void *new_parent = tree_parent(node); // first, unlink from the parent - cx_tree_unlink(node, cx_tree_node_layout(tree)); + cx_tree_remove(node, tree_layout(tree)); // then relink each child ptrdiff_t loc_children = tree->loc_children; @@ -988,7 +708,7 @@ int cxTreeRemoveNode( } // link to new parent - cx_tree_link(new_parent, child, cx_tree_node_layout(tree)); + cx_tree_add(new_parent, child, tree_layout(tree)); // proceed to next child child = tree_next(child); @@ -1012,7 +732,7 @@ void cxTreeRemoveSubtree(CxTree *tree, void *node) { return; } size_t subtree_size = cxTreeSubtreeSize(tree, node); - cx_tree_unlink(node, cx_tree_node_layout(tree)); + cx_tree_remove(node, tree_layout(tree)); tree->collection.size -= subtree_size; } @@ -1023,7 +743,7 @@ int cxTreeDestroyNode( ) { int result = cxTreeRemoveNode(tree, node, relink_func); if (result == 0) { - cx_invoke_destructor(tree, node); + cx_invoke_destructor_raw(tree, node); return 0; } else { return result; @@ -1031,14 +751,15 @@ int cxTreeDestroyNode( } void cxTreeDestroySubtree(CxTree *tree, void *node) { - cx_tree_unlink(node, cx_tree_node_layout(tree)); + cx_tree_remove(node, tree_layout(tree)); CxTreeIterator iter = cx_tree_iterator( node, true, tree->loc_children, tree->loc_next ); cx_foreach(void *, child, iter) { if (iter.exiting) { - cx_invoke_destructor(tree, child); + // always call the destructors with the node! + cx_invoke_destructor_raw(tree, child); } } tree->collection.size -= iter.counter; @@ -1048,18 +769,18 @@ void cxTreeDestroySubtree(CxTree *tree, void *node) { } void cxTreeIteratorDispose(CxTreeIterator *iter) { - cxFreeDefault(iter->stack); - iter->stack = NULL; -} - -void cxTreeVisitorDispose(CxTreeVisitor *visitor) { - struct cx_tree_visitor_queue_s *q = visitor->queue_next; - while (q != NULL) { - struct cx_tree_visitor_queue_s *next = q->next; - cxFreeDefault(q); - q = next; + if (iter->use_dfs) { + cxFreeDefault(iter->stack); + iter->stack = NULL; + } else { + struct cx_tree_visitor_queue_s *q = iter->queue_next; + while (q != NULL) { + struct cx_tree_visitor_queue_s *next = q->next; + cxFreeDefault(q); + q = next; + } + iter->queue_next = iter->queue_last = NULL; } - visitor->queue_next = visitor->queue_last = NULL; } CxTreeIterator cxTreeIterateSubtree(CxTree *tree, void *node, bool visit_on_exit) { @@ -1069,7 +790,7 @@ CxTreeIterator cxTreeIterateSubtree(CxTree *tree, void *node, bool visit_on_exit ); } -CxTreeVisitor cxTreeVisitSubtree(CxTree *tree, void *node) { +CxTreeIterator cxTreeVisitSubtree(CxTree *tree, void *node) { return cx_tree_visitor( node, tree->loc_children, tree->loc_next ); @@ -1079,6 +800,6 @@ CxTreeIterator cxTreeIterate(CxTree *tree, bool visit_on_exit) { return cxTreeIterateSubtree(tree, tree->root, visit_on_exit); } -CxTreeVisitor cxTreeVisit(CxTree *tree) { +CxTreeIterator cxTreeVisit(CxTree *tree) { return cxTreeVisitSubtree(tree, tree->root); } diff --git a/ui/cocoa/GridLayout.m b/ui/cocoa/GridLayout.m index c27ba1d..5564cfc 100644 --- a/ui/cocoa/GridLayout.m +++ b/ui/cocoa/GridLayout.m @@ -38,7 +38,7 @@ self = [super init]; _columnspacing = 0; _rowspacing = 0; - _children = cxArrayListCreateSimple(sizeof(GridElm), 32); + _children = cxArrayListCreate(NULL, sizeof(GridElm), 32); _preferredSize.width = -1; _preferredSize.height = -1; diff --git a/ui/cocoa/list.m b/ui/cocoa/list.m index dcb238e..5e72e92 100644 --- a/ui/cocoa/list.m +++ b/ui/cocoa/list.m @@ -408,7 +408,7 @@ static CxList* copy_sublists(const CxAllocator *a, UiSourceListArgs *args) { max = INT_MAX; } - CxList *sublists = cxArrayListCreate(a, NULL, sizeof(UiSubList), args->numsublists); + CxList *sublists = cxArrayListCreate(a, sizeof(UiSubList), args->numsublists); sublists->collection.advanced_destructor = (cx_destructor_func2)sublist_free; for(int i=0;iobservers = ui_add_observer(v->observers, f, data); break; } + case UI_VAR_GENERIC: break; + case UI_VAR_SPECIAL: break; } } +void ui_int_add_observer(UiInteger *i, ui_callback f, void *data) { + i->observers = ui_add_observer(i->observers, f, data); +} + +void ui_double_add_observer(UiDouble *d, ui_callback f, void *data) { + d->observers = ui_add_observer(d->observers, f, data); +} + +void ui_range_add_observer(UiRange *r, ui_callback f, void *data) { + r->observers = ui_add_observer(r->observers, f, data); +} + +void ui_string_add_observer(UiString *s, ui_callback f, void *data) { + s->observers = ui_add_observer(s->observers, f, data); +} + +void ui_text_add_observer(UiText *t, ui_callback f, void *data) { + t->observers = ui_add_observer(t->observers, f, data); +} + +void ui_list_add_observer(UiList *l, ui_callback f, void *data) { + l->observers = ui_add_observer(l->observers, f, data); +} + UiInteger* ui_get_int_var(UiContext *ctx, const char *name) { UiVar *var = uic_get_var_t(ctx, name, UI_VAR_INTEGER); return var ? var->value : NULL; diff --git a/ui/common/context.h b/ui/common/context.h index 5efcc2e..407c051 100644 --- a/ui/common/context.h +++ b/ui/common/context.h @@ -83,6 +83,10 @@ struct UiContext { #elif UI_GTK2 || UI_GTK3 GtkAccelGroup *accel_group; #endif +#endif +#ifdef UI_WIN32 + CxMap *command_map; // key: int, value: UiCommand + uint64_t command_id_counter; #endif // allow only one document to be attached diff --git a/ui/common/object.c b/ui/common/object.c index 58cbb80..f158230 100644 --- a/ui/common/object.c +++ b/ui/common/object.c @@ -107,15 +107,11 @@ void uic_object_destroy(UiObject *obj) { } UiObject* uic_object_new_toplevel(void) { - fflush(stdout); CxMempool *mp = cxMempoolCreateSimple(256); UiObject *obj = cxCalloc(mp->allocator, 1, sizeof(UiObjectPrivate)); - fflush(stdout); obj->ctx = uic_context(obj, mp); obj->ctx->parent = ui_global_context(); - fflush(stdout); uic_object_created(obj); - fflush(stdout); return obj; } diff --git a/ui/gtk/button.c b/ui/gtk/button.c index 8628dad..d9acdbf 100644 --- a/ui/gtk/button.c +++ b/ui/gtk/button.c @@ -505,41 +505,33 @@ UIWIDGET ui_switch_create(UiObject* obj, UiToggleArgs *args) { #define RADIOBUTTON_GET_ACTIVE(button) gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button)) #endif -static void radiobutton_toggled(void *widget, UiVarEventData *event) { - gboolean active = RADIOBUTTON_GET_ACTIVE(widget); - +static void radiobutton_toggled(void *widget, UiEventData *event) { UiEvent e; e.obj = event->obj; e.window = event->obj->window; e.document = event->obj->ctx->document; e.eventdata = NULL; e.eventdatatype = 0; - e.intval = active; + e.intval = RADIOBUTTON_GET_ACTIVE(widget); e.set = ui_get_setop(); - - if(event->callback) { - event->callback(&e, event->userdata); - } - - if(active && event->var) { - UiInteger *i = event->var->value; - - e.intval = i->get(i); - ui_notify_evt(i->observers, &e); - } + event->callback(&e, event->userdata); } typedef struct UiRadioButtonData { - UiObject *obj; - UiVar *var; + UiInteger *value; + UiVarEventData *eventdata; UiBool first; } UiRadioButtonData; static void destroy_radiobutton(GtkWidget *w, UiRadioButtonData *data) { if(data->first) { - UiInteger *value = data->var->value; - ui_destroy_boundvar(data->obj->ctx, data->var); - g_slist_free(value->obj); + ui_destroy_vardata(w, data->eventdata); + g_slist_free(data->value->obj); + data->value->obj = NULL; + data->value->get = NULL; + data->value->set = NULL; + } else { + free(data->eventdata); } free(data); } @@ -562,16 +554,6 @@ UIWIDGET ui_radiobutton_create(UiObject *obj, UiToggleArgs *args) { GtkWidget *rbutton = RADIOBUTTON_NEW(rg, args->label); ui_set_name_and_style(rbutton, args->name, args->style_class); ui_set_widget_states(obj->ctx, rbutton, args->states); - - UiVarEventData *event = malloc(sizeof(UiVarEventData)); - event->obj = obj; - event->var = var; - event->observers = NULL; - event->callback = args->onchange; - event->userdata = args->onchangedata; - event->customint1 = 0; - event->customint2 = 0; - if(rgroup) { #if GTK_MAJOR_VERSION >= 4 if(rg) { @@ -589,28 +571,52 @@ UIWIDGET ui_radiobutton_create(UiObject *obj, UiToggleArgs *args) { ui_radiobutton_set(rgroup, rgroup->value); + UiVarEventData *event = malloc(sizeof(UiVarEventData)); + event->obj = obj; + event->var = var; + event->observers = NULL; + event->callback = NULL; + event->userdata = NULL; + event->customint1 = 0; + event->customint2 = 0; + UiRadioButtonData *rbdata = malloc(sizeof(UiRadioButtonData)); - rbdata->obj = obj; - rbdata->var = var; + rbdata->value = rgroup; + rbdata->eventdata = event; rbdata->first = first; + g_signal_connect( + rbutton, + "toggled", + G_CALLBACK(ui_radio_obs), + event); g_signal_connect( rbutton, "destroy", G_CALLBACK(destroy_radiobutton), rbdata); } + + if(args->onchange) { + UiEventData *event = malloc(sizeof(UiEventData)); + event->obj = obj; + event->userdata = args->onchangedata; + event->callback = args->onchange; + event->value = 0; + event->customdata = NULL; + event->customint = 0; - g_signal_connect( - rbutton, - "toggled", - G_CALLBACK(radiobutton_toggled), - event); - g_signal_connect( - rbutton, - "destroy", - G_CALLBACK(ui_destroy_userdata), - event); + g_signal_connect( + rbutton, + "toggled", + G_CALLBACK(radiobutton_toggled), + event); + g_signal_connect( + rbutton, + "destroy", + G_CALLBACK(ui_destroy_userdata), + event); + } UiContainerPrivate *ct = (UiContainerPrivate*)obj->container_end; UiLayout layout = UI_ARGS2LAYOUT(args); @@ -619,6 +625,20 @@ UIWIDGET ui_radiobutton_create(UiObject *obj, UiToggleArgs *args) { return rbutton; } +void ui_radio_obs(GtkToggleButton *widget, UiVarEventData *event) { + UiInteger *i = event->var->value; + + UiEvent e; + e.obj = event->obj; + e.window = event->obj->window; + e.document = event->obj->ctx->document; + e.eventdata = NULL; + e.eventdatatype = 0; + e.intval = i->get(i); + + ui_notify_evt(i->observers, &e); +} + #if GTK_MAJOR_VERSION >= 4 int64_t ui_radiobutton_get(UiInteger *value) { int selection = 0; diff --git a/ui/gtk/list.c b/ui/gtk/list.c index a383048..e8b649c 100644 --- a/ui/gtk/list.c +++ b/ui/gtk/list.c @@ -1021,7 +1021,7 @@ static void update_list_row(UiListView *listview, GtkListStore *store, GtkTreeIt void *data = listview->getvalue(list, elm, row, c, listview->getvaluedata, &freevalue); UiModelType type = model->types[i]; - + UiTextStyle cstyle = { 0, 0 }; if(getstyle) { // in case the column is icon+text, only get a style for the text column int style_col = c; @@ -1032,8 +1032,15 @@ static void update_list_row(UiListView *listview, GtkListStore *store, GtkTreeIt // Get the individual column style // The column style overrides the row style, however if no column style // is provided, we stick with the row style - if(getstyle(list, elm, row, style_col, listview->getstyledata, &style)) { + if(getstyle(list, elm, row, style_col, listview->getstyledata, &cstyle)) { style_set = TRUE; + cstyle.text_style |= style.text_style; + if(!cstyle.fg_set) { + cstyle.fg_set = style.fg_set; + cstyle.fg = style.fg; + } + } else { + cstyle = style; } } @@ -1139,7 +1146,7 @@ static void update_list_row(UiListView *listview, GtkListStore *store, GtkTreeIt GValue style_weight_value = G_VALUE_INIT; g_value_init(&style_weight_value, G_TYPE_INT); - if(style.text_style & UI_TEXT_STYLE_BOLD) { + if(cstyle.text_style & UI_TEXT_STYLE_BOLD) { g_value_set_int(&style_weight_value, 600); } else { g_value_set_int(&style_weight_value, 400); @@ -1148,7 +1155,7 @@ static void update_list_row(UiListView *listview, GtkListStore *store, GtkTreeIt GValue style_underline_value = G_VALUE_INIT; g_value_init(&style_underline_value, G_TYPE_INT); - if(style.text_style & UI_TEXT_STYLE_UNDERLINE) { + if(cstyle.text_style & UI_TEXT_STYLE_UNDERLINE) { g_value_set_int(&style_underline_value, PANGO_UNDERLINE_SINGLE); } else { g_value_set_int(&style_underline_value, PANGO_UNDERLINE_NONE); @@ -1157,7 +1164,7 @@ static void update_list_row(UiListView *listview, GtkListStore *store, GtkTreeIt GValue style_italic_value = G_VALUE_INIT; g_value_init(&style_italic_value, G_TYPE_INT); - if(style.text_style & UI_TEXT_STYLE_ITALIC) { + if(cstyle.text_style & UI_TEXT_STYLE_ITALIC) { g_value_set_int(&style_italic_value, PANGO_STYLE_ITALIC); } else { g_value_set_int(&style_italic_value, PANGO_STYLE_NORMAL); @@ -1166,12 +1173,12 @@ static void update_list_row(UiListView *listview, GtkListStore *store, GtkTreeIt GValue style_fgset_value = G_VALUE_INIT; g_value_init(&style_fgset_value, G_TYPE_BOOLEAN); - g_value_set_boolean(&style_fgset_value, style.fg_set); + g_value_set_boolean(&style_fgset_value, cstyle.fg_set); gtk_list_store_set_value(store, iter, soff + 4, &style_fgset_value); - if(style.fg_set) { + if(cstyle.fg_set) { char buf[8]; - snprintf(buf, 8, "#%02X%02X%02X", (int)style.fg.red, (int)style.fg.green, (int)style.fg.blue); + snprintf(buf, 8, "#%02X%02X%02X", (int)cstyle.fg.red, (int)cstyle.fg.green, (int)cstyle.fg.blue); GValue style_fg_value = G_VALUE_INIT; g_value_init(&style_fg_value, G_TYPE_STRING); @@ -1358,6 +1365,23 @@ void ui_dropdown_select(UIWIDGET dropdown, int index) { gtk_combo_box_set_active(GTK_COMBO_BOX(dropdown), index); } +static void table_cell_toggled( + GtkCellRendererToggle *renderer, + gchar *path, + gpointer user_data) +{ + printf("cell toggled\n"); +} + +static void table_cell_edited( + GtkCellRendererText *renderer, + gchar *path, + gchar *new_text, + gpointer user_data) +{ + printf("cell edited\n"); +} + UIWIDGET ui_table_create(UiObject *obj, UiListArgs *args) { // create treeview GtkWidget *view = gtk_tree_view_new(); @@ -1416,8 +1440,20 @@ UIWIDGET ui_table_create(UiObject *obj, UiListArgs *args) { "pixbuf", i + addi, NULL); + } else if (model->types[i] == UI_BOOL_EDITABLE) { + GtkCellRenderer *renderer = gtk_cell_renderer_toggle_new(); + column = gtk_tree_view_column_new_with_attributes( + model->titles[i], + renderer, + "active", + i + addi, + NULL); + g_signal_connect(renderer, "toggled", G_CALLBACK(table_cell_toggled), NULL); } else { GtkCellRenderer *textrenderer = gtk_cell_renderer_text_new(); + if(model->types[i] == UI_STRING_EDITABLE) { + g_object_set(textrenderer, "editable", TRUE, NULL); + } column = gtk_tree_view_column_new_with_attributes( model->titles[i], textrenderer, @@ -2460,7 +2496,11 @@ static void listbox_button_clicked(GtkWidget *button, UiEventDataExt *data) { UIMENU menu = data->customdata3; g_object_set_data(G_OBJECT(button), "ui-button-popup", menu); +#if GTK_CHECK_VERSION(4, 0, 0) gtk_popover_popup(GTK_POPOVER(menu)); +#else + ui_contextmenu_popup(menu, button, 0, 0); +#endif } } @@ -2552,6 +2592,7 @@ static void listbox_fill_row(UiListBox *listbox, GtkWidget *row, UiListBoxSubLis event ); gtk_widget_set_visible(button, FALSE); + WIDGET_NO_SHOW_ALL(button); g_object_set_data(G_OBJECT(row), "ui-listbox-row-button", button); @@ -2591,6 +2632,7 @@ static void update_sublist_item(UiListBox *listbox, UiListBoxSubList *sublist, i LISTBOX_ROW_REMOVE_CHILD(row); listbox_fill_row(listbox, GTK_WIDGET(row), sublist, &item, index); + LISTBOX_ROW_SHOW(row); // cleanup free(item.label); @@ -2727,6 +2769,7 @@ void ui_listbox_update_sublist(UiListBox *listbox, UiListBoxSubList *sublist, si #endif listbox_fill_row(listbox, row, sublist, &item, index); + LISTBOX_ROW_SHOW(row); if(index == first_index) { // first row in the sublist, set ui_listbox data to the row // which is then used by the headerfunc diff --git a/ui/gtk/menu.c b/ui/gtk/menu.c index 0601a92..8bfbbbf 100644 --- a/ui/gtk/menu.c +++ b/ui/gtk/menu.c @@ -153,29 +153,100 @@ void add_checkitem_widget(GtkWidget *p, int index, UiMenuItemI *item, UiObject * GtkWidget *widget = gtk_check_menu_item_new_with_mnemonic(ci->label); gtk_menu_shell_append(GTK_MENU_SHELL(p), widget); - if(ci->callback) { - UiEventData *event = malloc(sizeof(UiEventData)); - event->obj = obj; - event->userdata = ci->userdata; - event->callback = ci->callback; - event->value = 0; - event->customdata = NULL; - - g_signal_connect( - widget, - "toggled", - G_CALLBACK(ui_menu_event_toggled), - event); - g_signal_connect( - widget, - "destroy", - G_CALLBACK(ui_destroy_userdata), - event); + UiVarEventData *event = malloc(sizeof(UiVarEventData)); + memset(event, 0, sizeof(UiVarEventData)); + event->obj = obj; + event->userdata = ci->userdata; + event->callback = ci->callback; + event->var = uic_widget_var(obj->ctx, obj->ctx, NULL, ci->varname, UI_VAR_INTEGER); + if(event->var) { + UiInteger *v = event->var->value; + v->obj = widget; + v->get = ui_checkitem_get; + v->set = ui_checkitem_set; + if(v->value != 0) { + gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(widget), TRUE); + } + } + + g_signal_connect( + widget, + "toggled", + G_CALLBACK(ui_menu_event_toggled), + event); + g_signal_connect( + widget, + "destroy", + G_CALLBACK(ui_destroy_userdata), + event); +} + +static void ui_menu_event_radio_item_toggled(GtkRadioMenuItem *ri, UiVarEventData *event) { + UiInteger *i = event->var->value; + + UiEvent evt; + evt.obj = event->obj; + evt.window = event->obj->window; + evt.document = event->obj->ctx->document; + evt.eventdata = i; + evt.eventdatatype = i ? UI_EVENT_DATA_INTEGER_VALUE : 0; + evt.intval = gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(ri)); + + if(event->callback) { + event->callback(&evt, event->userdata); + } + + if(evt.intval) { + evt.intval = ui_get(i); + ui_notify_evt(i->observers, &evt); } } +static void ui_destroy_menu_radio_item(GtkWidget *unused, UiVarEventData *event) { + if(event->customint1) { + uic_unbind_var(event->var); + } + free(event); +} + void add_radioitem_widget(GtkWidget *p, int index, UiMenuItemI *item, UiObject *obj) { - // TODO + UiMenuRadioItem *ri = (UiMenuRadioItem*)item; + + UiVar *var = uic_widget_var(obj->ctx, obj->ctx, NULL, ri->varname, UI_VAR_INTEGER); + if(!var) { + fprintf(stderr, "Error: menu radioitem varname is null\n"); + return; + } + int first = 0; + UiInteger *i = var->value; + GSList *group = i->obj; + GtkWidget *widget = gtk_radio_menu_item_new_with_label(group, ri->label); + gtk_menu_shell_append(GTK_MENU_SHELL(p), widget); + if(!group) { + i->get = ui_radioitem_get; + i->set = ui_radioitem_set; + first = 1; + } + i->obj = gtk_radio_menu_item_get_group(GTK_RADIO_MENU_ITEM(widget)); + + UiVarEventData *event = malloc(sizeof(UiVarEventData)); + memset(event, 0, sizeof(UiVarEventData)); + event->obj = obj; + event->var = var; + event->callback = ri->callback; + event->userdata = ri->userdata; + event->customint1 = first; + + g_signal_connect( + widget, + "toggled", + G_CALLBACK(ui_menu_event_radio_item_toggled), + event); + g_signal_connect( + widget, + "destroy", + G_CALLBACK(ui_destroy_menu_radio_item), + event); } static void menuitem_list_remove_binding(void *obj) { @@ -323,14 +394,23 @@ void ui_menu_event_wrapper(GtkMenuItem *item, UiEventData *event) { uic_set_tmp_eventdata(NULL, 0); } -void ui_menu_event_toggled(GtkCheckMenuItem *ci, UiEventData *event) { +void ui_menu_event_toggled(GtkCheckMenuItem *ci, UiVarEventData *event) { + UiInteger *i = event->var ? event->var->value : NULL; + UiEvent evt; evt.obj = event->obj; evt.window = event->obj->window; evt.document = event->obj->ctx->document; - evt.eventdata = NULL; + evt.eventdata = i; + evt.eventdatatype = i ? UI_EVENT_DATA_INTEGER_VALUE : 0; evt.intval = gtk_check_menu_item_get_active(ci); - event->callback(&evt, event->userdata); + if(event->callback) { + event->callback(&evt, event->userdata); + } + + if(i) { + ui_notify_evt(i->observers, &evt); + } } int64_t ui_checkitem_get(UiInteger *i) { @@ -341,7 +421,48 @@ int64_t ui_checkitem_get(UiInteger *i) { void ui_checkitem_set(UiInteger *i, int64_t value) { i->value = value; - gtk_check_menu_item_set_active(i->obj, value); + gtk_check_menu_item_set_active(i->obj, (gboolean)value); +} + +int64_t ui_radioitem_get(UiInteger *value) { + int selection = 0; + GSList *ls = value->obj; + guint len = g_slist_length(ls); + int i = 0; + while(ls) { + if(gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(ls->data))) { + selection = len - i; + break; + } + ls = ls->next; + i++; + } + + value->value = selection; + return selection; +} + +void ui_radioitem_set(UiInteger *i, int64_t value) { + GSList *ls = i->obj; + + int len = g_slist_length(ls); + if(value > len) { + value = len; + } + int s = len - value; + int j = 0; + int unset = 1; + while(ls) { + if(j == s) { + gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(ls->data), TRUE); + unset = 0; + break; + } + ls = ls->next; + j++; + } + + i->value = value; } diff --git a/ui/gtk/menu.h b/ui/gtk/menu.h index a7f65e7..4cfa419 100644 --- a/ui/gtk/menu.h +++ b/ui/gtk/menu.h @@ -75,9 +75,11 @@ void add_menuitem_list_widget(GtkWidget *p, int i, UiMenuItemI *item, UiObject * void ui_menulist_update(UiList *list, int ignored); void ui_update_menuitem_list(UiActiveMenuItemList *list); void ui_menu_event_wrapper(GtkMenuItem *item, UiEventData *event); -void ui_menu_event_toggled(GtkCheckMenuItem *ci, UiEventData *event); +void ui_menu_event_toggled(GtkCheckMenuItem *ci, UiVarEventData *event); int64_t ui_checkitem_get(UiInteger *i); void ui_checkitem_set(UiInteger *i, int64_t value); +int64_t ui_radioitem_get(UiInteger *i); +void ui_radioitem_set(UiInteger *i, int64_t value); #endif /* GTK_MAJOR_VERSION <= 3 */ diff --git a/ui/gtk/toolbar.c b/ui/gtk/toolbar.c index 7826384..33efbcd 100644 --- a/ui/gtk/toolbar.c +++ b/ui/gtk/toolbar.c @@ -44,7 +44,7 @@ #if UI_GTK2 || UI_GTK3 -GtkWidget* ui_create_toolbar(UiObject *obj) { +GtkWidget* ui_create_toolbar(UiObject *obj, UiBool sidebar) { GtkWidget *toolbar = gtk_toolbar_new(); #ifdef UI_GTK3 gtk_style_context_add_class( @@ -56,25 +56,24 @@ GtkWidget* ui_create_toolbar(UiObject *obj) { CxList *left_defaults = uic_get_toolbar_defaults(UI_TOOLBAR_LEFT); CxList *center_defaults = uic_get_toolbar_defaults(UI_TOOLBAR_CENTER); CxList *right_defaults = uic_get_toolbar_defaults(UI_TOOLBAR_RIGHT); + CxList *sidebar_left = uic_get_toolbar_defaults(UI_TOOLBAR_SIDEBAR_LEFT); + CxList *sidebar_right = uic_get_toolbar_defaults(UI_TOOLBAR_SIDEBAR_RIGHT); + CxList *rightpanel_left = uic_get_toolbar_defaults(UI_TOOLBAR_RIGHTPANEL_LEFT); + CxList *rightpanel_center = uic_get_toolbar_defaults(UI_TOOLBAR_RIGHTPANEL_CENTER); + CxList *rightpanel_right = uic_get_toolbar_defaults(UI_TOOLBAR_RIGHTPANEL_RIGHT); + + if(sidebar) { + ui_toolbar_add_items(obj, toolbar, items, sidebar_left); + ui_toolbar_add_items(obj, toolbar, items, sidebar_right); + } ui_toolbar_add_items(obj, toolbar, items, left_defaults); ui_toolbar_add_items(obj, toolbar, items, center_defaults); ui_toolbar_add_items(obj, toolbar, items, right_defaults); - /* - GtkToolbar *tb = GTK_TOOLBAR(toolbar); - CxIterator i = cxListIterator(defaults); - cx_foreach(char *, def, i) { - UiToolItemI *item = cxMapGet(toolbar_items, def); - if(item) { - item->add_to(tb, item, obj); - } else if(!strcmp(def, "@separator")) { - gtk_toolbar_insert(tb, gtk_separator_tool_item_new(), -1); - } else { - fprintf(stderr, "UI Error: Unknown toolbar item: %s\n", def); - } - } - */ + ui_toolbar_add_items(obj, toolbar, items, rightpanel_left); + ui_toolbar_add_items(obj, toolbar, items, rightpanel_center); + ui_toolbar_add_items(obj, toolbar, items, rightpanel_right); return toolbar; } diff --git a/ui/gtk/toolbar.h b/ui/gtk/toolbar.h index 80bd113..7534c63 100644 --- a/ui/gtk/toolbar.h +++ b/ui/gtk/toolbar.h @@ -113,7 +113,7 @@ void ui_toolitem_vstgr( void *userdata, va_list ap); -GtkWidget* ui_create_toolbar(UiObject *obj); +GtkWidget* ui_create_toolbar(UiObject *obj, UiBool sidebar); void ui_toolbar_add_items(UiObject *obj, GtkWidget *toolbar, CxMap *items, CxList *defaults); diff --git a/ui/gtk/toolkit.c b/ui/gtk/toolkit.c index 5e57a5d..10cba07 100644 --- a/ui/gtk/toolkit.c +++ b/ui/gtk/toolkit.c @@ -239,9 +239,10 @@ void ui_set_visible(UIWIDGET widget, UiBool visible) { gtk_widget_set_visible(widget, visible); #else if(visible) { + gtk_widget_set_no_show_all(widget, FALSE); gtk_widget_show_all(widget); } else { - gtk_widget_set_no_show_all(widget, FALSE); + gtk_widget_set_no_show_all(widget, TRUE); gtk_widget_hide(widget); } #endif @@ -281,7 +282,7 @@ void ui_destroy_userdata(GtkWidget *object, void *userdata) { free(userdata); } -void ui_destroy_vardata(GtkWidget *object, UiVarEventData *data) { +void ui_destroy_vardata(GtkWidget *unused, UiVarEventData *data) { if(data->var) { ui_destroy_boundvar(data->obj->ctx, data->var); } diff --git a/ui/gtk/toolkit.h b/ui/gtk/toolkit.h index d3f8897..0e421b9 100644 --- a/ui/gtk/toolkit.h +++ b/ui/gtk/toolkit.h @@ -58,6 +58,7 @@ extern "C" { #define WINDOW_SHOW(window) gtk_window_present(GTK_WINDOW(window)) #define WINDOW_DESTROY(window) gtk_window_destroy(GTK_WINDOW(window)) #define WINDOW_SET_CONTENT(window, child) gtk_window_set_child(GTK_WINDOW(window), child) +#define WIDGET_NO_SHOW_ALL(widget) #define BOX_ADD(box, child) gtk_box_append(GTK_BOX(box), child) #define BOX_ADD_EXPAND(box, child) gtk_widget_set_hexpand(child, TRUE); gtk_widget_set_vexpand(child, TRUE); gtk_box_append(GTK_BOX(box), child) #define BOX_ADD_NO_EXPAND(box, child) gtk_box_append(GTK_BOX(box), child) @@ -75,12 +76,14 @@ extern "C" { #define LISTBOX_REMOVE(listbox, row) gtk_list_box_remove(GTK_LIST_BOX(listbox), row) #define LISTBOX_ROW_SET_CHILD(row, child) gtk_list_box_row_set_child(GTK_LIST_BOX_ROW(row), child) #define LISTBOX_ROW_REMOVE_CHILD(row) gtk_list_box_row_set_child(GTK_LIST_BOX_ROW(row), NULL) +#define LISTBOX_ROW_SHOW(row) #define PANED_SET_CHILD1(paned, child) gtk_paned_set_start_child(GTK_PANED(paned), child) #define PANED_SET_CHILD2(paned, child) gtk_paned_set_end_child(GTK_PANED(paned), child) #else #define WINDOW_SHOW(window) gtk_widget_show_all(window) #define WINDOW_DESTROY(window) gtk_widget_destroy(window) #define WINDOW_SET_CONTENT(window, child) gtk_container_add(GTK_CONTAINER(window), child) +#define WIDGET_NO_SHOW_ALL(widget) gtk_widget_set_no_show_all(widget, TRUE) #define BOX_ADD(box, child) gtk_container_add(GTK_CONTAINER(box), child) #define BOX_ADD_EXPAND(box, child) gtk_box_pack_start(GTK_BOX(box), child, TRUE, TRUE, 0) #define BOX_ADD_NO_EXPAND(box, child) gtk_box_pack_start(GTK_BOX(box), child, TRUE, FALSE, 0) @@ -98,6 +101,7 @@ extern "C" { #define LISTBOX_REMOVE(listbox, row) gtk_container_remove(GTK_CONTAINER(listbox), row) #define LISTBOX_ROW_SET_CHILD(row, child) gtk_container_add(GTK_CONTAINER(row), child) #define LISTBOX_ROW_REMOVE_CHILD(row) gtk_container_remove(GTK_CONTAINER(row), gtk_bin_get_child(GTK_BIN(row))) +#define LISTBOX_ROW_SHOW(row) gtk_widget_show_all(GTK_WIDGET(row)) #define PANED_SET_CHILD1(paned, child) gtk_paned_pack1(GTK_PANED(paned), child, TRUE, TRUE) #define PANED_SET_CHILD2(paned, child) gtk_paned_pack2(GTK_PANED(paned), child, TRUE, TRUE) #endif @@ -186,7 +190,7 @@ void ui_set_widget_visibility_states(UiContext *ctx, GtkWidget *widget, const in void ui_set_widget_nvisibility_states(UiContext *ctx, GtkWidget *widget, const int *states, size_t ngroups); void ui_destroy_userdata(GtkWidget *object, void *userdata); -void ui_destroy_vardata(GtkWidget *object, UiVarEventData *data); +void ui_destroy_vardata(GtkWidget *unused, UiVarEventData *data); void ui_destroy_widget_var(GtkWidget *object, UiVar *var); void ui_destroy_boundvar(UiContext *ctx, UiVar *var); diff --git a/ui/gtk/window.c b/ui/gtk/window.c index 6fa68f7..1046391 100644 --- a/ui/gtk/window.c +++ b/ui/gtk/window.c @@ -309,7 +309,7 @@ static UiObject* create_window(const char *title, UiBool sidebar, UiBool splitvi // TODO: gtk4 toolbar #else if(uic_toolbar_isenabled()) { - GtkWidget *tb = ui_create_toolbar(obj); + GtkWidget *tb = ui_create_toolbar(obj, sidebar); if(tb) { BOX_ADD(vbox, tb); } diff --git a/ui/motif/pathbar.c b/ui/motif/pathbar.c index f6735b1..e236c23 100644 --- a/ui/motif/pathbar.c +++ b/ui/motif/pathbar.c @@ -186,9 +186,9 @@ static cxmutstr concat_path_s(cxstring base, cxstring path) { cxmutstr url; if(add_separator) { - url = cx_strcat(3, base, cx_str("/"), path); + url = cx_strcat(CX_NULLSTR, 3, base, cx_str("/"), path); } else { - url = cx_strcat(2, base, path); + url = cx_strcat(CX_NULLSTR, 2, base, path); } return url; diff --git a/ui/ui/toolkit.h b/ui/ui/toolkit.h index d4774ac..94c77f0 100644 --- a/ui/ui/toolkit.h +++ b/ui/ui/toolkit.h @@ -647,6 +647,13 @@ UIEXPORT UiGeneric* ui_get_generic_var(UiContext *ctx, const char *name); UIEXPORT void ui_var_add_observer(UiContext *ctx, const char *varname, ui_callback f, void *data); +UIEXPORT void ui_int_add_observer(UiInteger *i, ui_callback f, void *data); +UIEXPORT void ui_double_add_observer(UiDouble *d, ui_callback f, void *data); +UIEXPORT void ui_range_add_observer(UiRange *r, ui_callback f, void *data); +UIEXPORT void ui_string_add_observer(UiString *s, ui_callback f, void *data); +UIEXPORT void ui_text_add_observer(UiText *t, ui_callback f, void *data); +UIEXPORT void ui_list_add_observer(UiList *l, ui_callback f, void *data); + UIEXPORT UiObserver* ui_observer_new(ui_callback f, void *data); UIEXPORT UiObserver* ui_obsvlist_add(UiObserver *list, UiObserver *observer); UIEXPORT UiObserver* ui_add_observer(UiObserver *list, ui_callback f, void *data);