# HG changeset patch # User Mike Becker # Date 1766939480 -3600 # Node ID 36c0fb2b60b2a8341c63edad7a68be6d92c0c097 # Parent 8b0f162ac88ea8a8186bfcb61e272d58c4f24fcf overhaul all attributes diff -r 8b0f162ac88e -r 36c0fb2b60b2 src/allocator.c --- a/src/allocator.c Sun Dec 28 15:45:39 2025 +0100 +++ b/src/allocator.c Sun Dec 28 17:31:20 2025 +0100 @@ -61,14 +61,14 @@ #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_calloc_stdlib( - cx_attr_unused void *d, + CX_UNUSED void *d, size_t nmemb, size_t size ) { @@ -84,7 +84,7 @@ } static void cx_free_stdlib( - cx_attr_unused void *d, + CX_UNUSED void *d, void *mem ) { free(mem); diff -r 8b0f162ac88e -r 36c0fb2b60b2 src/cx/allocator.h --- a/src/cx/allocator.h Sun Dec 28 15:45:39 2025 +0100 +++ b/src/cx/allocator.h Sun Dec 28 17:31:20 2025 +0100 @@ -35,10 +35,6 @@ #include "common.h" -#ifdef __cplusplus -extern "C" { -#endif - /** * The class definition for an allocator. */ @@ -153,8 +149,8 @@ * * @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 @@ * @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 @@ * @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 @@ * @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 @@ * @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 @@ * @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 @@ * @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 @@ * @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 @@ * @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 @@ * @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 @@ * @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 @@ * * @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 -r 8b0f162ac88e -r 36c0fb2b60b2 src/cx/array_list.h --- a/src/cx/array_list.h Sun Dec 28 15:45:39 2025 +0100 +++ b/src/cx/array_list.h Sun Dec 28 17:31:20 2025 +0100 @@ -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 @@ * @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 @@ * @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 @@ * @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 @@ * @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 @@ * @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 @@ * @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 @@ * @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); @@ -721,7 +717,8 @@ * @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 @@ * @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 @@ * @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); /** @@ -778,8 +777,8 @@ * @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 +803,8 @@ * @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 +834,8 @@ * @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 +911,8 @@ * @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 +961,8 @@ * @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 +984,8 @@ * @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 +1013,8 @@ * @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 +1044,8 @@ * @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 +1068,8 @@ * @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 +1098,8 @@ * @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 +1110,8 @@ * @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 +1126,8 @@ * @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 -r 8b0f162ac88e -r 36c0fb2b60b2 src/cx/buffer.h --- a/src/cx/buffer.h Sun Dec 28 15:45:39 2025 +0100 +++ b/src/cx/buffer.h Sun Dec 28 17:31:20 2025 +0100 @@ -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 @@ * @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 @@ * @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 @@ * @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 @@ * @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 @@ * @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 @@ * @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 @@ * @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 @@ * @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 @@ * @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 @@ * @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 @@ * @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 @@ * 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 @@ * @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 @@ * @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 @@ * @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 @@ * @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 @@ * @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 @@ * @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 @@ * @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 @@ * 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 @@ * @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 @@ * @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 @@ * @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 @@ * @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 @@ * @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 @@ * @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 -r 8b0f162ac88e -r 36c0fb2b60b2 src/cx/collection.h --- a/src/cx/collection.h Sun Dec 28 15:45:39 2025 +0100 +++ b/src/cx/collection.h Sun Dec 28 17:31:20 2025 +0100 @@ -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,4 @@ 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 - #endif // UCX_COLLECTION_H diff -r 8b0f162ac88e -r 36c0fb2b60b2 src/cx/common.h --- a/src/cx/common.h Sun Dec 28 15:45:39 2025 +0100 +++ b/src/cx/common.h Sun Dec 28 17:31:20 2025 +0100 @@ -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__)) // --------------------------------------------------------------------------- @@ -287,6 +287,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 +374,8 @@ * @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 -r 8b0f162ac88e -r 36c0fb2b60b2 src/cx/compare.h --- a/src/cx/compare.h Sun Dec 28 15:45:39 2025 +0100 +++ b/src/cx/compare.h Sun Dec 28 17:31:20 2025 +0100 @@ -38,10 +38,6 @@ #include "common.h" -#ifdef __cplusplus -extern "C" { -#endif - /** * A comparator function comparing two arbitrary values. * @@ -54,14 +50,14 @@ * 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 @@ * @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 @@ * @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 @@ * @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 @@ * @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 @@ * @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 @@ * @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 @@ * @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 @@ * @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 @@ * @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 @@ * @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 @@ * @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 @@ * @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 @@ * @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 @@ * @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 @@ * @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 @@ * @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 @@ * @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 @@ * @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 @@ * @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 @@ * @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 @@ * @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 @@ * @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 @@ * @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 @@ * @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 @@ * @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 @@ * @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 @@ * @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 @@ * @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 @@ * @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 @@ * @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 @@ * @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 @@ * @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 @@ * @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 @@ * @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 @@ * @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 @@ * @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 -r 8b0f162ac88e -r 36c0fb2b60b2 src/cx/hash_key.h --- a/src/cx/hash_key.h Sun Dec 28 15:45:39 2025 +0100 +++ b/src/cx/hash_key.h Sun Dec 28 17:31:20 2025 +0100 @@ -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 @@ * @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,8 @@ * @param x the integer * @return the hash */ -CX_INLINE 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; @@ -104,7 +101,8 @@ * @param x the integer * @return the hash */ -CX_INLINE 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); @@ -122,9 +120,8 @@ * @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_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. @@ -132,8 +129,8 @@ * @param x the integer * @return the hash key */ -cx_attr_nodiscard -CX_INLINE 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; @@ -147,8 +144,8 @@ * @param x the integer * @return the hash key */ -cx_attr_nodiscard -CX_INLINE 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; @@ -164,8 +161,8 @@ * @param str the string * @return the hash key */ -cx_attr_nodiscard cx_attr_cstr_arg(1) -CX_INLINE 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)); } @@ -180,8 +177,8 @@ * @param str the string * @return the hash key */ -cx_attr_nodiscard cx_attr_cstr_arg(1) -CX_INLINE 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)); } @@ -192,8 +189,8 @@ * @param len the length * @return the hash key */ -cx_attr_nodiscard cx_attr_access_r(1, 2) -CX_INLINE CxHashKey cx_hash_key_bytes(const unsigned char *bytes, 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); } @@ -203,8 +200,8 @@ * @param str the string * @return the hash key */ -cx_attr_nodiscard -CX_INLINE 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); } @@ -214,8 +211,8 @@ * @param str the string * @return the hash key */ -cx_attr_nodiscard -CX_INLINE 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); } @@ -226,8 +223,8 @@ * @param key 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; } @@ -238,8 +235,8 @@ * @param key a pointer to a key * @return a copy of the key (not the data) */ -cx_attr_nodiscard -CX_INLINE CxHashKey cx_hash_key_deref(const CxHashKey *key) { +CX_NODISCARD CX_INLINE +CxHashKey cx_hash_key_deref(const CxHashKey *key) { return *key; } @@ -279,8 +276,8 @@ * @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. @@ -288,11 +285,10 @@ * @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) // ---------------------------------------------------------- diff -r 8b0f162ac88e -r 36c0fb2b60b2 src/cx/hash_map.h --- a/src/cx/hash_map.h Sun Dec 28 15:45:39 2025 +0100 +++ b/src/cx/hash_map.h Sun Dec 28 17:31:20 2025 +0100 @@ -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 @@ * @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 @@ * @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 -r 8b0f162ac88e -r 36c0fb2b60b2 src/cx/iterator.h --- a/src/cx/iterator.h Sun Dec 28 15:45:39 2025 +0100 +++ b/src/cx/iterator.h Sun Dec 28 17:31:20 2025 +0100 @@ -38,10 +38,6 @@ #include "common.h" -#ifdef __cplusplus -extern "C" { -#endif - /** * Common data for all iterators. */ @@ -220,8 +216,8 @@ * @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 +233,7 @@ * @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 -r 8b0f162ac88e -r 36c0fb2b60b2 src/cx/json.h --- a/src/cx/json.h Sun Dec 28 15:45:39 2025 +0100 +++ b/src/cx/json.h Sun Dec 28 17:31:20 2025 +0100 @@ -43,11 +43,6 @@ #include "array_list.h" #include "map.h" -#ifdef __cplusplus -extern "C" { -#endif - - /** * The type of the parsed token. */ @@ -115,6 +110,10 @@ */ CX_JSON_NOTHING, // this allows us to always return non-NULL values /** + * No meaningful data. + */ + CX_JSON_UNINITIALIZED, + /** * A JSON object. */ CX_JSON_OBJECT, @@ -427,8 +426,8 @@ * * @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. @@ -436,8 +435,8 @@ * @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. @@ -457,8 +456,8 @@ * @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); @@ -472,8 +471,8 @@ * @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. @@ -485,8 +484,8 @@ * @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. @@ -495,8 +494,8 @@ * @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. @@ -504,8 +503,8 @@ * @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. @@ -515,8 +514,8 @@ * * @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. @@ -536,8 +535,8 @@ * @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); /** @@ -548,8 +547,8 @@ * @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); } @@ -581,8 +580,8 @@ * @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); /** @@ -603,6 +602,20 @@ 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. * * @param allocator the allocator to use @@ -610,8 +623,8 @@ * @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. @@ -624,8 +637,8 @@ * @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. @@ -636,8 +649,8 @@ * @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. @@ -648,8 +661,8 @@ * @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. @@ -662,8 +675,8 @@ * @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. @@ -685,8 +698,8 @@ * @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. @@ -697,8 +710,8 @@ * @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. @@ -709,8 +722,8 @@ * @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. @@ -724,8 +737,8 @@ * @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. @@ -739,8 +752,8 @@ * @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. @@ -751,8 +764,8 @@ * @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. @@ -766,8 +779,8 @@ * @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. @@ -780,8 +793,8 @@ * @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. @@ -810,8 +823,8 @@ * @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. @@ -836,8 +849,8 @@ * @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. @@ -863,8 +876,8 @@ * @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. @@ -890,8 +903,8 @@ * @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. @@ -917,8 +930,8 @@ * @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. @@ -946,8 +959,8 @@ * @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. @@ -962,19 +975,6 @@ #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. * * Before this function can be called, the input buffer needs @@ -996,8 +996,8 @@ * @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. @@ -1006,8 +1006,8 @@ * @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; } @@ -1018,8 +1018,8 @@ * @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; } @@ -1030,8 +1030,8 @@ * @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; } @@ -1046,8 +1046,8 @@ * @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; } @@ -1059,8 +1059,8 @@ * @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; } @@ -1076,8 +1076,8 @@ * @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; } @@ -1090,8 +1090,8 @@ * @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; } @@ -1107,8 +1107,8 @@ * @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; } @@ -1124,8 +1124,8 @@ * @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; } @@ -1137,8 +1137,8 @@ * @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; } @@ -1151,8 +1151,8 @@ * @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. @@ -1163,8 +1163,8 @@ * @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. @@ -1175,8 +1175,8 @@ * @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. @@ -1187,8 +1187,8 @@ * @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. @@ -1202,8 +1202,8 @@ * @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. @@ -1215,8 +1215,8 @@ * @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; } @@ -1229,8 +1229,8 @@ * @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; } @@ -1248,8 +1248,8 @@ * @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. @@ -1264,8 +1264,8 @@ * @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. @@ -1278,8 +1278,8 @@ * @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. @@ -1290,8 +1290,8 @@ * @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); } @@ -1307,8 +1307,8 @@ * @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. @@ -1316,8 +1316,8 @@ * @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. @@ -1341,8 +1341,8 @@ * @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. @@ -1369,7 +1369,8 @@ * @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); /** @@ -1385,11 +1386,10 @@ * @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(). * @@ -1402,8 +1402,8 @@ * @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); @@ -1419,9 +1419,5 @@ */ #define cxJsonCloneFunc ((cx_clone_func) cx_json_clone_func) -#ifdef __cplusplus -} -#endif - #endif /* UCX_JSON_H */ diff -r 8b0f162ac88e -r 36c0fb2b60b2 src/cx/kv_list.h --- a/src/cx/kv_list.h Sun Dec 28 15:45:39 2025 +0100 +++ b/src/cx/kv_list.h Sun Dec 28 17:31:20 2025 +0100 @@ -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 @@ * @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 @@ * @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 @@ * @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 @@ * @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 @@ * @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 @@ * @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 @@ */ #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 @@ * @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 @@ * @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 @@ */ #define cxKvListAdd(list, key, value) cxKvListInsert(list, (list)->collection.size, key, value) -#ifdef __cplusplus -} // extern "C" -#endif - #endif // UCX_KV_LIST_H diff -r 8b0f162ac88e -r 36c0fb2b60b2 src/cx/linked_list.h --- a/src/cx/linked_list.h Sun Dec 28 15:45:39 2025 +0100 +++ b/src/cx/linked_list.h Sun Dec 28 17:31:20 2025 +0100 @@ -39,10 +39,6 @@ #include "common.h" #include "list.h" -#ifdef __cplusplus -extern "C" { -#endif - /** * Metadata for a linked list. */ @@ -94,8 +90,8 @@ * @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 @@ * @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 @@ * @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 @@ * @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 @@ * @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 @@ * @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 @@ * @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 @@ * @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 @@ * @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 @@ * @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 @@ * @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 @@ * @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 @@ * @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 @@ * @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 @@ * @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 @@ * @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 @@ * @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 @@ * @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 @@ * @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 @@ * @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); /** @@ -450,8 +446,8 @@ * @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 +469,8 @@ * @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 +494,8 @@ * @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 +517,8 @@ * @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 +528,8 @@ * @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 +543,8 @@ * @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 +560,10 @@ * @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 +577,8 @@ * @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); /** @@ -599,8 +594,8 @@ * @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 +606,7 @@ * @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 -r 8b0f162ac88e -r 36c0fb2b60b2 src/cx/list.h --- a/src/cx/list.h Sun Dec 28 15:45:39 2025 +0100 +++ b/src/cx/list.h Sun Dec 28 17:31:20 2025 +0100 @@ -39,10 +39,6 @@ #include "common.h" #include "collection.h" -#ifdef __cplusplus -extern "C" { -#endif - /** * List class type. */ @@ -206,8 +202,8 @@ * @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 @@ * @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 @@ * @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 @@ * * @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 @@ * @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 @@ * @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 @@ * @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 @@ * @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 @@ * @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 @@ * @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 @@ * @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 @@ * @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 @@ * @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 @@ * @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 @@ * @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 @@ * @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 @@ * @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 @@ * @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 @@ * @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 @@ * * @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 @@ * @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 @@ * @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 @@ * @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 @@ * @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 @@ * @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 @@ * @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 @@ * @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 @@ * @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 @@ * * @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 @@ * @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 @@ * @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 @@ * @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 @@ * @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 @@ * @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 @@ * @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 @@ * @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 @@ * @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 @@ * @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 @@ * @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 @@ * @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 @@ * @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 @@ * 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 @@ * * @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 @@ * @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 @@ * * @param list the list that shall be freed */ -CX_EXPORT void cxListFree(CxList *list); +CX_EXTERN +void cxListFree(CxList *list); /** @@ -989,8 +986,8 @@ * @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 @@ * @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 @@ * @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 @@ * @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 @@ * @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 @@ * @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 @@ * @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 @@ * @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 @@ * @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 @@ * @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 -r 8b0f162ac88e -r 36c0fb2b60b2 src/cx/map.h --- a/src/cx/map.h Sun Dec 28 15:45:39 2025 +0100 +++ b/src/cx/map.h Sun Dec 28 17:31:20 2025 +0100 @@ -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 @@ * * @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 @@ * * @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 @@ * @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 @@ * @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 @@ * @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 @@ * @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 @@ * @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 @@ * @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 @@ * @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 @@ * @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 @@ */ #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 @@ * @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 @@ * @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 @@ * @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 @@ * @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 @@ * @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 @@ * @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 @@ * @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 @@ * @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 @@ * @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 @@ * @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 @@ * @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 @@ * @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 @@ * @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 -r 8b0f162ac88e -r 36c0fb2b60b2 src/cx/mempool.h --- a/src/cx/mempool.h Sun Dec 28 15:45:39 2025 +0100 +++ b/src/cx/mempool.h Sun Dec 28 17:31:20 2025 +0100 @@ -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 @@ * * @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 @@ * @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 @@ * @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 @@ * @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 @@ * @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 @@ * @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 @@ * * @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 @@ * * @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 @@ * @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 @@ * @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 @@ * @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 @@ * @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 -r 8b0f162ac88e -r 36c0fb2b60b2 src/cx/printf.h --- a/src/cx/printf.h Sun Dec 28 15:45:39 2025 +0100 +++ b/src/cx/printf.h Sun Dec 28 17:31:20 2025 +0100 @@ -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 @@ * @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 @@ * @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 @@ * @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 @@ * @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 @@ * @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 @@ * @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 @@ * @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 @@ * @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 -r 8b0f162ac88e -r 36c0fb2b60b2 src/cx/properties.h --- a/src/cx/properties.h Sun Dec 28 15:45:39 2025 +0100 +++ b/src/cx/properties.h Sun Dec 28 17:31:20 2025 +0100 @@ -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 @@ * @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 @@ * * @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 @@ * * @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 @@ * @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 @@ * @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 @@ * @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 @@ * @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 @@ * @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 @@ #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 -r 8b0f162ac88e -r 36c0fb2b60b2 src/cx/streams.h --- a/src/cx/streams.h Sun Dec 28 15:45:39 2025 +0100 +++ b/src/cx/streams.h Sun Dec 28 17:31:20 2025 +0100 @@ -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 @@ * 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 @@ * @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 @@ #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 -r 8b0f162ac88e -r 36c0fb2b60b2 src/cx/string.h --- a/src/cx/string.h Sun Dec 28 15:45:39 2025 +0100 +++ b/src/cx/string.h Sun Dec 28 17:31:20 2025 +0100 @@ -159,7 +159,7 @@ * * @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; @@ -183,7 +183,7 @@ * * @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; @@ -208,7 +208,7 @@ * * @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; @@ -233,7 +233,7 @@ * * @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; @@ -242,40 +242,39 @@ } #ifdef __cplusplus -cx_attr_nodiscard +CX_NODISCARD CX_CPPDECL cxmutstr cx_strcast_m(cxmutstr str) { return str; } -cx_attr_nodiscard +CX_NODISCARD CX_CPPDECL cxstring cx_strcast_m(cxstring str) { return str; } -cx_attr_nodiscard +CX_NODISCARD CX_CPPDECL cxmutstr cx_strcast_m(char *str) { return cx_mutstr(str); } -cx_attr_nodiscard +CX_NODISCARD CX_CPPDECL cxmutstr cx_strcast_m(unsigned char *str) { return cx_mutstr(reinterpret_cast(str)); } -cx_attr_nodiscard +CX_NODISCARD CX_CPPDECL cxstring cx_strcast_m(const char *str) { return cx_str(str); } -cx_attr_nodiscard +CX_NODISCARD CX_CPPDECL cxstring cx_strcast_m(const unsigned char *str) { return cx_str(reinterpret_cast(str)); } -cx_attr_nodiscard +CX_NODISCARD CX_CPPDECL cxstring cx_strcast_(cxmutstr str) { return cx_strn(str.ptr, str.length); } -cx_attr_nodiscard +CX_NODISCARD CX_CPPDECL cxstring cx_strcast_(cxstring str) { return str; } #define cx_strcast(s) cx_strcast_(cx_strcast_m(s)) -extern "C" { #else /** * Internal function, do not use. @@ -284,7 +283,7 @@ * @see cx_strcast_m() * @see cx_strcast() */ -cx_attr_nodiscard +CX_NODISCARD CX_INLINE cxmutstr cx_strcast_cxms(cxmutstr str) { return str; } @@ -295,7 +294,7 @@ * @see cx_strcast_m() * @see cx_strcast() */ -cx_attr_nodiscard +CX_NODISCARD CX_INLINE cxstring cx_strcast_cxs(cxstring str) { return str; } @@ -307,7 +306,7 @@ * @see cx_strcast_m() * @see cx_strcast() */ -cx_attr_nodiscard +CX_NODISCARD CX_INLINE cxmutstr cx_strcast_uc(unsigned char *str) { return cx_mutstr((char*)str); } @@ -319,7 +318,7 @@ * @see cx_strcast_m() * @see cx_strcast() */ -cx_attr_nodiscard +CX_NODISCARD CX_INLINE cxmutstr cx_strcast_c(char *str) { return cx_mutstr(str); } @@ -331,7 +330,7 @@ * @see cx_strcast_m() * @see cx_strcast() */ -cx_attr_nodiscard +CX_NODISCARD CX_INLINE cxstring cx_strcast_ucc(const unsigned char *str) { return cx_str((const char*)str); } @@ -343,7 +342,7 @@ * @see cx_strcast_m() * @see cx_strcast() */ -cx_attr_nodiscard +CX_NODISCARD CX_INLINE cxstring cx_strcast_cc(const char *str) { return cx_str(str); } @@ -419,7 +418,8 @@ * * @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. @@ -434,8 +434,8 @@ * @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. @@ -450,8 +450,8 @@ * @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. @@ -496,8 +496,8 @@ * @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. @@ -519,8 +519,8 @@ * @param ... all other UCX strings * @return the concatenated string */ -cx_attr_nonnull -CX_EXPORT cxmutstr cx_strcat_a(const CxAllocator *alloc, +CX_EXTERN CX_NONNULL +cxmutstr cx_strcat_a(const CxAllocator *alloc, cxmutstr str, size_t count, ...); /** @@ -553,8 +553,8 @@ * @return a substring of @p string starting at @p start * @see cx_strsubsl() */ -cx_attr_nodiscard -CX_EXPORT cxstring cx_strsubsl_(cxstring string, size_t start, size_t length); +CX_EXTERN CX_NODISCARD +cxstring cx_strsubsl_(cxstring string, size_t start, size_t length); /** * Returns a substring. @@ -566,19 +566,20 @@ * @return a substring of @p string starting at @p start * @see cx_strsubs() */ -cx_attr_nodiscard -CX_EXPORT cxstring cx_strsubs_(cxstring string, size_t start); +CX_EXTERN CX_NODISCARD +cxstring cx_strsubs_(cxstring string, size_t start); -CX_INLINE cxmutstr cx_strsubs_m_(cxmutstr string, size_t start) { +CX_INLINE +cxmutstr cx_strsubs_m_(cxmutstr string, size_t start) { return cx_mutstrcast(cx_strsubs_(cx_strcast(string), start)); } -CX_INLINE cxmutstr cx_strsubsl_m_(cxmutstr string, size_t start, size_t length) { +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 -} // extern "C" CX_CPPDECL cxstring cx_strsubs_cpp_(cxstring string, size_t start) { return cx_strsubs_(string, start); } @@ -593,7 +594,6 @@ } #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) -extern "C" { #else /** * Returns a substring starting at the specified location. @@ -644,7 +644,8 @@ * @return the character at the index * @see cx_strat() */ -CX_INLINE char cx_strat_(cxstring str, off_t index) { +CX_INLINE +char cx_strat_(cxstring str, off_t index) { size_t i; if (index >= 0) { i = index; @@ -684,8 +685,8 @@ * * @see cx_strchr_m() */ -cx_attr_nodiscard -CX_EXPORT cxstring cx_strchr(cxstring string, int chr); +CX_EXTERN CX_NODISCARD +cxstring cx_strchr(cxstring string, int chr); /** * Returns a substring starting at the location of the first occurrence of the @@ -699,8 +700,8 @@ * * @see cx_strchr() */ -cx_attr_nodiscard -CX_EXPORT cxmutstr cx_strchr_m(cxmutstr string, int chr); +CX_EXTERN CX_NODISCARD +cxmutstr cx_strchr_m(cxmutstr string, int chr); /** * Returns a substring starting at the location of the last occurrence of the @@ -714,8 +715,8 @@ * * @see cx_strrchr_m() */ -cx_attr_nodiscard -CX_EXPORT cxstring cx_strrchr(cxstring string, int chr); +CX_EXTERN CX_NODISCARD +cxstring cx_strrchr(cxstring string, int chr); /** * Returns a substring starting at the location of the last occurrence of the @@ -729,8 +730,8 @@ * * @see cx_strrchr() */ -cx_attr_nodiscard -CX_EXPORT cxmutstr cx_strrchr_m(cxmutstr string, int chr); +CX_EXTERN CX_NODISCARD +cxmutstr cx_strrchr_m(cxmutstr string, int chr); /** * Searches for a specific substring. @@ -743,8 +744,8 @@ * 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); +CX_EXTERN CX_NODISCARD +cxstring cx_strstr_(cxstring haystack, cxstring needle); /** * Returns a substring starting at the location of the first occurrence of the @@ -774,8 +775,8 @@ * or an empty string, if the sequence is not contained * @see cx_strstr_m() */ -cx_attr_nodiscard -CX_EXPORT cxmutstr cx_strstr_m_(cxmutstr haystack, cxstring needle); +CX_EXTERN CX_NODISCARD +cxmutstr cx_strstr_m_(cxmutstr haystack, cxstring needle); /** * Returns a substring starting at the location of the first occurrence of the @@ -806,8 +807,8 @@ * @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); /** @@ -823,8 +824,8 @@ * @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); @@ -841,8 +842,8 @@ * @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); /** @@ -858,8 +859,8 @@ * @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); @@ -946,8 +947,8 @@ * @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. @@ -967,8 +968,8 @@ * @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. @@ -993,8 +994,8 @@ * @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. @@ -1006,9 +1007,8 @@ * @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. @@ -1022,8 +1022,8 @@ * @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. @@ -1064,8 +1064,8 @@ * @param string the string that shall be trimmed * @return the trimmed string */ -cx_attr_nodiscard -CX_EXPORT cxstring cx_strtrim(cxstring string); +CX_EXTERN CX_NODISCARD +cxstring cx_strtrim(cxstring string); /** * Omits leading and trailing spaces. @@ -1076,8 +1076,8 @@ * @param string the string that shall be trimmed * @return the trimmed string */ -cx_attr_nodiscard -CX_EXPORT cxmutstr cx_strtrim_m(cxmutstr string); +CX_EXTERN CX_NODISCARD +cxmutstr cx_strtrim_m(cxmutstr string); /** * Checks if a string has a specific prefix. @@ -1087,8 +1087,8 @@ * @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. @@ -1108,8 +1108,8 @@ * @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. @@ -1129,8 +1129,8 @@ * @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. @@ -1150,8 +1150,8 @@ * @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. @@ -1163,7 +1163,6 @@ */ #define cx_strcasesuffix(string, suffix) cx_strcasesuffix_(cx_strcast(string), cx_strcast(suffix)) - /** * Replaces a string with another string. * @@ -1180,8 +1179,8 @@ * @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); /** @@ -1268,8 +1267,8 @@ * @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. @@ -1292,11 +1291,10 @@ * @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 -} // extern "C" CX_CPPDECL cx_strtok_next(CxStrtokCtx *ctx, cxstring *token) { return cx_strtok_next_(ctx, token); } @@ -1305,7 +1303,6 @@ // but it works on all supported platforms return cx_strtok_next_(ctx, reinterpret_cast(token)); } -extern "C" { #else // ! __cplusplus /** * Returns the next token. @@ -1330,8 +1327,8 @@ * @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 * @@ -1351,8 +1348,8 @@ * @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. @@ -1368,8 +1365,8 @@ * @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. @@ -1385,8 +1382,8 @@ * @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. @@ -1402,8 +1399,8 @@ * @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. @@ -1419,8 +1416,8 @@ * @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. @@ -1436,8 +1433,8 @@ * @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. @@ -1453,8 +1450,8 @@ * @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. @@ -1470,8 +1467,8 @@ * @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. @@ -1487,8 +1484,8 @@ * @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. @@ -1504,8 +1501,8 @@ * @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. @@ -1521,8 +1518,8 @@ * @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. @@ -1538,8 +1535,8 @@ * @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. @@ -1555,8 +1552,8 @@ * @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. @@ -1572,8 +1569,8 @@ * @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. @@ -1589,8 +1586,8 @@ * @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. @@ -1606,8 +1603,8 @@ * @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. @@ -1623,8 +1620,8 @@ * @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. @@ -1640,8 +1637,8 @@ * @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. @@ -1657,8 +1654,8 @@ * @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. @@ -2304,8 +2301,4 @@ */ #define cx_strtod(str, output) cx_strtod_lc_(cx_strcast(str), output, '.', ",") -#ifdef __cplusplus -} // extern "C" -#endif - #endif //UCX_STRING_H diff -r 8b0f162ac88e -r 36c0fb2b60b2 src/cx/test.h --- a/src/cx/test.h Sun Dec 28 15:45:39 2025 +0100 +++ b/src/cx/test.h Sun Dec 28 17:31:20 2025 +0100 @@ -73,10 +73,6 @@ #include #include -#ifdef __cplusplus -extern "C" { -#endif - #ifndef __FUNCTION__ /** * Alias for the __func__ preprocessor macro. @@ -136,7 +132,7 @@ * @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 @@ * @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 @@ * @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 @@ #define CX_TEST_CALL_SUBROUTINE(name,...) \ name(_suite_,_output_,_writefnc_,_env_,__VA_ARGS__) -#ifdef __cplusplus -} -#endif - #endif /* UCX_TEST_H */ diff -r 8b0f162ac88e -r 36c0fb2b60b2 src/cx/tree.h --- a/src/cx/tree.h Sun Dec 28 15:45:39 2025 +0100 +++ b/src/cx/tree.h Sun Dec 28 17:31:20 2025 +0100 @@ -40,10 +40,6 @@ #include "collection.h" -#ifdef __cplusplus -extern "C" { -#endif - /** * A depth-first tree iterator. * @@ -213,15 +209,15 @@ * Releases internal memory of the given tree iterator. * @param iter the iterator */ -cx_attr_nonnull -CX_EXPORT void cxTreeIteratorDispose(CxTreeIterator *iter); +CX_EXTERN CX_NONNULL +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 cxTreeVisitorDispose(CxTreeVisitor *visitor); /** * Advises the iterator to skip the subtree below the current node and @@ -256,8 +252,8 @@ * @param loc_next offset in the node struct for the next pointer * @see cx_tree_unlink() */ -cx_attr_nonnull -CX_EXPORT void cx_tree_link(void *parent, void *node, +CX_EXTERN CX_NONNULL +void cx_tree_link(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); @@ -275,8 +271,8 @@ * @param loc_next offset in the node struct for the next pointer * @see cx_tree_link() */ -cx_attr_nonnull -CX_EXPORT void cx_tree_unlink(void *node, +CX_EXTERN CX_NONNULL +void cx_tree_unlink(void *node, ptrdiff_t loc_parent, ptrdiff_t loc_children, ptrdiff_t loc_last_child, ptrdiff_t loc_prev, ptrdiff_t loc_next); @@ -366,8 +362,8 @@ * 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, +CX_EXTERN CX_NONNULL CX_ACCESS_W(5) +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); @@ -385,7 +381,7 @@ * node matching the criteria is returned. * * @param root the root node -* @param depth the maximum depth (zero=indefinite, one=just root) + * @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 @@ -395,8 +391,8 @@ * 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, +CX_EXTERN CX_NONNULL CX_ACCESS_W(5) +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); @@ -420,8 +416,8 @@ * @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); /** @@ -442,8 +438,8 @@ * @return the new tree visitor * @see cxTreeVisitorDispose() */ -cx_attr_nodiscard -CX_EXPORT CxTreeVisitor cx_tree_visitor(void *root, +CX_EXTERN CX_NODISCARD +CxTreeVisitor cx_tree_visitor(void *root, ptrdiff_t loc_children, ptrdiff_t loc_next); /** @@ -504,8 +500,8 @@ * @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_EXTERN CX_NONNULL_ARG(1, 3, 4, 6, 7) CX_ACCESS_W(6) +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, @@ -548,8 +544,8 @@ * @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_EXTERN CX_NONNULL_ARG(1, 4, 5, 7, 8) CX_ACCESS_W(7) +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, @@ -600,8 +596,8 @@ * @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_EXTERN CX_NONNULL_ARG(1, 2, 3, 5, 6) CX_ACCESS_W(5) +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, @@ -786,8 +782,8 @@ * @param node the node 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); /** @@ -825,7 +821,8 @@ * * @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. @@ -851,8 +848,8 @@ * @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_EXTERN CX_NONNULL_ARG(2, 3, 4) CX_NODISCARD CX_MALLOC CX_DEALLOC(cxTreeFree, 1) +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); @@ -899,8 +896,8 @@ * @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_NONNULL_ARG(2) CX_NODISCARD CX_MALLOC CX_DEALLOC(cxTreeFree, 1) +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); @@ -916,8 +913,8 @@ * @retval zero success * @retval non-zero failure */ -cx_attr_nonnull -CX_EXPORT int cxTreeInsert(CxTree *tree, const void *data); +CX_EXTERN CX_NONNULL +int cxTreeInsert(CxTree *tree, const void *data); /** * Inserts elements provided by an iterator efficiently into the tree. @@ -931,8 +928,8 @@ * @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); +CX_EXTERN CX_NONNULL +size_t cxTreeInsertIter(CxTree *tree, CxIteratorBase *iter, size_t n); /** * Inserts an array of data efficiently into the tree. @@ -947,8 +944,8 @@ * @param n the number of elements in the array * @return the number of elements that could be successfully inserted */ -cx_attr_nonnull -CX_EXPORT size_t cxTreeInsertArray(CxTree *tree, const void *data, size_t elem_size, size_t n); +CX_EXTERN CX_NONNULL +size_t cxTreeInsertArray(CxTree *tree, const void *data, size_t elem_size, size_t n); /** * Searches the data in the specified tree. @@ -961,8 +958,8 @@ * @param data the data to search for * @return the first matching node, or @c NULL when the data cannot be found */ -cx_attr_nonnull cx_attr_nodiscard -CX_EXPORT void *cxTreeFind(CxTree *tree, const void *data); +CX_EXTERN CX_NONNULL CX_NODISCARD +void *cxTreeFind(CxTree *tree, const void *data); /** * Searches the data in the specified subtree. @@ -983,8 +980,8 @@ * @param max_depth the maximum search depth * @return the first matching node, or @c NULL when the data cannot be found */ -cx_attr_nonnull cx_attr_nodiscard -CX_EXPORT void *cxTreeFindInSubtree(CxTree *tree, const void *data, void *subtree_root, size_t max_depth); +CX_EXTERN CX_NONNULL CX_NODISCARD +void *cxTreeFindInSubtree(CxTree *tree, const void *data, void *subtree_root, size_t max_depth); /** * Determines the size of the specified subtree. @@ -993,8 +990,8 @@ * @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 +1000,8 @@ * @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 +1009,8 @@ * @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 +1018,8 @@ * @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 +1033,8 @@ * @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 +1046,8 @@ * @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 +CxTreeVisitor cxTreeVisitSubtree(CxTree *tree, void *node); /** * Creates a depth-first iterator for the specified tree. @@ -1061,8 +1058,8 @@ * @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,8 +1068,8 @@ * @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 +CxTreeVisitor cxTreeVisit(CxTree *tree); /** * Sets the (new) parent of the specified child. @@ -1085,8 +1082,8 @@ * @param child the node to add * @see cxTreeAddChildNode() */ -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. @@ -1103,8 +1100,8 @@ * @param child the node to add * @see cxTreeSetParent() */ -cx_attr_nonnull -CX_EXPORT void cxTreeAddChildNode(CxTree *tree, void *parent, void *child); +CX_EXTERN CX_NONNULL +void cxTreeAddChildNode(CxTree *tree, void *parent, void *child); /** * Creates a new node and adds it to the tree. @@ -1123,8 +1120,8 @@ * @return zero when the new node was created, non-zero on allocation failure * @see cxTreeInsert() */ -cx_attr_nonnull -CX_EXPORT int cxTreeAddChild(CxTree *tree, void *parent, const void *data); +CX_EXTERN CX_NONNULL +int cxTreeAddChild(CxTree *tree, void *parent, const void *data); /** * A function that is invoked when a node needs to be re-linked to a new parent. @@ -1158,8 +1155,8 @@ * 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 +1169,8 @@ * @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 +1190,7 @@ * 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 -r 8b0f162ac88e -r 36c0fb2b60b2 src/hash_key.c --- a/src/hash_key.c Sun Dec 28 15:45:39 2025 +0100 +++ b/src/hash_key.c Sun Dec 28 17:31:20 2025 +0100 @@ -63,14 +63,14 @@ 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 ; } diff -r 8b0f162ac88e -r 36c0fb2b60b2 src/json.c --- a/src/json.c Sun Dec 28 15:45:39 2025 +0100 +++ b/src/json.c Sun Dec 28 17:31:20 2025 +0100 @@ -1499,7 +1499,7 @@ } 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; } @@ -1511,7 +1511,8 @@ return ret; \ } else { \ *target = *ret; \ - cxFree(allocator, ret); \ + ret->type = CX_JSON_UNINITIALIZED; \ + cxJsonValueFree(ret); \ return target; \ } \ } diff -r 8b0f162ac88e -r 36c0fb2b60b2 src/kv_list.c --- a/src/kv_list.c Sun Dec 28 15:45:39 2025 +0100 +++ b/src/kv_list.c Sun Dec 28 17:31:20 2025 +0100 @@ -515,7 +515,7 @@ } 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 -r 8b0f162ac88e -r 36c0fb2b60b2 src/list.c --- a/src/list.c Sun Dec 28 15:45:39 2025 +0100 +++ b/src/list.c Sun Dec 28 17:31:20 2025 +0100 @@ -63,33 +63,33 @@ // -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 -r 8b0f162ac88e -r 36c0fb2b60b2 src/map.c --- a/src/map.c Sun Dec 28 15:45:39 2025 +0100 +++ b/src/map.c Sun Dec 28 17:31:20 2025 +0100 @@ -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 -r 8b0f162ac88e -r 36c0fb2b60b2 src/tree.c --- a/src/tree.c Sun Dec 28 15:45:39 2025 +0100 +++ b/src/tree.c Sun Dec 28 17:31:20 2025 +0100 @@ -417,7 +417,7 @@ 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) { node = tree_next(node); diff -r 8b0f162ac88e -r 36c0fb2b60b2 tests/test_allocator.c --- a/tests/test_allocator.c Sun Dec 28 15:45:39 2025 +0100 +++ b/tests/test_allocator.c Sun Dec 28 17:31:20 2025 +0100 @@ -297,9 +297,9 @@ } static void *test_allocator_mock_failing_realloc( - cx_attr_unused void *p, - cx_attr_unused void *d, - cx_attr_unused size_t n + CX_UNUSED void *p, + CX_UNUSED void *d, + CX_UNUSED size_t n ) { return NULL; } diff -r 8b0f162ac88e -r 36c0fb2b60b2 tests/test_hash_map.c --- a/tests/test_hash_map.c Sun Dec 28 15:45:39 2025 +0100 +++ b/tests/test_hash_map.c Sun Dec 28 17:31:20 2025 +0100 @@ -359,7 +359,7 @@ } static void test_advanced_destructor( - cx_attr_unused void *unused, + CX_UNUSED void *unused, void *d ) { test_simple_destructor(d); diff -r 8b0f162ac88e -r 36c0fb2b60b2 tests/test_json.c --- a/tests/test_json.c Sun Dec 28 15:45:39 2025 +0100 +++ b/tests/test_json.c Sun Dec 28 17:31:20 2025 +0100 @@ -1041,7 +1041,8 @@ CX_TEST_ASSERT(result == CX_JSON_NO_ERROR); CX_TEST_ASSERT(cxJsonIsObject(v)); CxJsonValue *value = cxJsonObjGet(v, "value"); - CX_TEST_ASSERT(cxJsonAsString(value)); + CX_TEST_ASSERT(cxJsonIsString(value)); + CX_TEST_ASSERT(!cx_strcmp(cxJsonAsCxString(value), "test")); cxJsonValueFree(v); // read array cxJsonFill(&json, "[ 0, 1, 2, 3, 4, 5 ]\n"); diff -r 8b0f162ac88e -r 36c0fb2b60b2 tests/test_list.c --- a/tests/test_list.c Sun Dec 28 15:45:39 2025 +0100 +++ b/tests/test_list.c Sun Dec 28 17:31:20 2025 +0100 @@ -1916,7 +1916,7 @@ } #define roll_out_test_combos(name, body) \ static CX_TEST_SUBROUTINE(test_list_verify_##name, CxList *list, \ - cx_attr_unused bool isptrlist) body \ + CX_UNUSED bool isptrlist) body \ roll_out_test_invokers(name) static void set_default_class_funcs(CxList *list, cx_list_class *defaulted_cl) { @@ -1935,7 +1935,7 @@ set_default_class_funcs(list, &defaulted_cl) #define roll_out_test_combos_with_defaulted_funcs(name, body) \ static CX_TEST_SUBROUTINE(test_list_verify_##name, CxList *list, \ - cx_attr_unused bool isptrlist) body \ + CX_UNUSED bool isptrlist) body \ roll_out_test_invokers(name) \ CX_TEST(test_list_llm_##name) { \ set_up_combo \ @@ -2432,7 +2432,7 @@ }) static unsigned test_remove_array_destr_ctr; -static void test_remove_array_destr(cx_attr_unused void *d) { +static void test_remove_array_destr(CX_UNUSED void *d) { test_remove_array_destr_ctr++; } @@ -2979,7 +2979,7 @@ destr_test_ctr++; } -static void advanced_destr_test_fun(cx_attr_unused void *u, void *data) { +static void advanced_destr_test_fun(CX_UNUSED void *u, void *data) { simple_destr_test_fun(data); } diff -r 8b0f162ac88e -r 36c0fb2b60b2 tests/test_mempool.c --- a/tests/test_mempool.c Sun Dec 28 15:45:39 2025 +0100 +++ b/tests/test_mempool.c Sun Dec 28 17:31:20 2025 +0100 @@ -34,11 +34,11 @@ static unsigned test_mempool_destructor_called; -static void test_mempool_destructor(cx_attr_unused void *mem) { +static void test_mempool_destructor(CX_UNUSED void *mem) { test_mempool_destructor_called++; } -static void test_mempool_destructor2(void *data, cx_attr_unused void *mem) { +static void test_mempool_destructor2(void *data, CX_UNUSED void *mem) { int *ctr = data; *ctr = *ctr + 1; } diff -r 8b0f162ac88e -r 36c0fb2b60b2 tests/test_tree.c --- a/tests/test_tree.c Sun Dec 28 15:45:39 2025 +0100 +++ b/tests/test_tree.c Sun Dec 28 17:31:20 2025 +0100 @@ -2093,8 +2093,8 @@ static void test_tree_remove_node_relink_mock( void *node, - cx_attr_unused const void *oldp, - cx_attr_unused const void *newp + CX_UNUSED const void *oldp, + CX_UNUSED const void *newp ) { tree_node_file * n = node; // this function fakes the relink logic in below test