cxmutstr url;
if(add_separator) {
- url = cx_strcat(3, base, cx_strn("/", 1), path);
+ url = cx_strcat(CX_NULLSTR, 3, base, cx_strn("/", 1), path);
} else {
- url = cx_strcat(2, base, path);
+ url = cx_strcat(CX_NULLSTR, 2, base, path);
}
return url.ptr;
#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
) {
}
static void *cx_calloc_stdlib(
- cx_attr_unused void *d,
+ CX_UNUSED void *d,
size_t nmemb,
size_t size
) {
}
static void cx_free_stdlib(
- cx_attr_unused void *d,
+ CX_UNUSED void *d,
void *mem
) {
free(mem);
if (array->capacity < req_capacity) {
const size_t new_capacity = cx_array_grow_capacity(array->capacity,req_capacity);
if (cxReallocateArray(allocator, &array->data, new_capacity, elem_size)) {
- return -1; // LCOV_EXCL_LINE
+ return -1;
}
array->capacity = new_capacity;
}
}
#endif
+#if defined(WITH_QSORT_R) && defined(__APPLE__)
+// macOS uses a different comparefunc signature for qsort_r
+typedef struct QsortCmpFuncWrapper {
+ cx_compare_func2 fn;
+ void *context;
+} QsortCmpFuncWrapper;
+
+static int sort_comparefunc(void *context, const void *left, const void *right){
+ QsortCmpFuncWrapper *w = context;
+ return w->fn(left, right, w->context);
+}
+#endif
+
void cx_array_qsort_c(void *array, size_t nmemb, size_t size,
cx_compare_func2 fn, void *context) {
#ifdef WITH_QSORT_R
+#ifndef __APPLE__
qsort_r(array, nmemb, size, fn, context);
+#else
+ QsortCmpFuncWrapper wrapper;
+ wrapper.fn = fn;
+ wrapper.context = context;
+ qsort_r(array, nmemb, size, &wrapper, sort_comparefunc);
+#endif
#else
cx_array_fn_for_qsort = fn;
cx_array_context_for_qsort = context;
#include "common.h"
-#ifdef __cplusplus
-extern "C" {
-#endif
-
/**
* The class definition for an allocator.
*/
*
* @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.
* @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.
* @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,
* @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.
* @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
* @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.
* @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);
/**
* @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,
* @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);
/**
* @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.
* @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.
*
* @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
#include "list.h"
-#ifdef __cplusplus
-extern "C" {
-#endif
-
/**
* The maximum item size in an array list that fits into
* a stack buffer when swapped.
* @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.
* @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.
* @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.
* @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.
* @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);
/**
* @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);
* @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);
* @retval zero success
* @retval non-zero a re-allocation was necessary but failed
*/
-#define cx_array_insert_sorted_ca(allocator, array, element, cmp_func) \
+#define cx_array_insert_sorted_ca(allocator, array, element, cmp_func, context) \
cx_array_insert_sorted_c_(allocator, (CxArray*)&(array), sizeof((array).data[0]), (void*)&(element), 1, cmp_func, context, true)
/**
* @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);
/**
* @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);
/**
* @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);
/**
*
* @param array the name of the array
* @param fn (@c cx_compare_func) the compare function
- * @param context (@c void*) the context for the compare function
*/
#define cx_array_sort(array, fn) \
cx_array_sort_((CxArray*)&(array), sizeof((array).data[0]), fn)
* @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.
* @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.
* @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.
* @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.
* @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);
/**
* @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);
/**
* @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);
* @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);
/**
* @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);
/**
* @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);
/**
* @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.
* @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
#include "allocator.h"
#include "string.h"
-#ifdef __cplusplus
-extern "C" {
-#endif
-
/**
* No buffer features enabled (all flags cleared).
*/
* @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);
/**
* @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.
* @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.
* @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);
/**
* @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.
* @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.
* @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);
/**
* @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.
* @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.
* @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.
* @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.
* 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.
* @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.
* @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.
* @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.
* @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.
* @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);
/**
* @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);
/**
* @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);
/**
* 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.
* @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.
* @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().
* @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().
* @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.
* @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);
}
* @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
#include "iterator.h"
#include "compare.h"
-#ifdef __cplusplus
-extern "C" {
-#endif
-
/**
* Special constant used for creating collections that are storing pointers.
*/
if ((c)->collection.simple_destructor) cx_invoke_simple_destructor(c,e); \
if ((c)->collection.advanced_destructor) cx_invoke_advanced_destructor(c,e)
-#ifdef __cplusplus
-} // extern "C"
-#endif
+/**
+ * Invokes all available destructor functions for a specific element.
+ *
+ * Usually only used by collection implementations. There should be no need
+ * to invoke this macro manually.
+ *
+ * In contrast to cx_invoke_destructor(), this macro does not automatically
+ * dereference pointers to the elements when cxCollectionStoresPointers()
+ * returns true.
+ *
+ * @param c a pointer to a struct that contains #CX_COLLECTION_BASE
+ * @param e pointer to the element
+ */
+#define cx_invoke_destructor_raw(c, e) \
+ if ((c)->collection.simple_destructor) (c)->collection.simple_destructor(e); \
+ if ((c)->collection.advanced_destructor) (c)->collection.advanced_destructor((c)->collection.destructor_data, e)
+
#endif // UCX_COLLECTION_H
/**
* 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
/**
* @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__
* 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.
* 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.
* 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__))
// ---------------------------------------------------------------------------
#ifdef _MSC_VER
#define cx_thread_local __declspec(thread)
#else // ! _MSC_VER
-#if __STDC_VERSION__ < 202300L
+#if !defined __STDC_VERSION__ || __STDC_VERSION__ < 202300L
+/** Platform independent thread-local macro. */
#define cx_thread_local _Thread_local
#else // C23 or newer
+/** Platform independent thread-local macro. */
#define cx_thread_local thread_local
#endif // C23
#endif // _MSC_VER
#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.
* @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
#include "common.h"
-#ifdef __cplusplus
-extern "C" {
-#endif
-
/**
* A comparator function comparing two arbitrary values.
*
* 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.
* @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.
* @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.
* @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.
* @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.
* @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.
* @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.
* @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.
* @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.
* @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.
* @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.
* @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.
* @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.
* @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.
* @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.
* @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.
* @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.
* @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.
* @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.
* @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.
* @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.
* @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.
* @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.
* @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.
* @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.
* @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.
* @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.
* @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.
* @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.
* @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.
* @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.
* @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.
* @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.
* @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.
* @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.
* @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 {
* @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
#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 {
/**
* @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.
* @param x the integer
* @return the hash
*/
-CX_EXPORT uint32_t cx_hash_u32(uint32_t x);
+CX_INLINE
+uint32_t cx_hash_u32(uint32_t x) {
+ x = ((x >> 16) ^ x) * 0x45d9f3bu;
+ x = ((x >> 16) ^ x) * 0x45d9f3bu;
+ x = (x >> 16) ^ x;
+ return x;
+}
/**
* Mixes up a 64-bit integer to be used as a hash.
* @param x the integer
* @return the hash
*/
-CX_EXPORT uint64_t cx_hash_u64(uint64_t x);
+CX_INLINE
+uint64_t cx_hash_u64(uint64_t x){
+ x = (x ^ (x >> 30)) * UINT64_C(0xbf58476d1ce4e5b9);
+ x = (x ^ (x >> 27)) * UINT64_C(0x94d049bb133111eb);
+ x = x ^ (x >> 31);
+ return x;
+}
+
+/**
+ * Computes a hash key for an arbitrary object.
+ *
+ * The computation uses the in-memory representation that might not be
+ * the same on different platforms. Therefore, this hash should not be
+ * used for data exchange with different machines.
+ *
+ * @param obj a pointer to an arbitrary object
+ * @param len the length of the object in memory
+ * @return the hash key
+ */
+CX_EXTERN CX_NODISCARD CX_ACCESS_R(1, 2)
+CxHashKey cx_hash_key(const void *obj, size_t len);
/**
* Computes a hash key from a 32-bit integer.
* @param x the integer
* @return the hash key
*/
-cx_attr_nodiscard
-CX_EXPORT CxHashKey cx_hash_key_u32(uint32_t x);
+CX_NODISCARD CX_INLINE
+CxHashKey cx_hash_key_u32(uint32_t x) {
+ CxHashKey key;
+ key.data = NULL;
+ key.len = 0;
+ key.hash = cx_hash_u32(x);
+ return key;
+}
/**
* Computes a hash key from a 64-bit integer.
* @param x the integer
* @return the hash key
*/
-cx_attr_nodiscard
-CX_EXPORT CxHashKey cx_hash_key_u64(uint64_t x);
+CX_NODISCARD CX_INLINE
+CxHashKey cx_hash_key_u64(uint64_t x) {
+ CxHashKey key;
+ key.data = NULL;
+ key.len = 0;
+ key.hash = cx_hash_u64(x);
+ return key;
+}
/**
* Computes a hash key from a string.
* @param str the string
* @return the hash key
*/
-cx_attr_nodiscard cx_attr_cstr_arg(1)
-CX_EXPORT CxHashKey cx_hash_key_str(const char *str);
+CX_NODISCARD CX_CSTR_ARG(1) CX_INLINE
+CxHashKey cx_hash_key_str(const char *str) {
+ return cx_hash_key((const void*)str, str == NULL ? 0 : strlen(str));
+}
/**
* Computes a hash key from a string.
* @param str the string
* @return the hash key
*/
-cx_attr_nodiscard cx_attr_cstr_arg(1)
-CX_EXPORT CxHashKey cx_hash_key_ustr(const unsigned char *str);
+CX_NODISCARD CX_CSTR_ARG(1) CX_INLINE
+CxHashKey cx_hash_key_ustr(const unsigned char *str) {
+ return cx_hash_key((const void*)str, str == NULL ? 0 : strlen((const char*)str));
+}
/**
* Computes a hash key from a byte array.
* @param len the length
* @return the hash key
*/
-cx_attr_nodiscard cx_attr_access_r(1, 2)
-CX_EXPORT CxHashKey cx_hash_key_bytes(const unsigned char *bytes, size_t len);
-
-/**
- * Computes a hash key for an arbitrary object.
- *
- * The computation uses the in-memory representation that might not be
- * the same on different platforms. Therefore, this hash should not be
- * used for data exchange with different machines.
- *
- * @param obj a pointer to an arbitrary object
- * @param len the length of the object in memory
- * @return the hash key
- */
-cx_attr_nodiscard
-cx_attr_access_r(1, 2)
-CX_EXPORT CxHashKey cx_hash_key(const void *obj, size_t len);
+CX_NODISCARD CX_ACCESS_R(1, 2) CX_INLINE
+CxHashKey cx_hash_key_bytes(const unsigned char *bytes, size_t len) {
+ return cx_hash_key((const void*)bytes, len);
+}
/**
* Computes a hash key from a UCX string.
* @param str the string
* @return the hash key
*/
-cx_attr_nodiscard
-CX_EXPORT CxHashKey cx_hash_key_cxstr(cxstring str);
+CX_NODISCARD CX_INLINE
+CxHashKey cx_hash_key_cxstr(cxstring str) {
+ return cx_hash_key((void*)str.ptr, str.length);
+}
/**
* Computes a hash key from a UCX string.
* @param str the string
* @return the hash key
*/
-cx_attr_nodiscard
-CX_EXPORT CxHashKey cx_hash_key_mutstr(cxmutstr str);
+CX_NODISCARD CX_INLINE
+CxHashKey cx_hash_key_mutstr(cxmutstr str) {
+ return cx_hash_key((void*)str.ptr, str.length);
+}
/**
* The identity function for the CX_HASH_KEY() macro.
* You should never need to use this manually.
*
* @param key the key
- * @return a copy of the key
+ * @return a copy of the key (not the data)
*/
-cx_attr_nodiscard
-CX_INLINE CxHashKey cx_hash_key_identity(CxHashKey key) {
+CX_NODISCARD CX_INLINE
+CxHashKey cx_hash_key_identity(CxHashKey key) {
return key;
}
+/**
+ * The dereference function for the CX_HASH_KEY() macro.
+ * You should never need to use this manually.
+ *
+ * @param key a pointer to a key
+ * @return a copy of the key (not the data)
+ */
+CX_NODISCARD CX_INLINE
+CxHashKey cx_hash_key_deref(const CxHashKey *key) {
+ return *key;
+}
+
#ifndef __cplusplus
/**
* Creates a hash key from any of the supported types with implicit length.
*
- * Does nothing when passing a CxHashkey.
+ * Does nothing when passing a CxHashKey and dereferences CxHashKey pointers.
*
* Supported types are UCX strings, zero-terminated C strings,
* and 32-bit or 64-bit unsigned integers.
* @returns the @c CxHashKey
*/
#define CX_HASH_KEY(key) _Generic((key), \
+ CxHashKey*: cx_hash_key_deref, \
+ const CxHashKey*: cx_hash_key_deref, \
CxHashKey: cx_hash_key_identity, \
cxstring: cx_hash_key_cxstr, \
cxmutstr: cx_hash_key_mutstr, \
* @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.
* @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)
// ----------------------------------------------------------
return key;
}
+CX_CPPDECL CxHashKey CX_HASH_KEY(const CxHashKey *key) {
+ return *key;
+}
+
CX_CPPDECL CxHashKey CX_HASH_KEY(cxstring str) {
return cx_hash_key_cxstr(str);
}
#include "map.h"
-#ifdef __cplusplus
-extern "C" {
-#endif
-
/** Internal structure for an element of a hash map. */
struct cx_hash_map_element_s;
* @param buckets the initial number of buckets in this hash map
* @return a pointer to the new hash map
*/
-cx_attr_nodiscard cx_attr_malloc cx_attr_dealloc(cxMapFree, 1)
-CX_EXPORT CxMap *cxHashMapCreate(const CxAllocator *allocator,
+CX_EXTERN CX_NODISCARD CX_MALLOC CX_DEALLOC(cxMapFree, 1)
+CxMap *cxHashMapCreate(const CxAllocator *allocator,
size_t itemsize, size_t buckets);
/**
* @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
#include "common.h"
-#ifdef __cplusplus
-extern "C" {
-#endif
-
/**
* Common data for all iterators.
*/
*/
#define cxIteratorFlagRemoval(iter) ((iter).base.remove = (iter).base.allow_remove)
-/**
- * Obtains a reference to an arbitrary iterator.
- *
- * This is useful for APIs that expect some iterator as an argument.
- *
- * @param iter the iterator
- * @return (@c struct @c cx_iterator_base_s*) a pointer to the iterator
- */
-#define cxIteratorRef(iter) &((iter).base)
-
/**
* Loops over an iterator.
*
* @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);
/**
* @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
#include "array_list.h"
#include "map.h"
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-
/**
* The type of the parsed token.
*/
* Reserved.
*/
CX_JSON_NOTHING, // this allows us to always return non-NULL values
+ /**
+ * No meaningful data.
+ */
+ CX_JSON_UNINITIALIZED,
/**
* A JSON object.
*/
*/
CxBuffer buffer;
- /**
- * Used internally.
- *
- * Remembers the prefix of the last uncompleted token.
- */
- CxJsonToken uncompleted;
-
/**
* A pointer to an intermediate state of the currently parsed value.
*
*/
cxmutstr uncompleted_member_name;
+ /**
+ * Internal buffer for uncompleted tokens.
+ */
+ cxmutstr uncompleted_content;
+
+ /**
+ * The expected type of the currently parsed, uncompleted token.
+ */
+ CxJsonTokenType uncompleted_tokentype;
+
/**
* State stack.
*/
*
* @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.
* @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.
* @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);
* @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.
* @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.
* @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.
* @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.
*
* @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.
* @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);
/**
* @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);
}
* @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);
/**
#define cxJsonFromString(allocator, str, value) \
cx_json_from_string(allocator, cx_strcast(str), value)
+/**
+ * Recursively deallocates the memory of a JSON value.
+ *
+ * @remark The type of each deallocated value will be changed
+ * to #CX_JSON_NOTHING, and values of such a type will be skipped
+ * by the deallocation. That means this function protects
+ * you from double-frees when you are accidentally freeing
+ * a nested value and then the parent value (or vice versa).
+ *
+ * @param value the value
+ */
+CX_EXTERN
+void cxJsonValueFree(CxJsonValue *value);
+
/**
* Creates a new (empty) JSON object.
*
* @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.
* @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.
* @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.
* @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.
* @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.
* @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.
* @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.
* @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.
* @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.
* @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.
* @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.
* @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.
* @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.
* @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.
* @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.
* @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.
* @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.
* @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.
* @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.
*/
#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.
*
* @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.
* @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;
}
* @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;
}
* @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;
}
* @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;
}
* @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;
}
* @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;
}
* @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;
}
* @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;
}
* @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;
}
* @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;
}
* @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.
* @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.
* @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.
* @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.
* @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.
* @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;
}
* @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;
}
* @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.
* @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.
* @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.
* @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);
}
* @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.
* @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.
* @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.
* @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);
/**
* @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().
*
* @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);
*/
#define cxJsonCloneFunc ((cx_clone_func) cx_json_clone_func)
-#ifdef __cplusplus
-}
-#endif
-
#endif /* UCX_JSON_H */
#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.
*
* @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);
/**
* @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);
/**
* @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.
* @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.
* @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.
* @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.
*/
#define cxKvListInsert(list, index, key, value) cx_kv_list_insert(list, index, CX_HASH_KEY(key), value)
-
/**
* Removes the key of a list item.
*
* @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.
* @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.
*/
#define cxKvListAdd(list, key, value) cxKvListInsert(list, (list)->collection.size, key, value)
-#ifdef __cplusplus
-} // extern "C"
-#endif
-
#endif // UCX_KV_LIST_H
#include "common.h"
#include "list.h"
-#ifdef __cplusplus
-extern "C" {
-#endif
-
/**
* Metadata for a linked list.
*/
* @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);
/**
* @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.
* @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);
/**
* @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);
* @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);
* @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.
* @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.
* @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.
* @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.
* @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.
* @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.
* @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.
* @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);
/**
* @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);
/**
* @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);
/**
* @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);
/**
* @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);
/**
* @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);
/**
* @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);
/**
* @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);
/**
* @param loc_next the location of a @c next pointer within your node struct (required)
* @param new_node a pointer to the node that shall be inserted
* @param cmp_func a compare function that will receive the node pointers
+ * @param context the context for the compare function
* @retval zero when the node was inserted
* @retval non-zero when a node with the same value already exists
*/
-cx_attr_nonnull_arg(1, 5, 6)
-CX_EXPORT int cx_linked_list_insert_unique_c(void **begin, void **end,
+CX_EXTERN CX_NONNULL_ARG(1, 5, 6)
+int cx_linked_list_insert_unique_c(void **begin, void **end,
ptrdiff_t loc_prev, ptrdiff_t loc_next, void *new_node, cx_compare_func2 cmp_func, void *context);
/**
* @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);
/**
* @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);
/**
* @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);
/**
* @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.
* @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);
/**
* @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.
*
* @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);
/**
* @param loc_advance the location of the pointer to advance
* @param loc_data the location of the @c data pointer within your node struct
* @param cmp_func the function to compare the elements
+ * @param context the context for the compare function
* @return the first non-zero result of invoking @p cmp_func or: negative if the left list is smaller than the
* right list, positive if the left list is larger than the right list, zero if both lists are equal.
*/
-cx_attr_nonnull_arg(5)
-CX_EXPORT int cx_linked_list_compare_c(const void *begin_left, const void *begin_right,
+CX_EXTERN CX_NONNULL_ARG(5)
+int cx_linked_list_compare_c(const void *begin_left, const void *begin_right,
ptrdiff_t loc_advance, ptrdiff_t loc_data, cx_compare_func2 cmp_func, void *context);
/**
* @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
#include "common.h"
#include "collection.h"
-#ifdef __cplusplus
-extern "C" {
-#endif
-
/**
* List class type.
*/
* @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);
/**
* @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);
/**
* @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);
/**
*
* @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.
* @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.
* @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);
* @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);
/**
* @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.
* @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.
* @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.
* @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.
* @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.
* @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.
* @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.
* @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.
* @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.
* @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.
* @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.
* @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.
*
* @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.
* @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.
* @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.
* @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.
* @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.
* @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.
* @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.
* @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.
* @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.
*
* @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.
* @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.
* @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.
* @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.
* @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.
* @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.
* @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.
* @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.
* @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.
* @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.
* @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.
* @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.
* @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.
* 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.
*
* @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.
* @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.
*
* @param list the list that shall be freed
*/
-CX_EXPORT void cxListFree(CxList *list);
+CX_EXTERN
+void cxListFree(CxList *list);
/**
* @retval non-zero when an allocation error occurred
* @see cxListCloneShallow()
*/
-cx_attr_nonnull_arg(1, 2, 3)
-CX_EXPORT int cxListClone(CxList *dst, const CxList *src,
+CX_EXTERN CX_NONNULL_ARG(1, 2, 3)
+int cxListClone(CxList *dst, const CxList *src,
cx_clone_func clone_func, const CxAllocator *clone_allocator, void *data);
/**
* @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);
* @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);
/**
* @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);
/**
* @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.
* @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);
/**
* @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.
* @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.
* @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.
* @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
typedef struct cx_list_s CxList;
#endif
-#ifdef __cplusplus
-extern "C" {
-#endif
-
/** Type for the UCX map. */
typedef struct cx_map_s CxMap;
*
* @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.
*
* @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.
* @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.
* @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.
* @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.
* @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.
* @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.
* @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.
* @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.
* @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.
*/
#define cxMapRemoveAndGet(map, key, targetbuf) cx_map_remove(map, CX_HASH_KEY(key), targetbuf)
-
/**
* Performs a deep clone of one map into another.
*
* @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.
*
* @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);
/**
* @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);
* @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);
/**
* @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);
/**
* @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);
/**
* @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.
* @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.
* @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.
* @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.
* @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.
* @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.
* @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
#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. */
*
* @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.
* @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.
* @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.
* @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.
* @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.
* @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.
*
* @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.
*
* @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.
* @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.
* @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.
* @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.
* @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
* @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.
*/
* @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
* @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
* @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
* @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
* @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, ...);
/**
* @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);
/**
* @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.
* @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
#include "map.h"
#include "buffer.h"
-#ifdef __cplusplus
-extern "C" {
-#endif
-
/**
* Configures the expected characters for the properties parser.
*/
* @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.
*
* @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.
*
* @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.
* @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.
* @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);
}
* @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.
* @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()`.
* @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);
/**
#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
#include "common.h"
-#ifdef __cplusplus
-extern "C" {
-#endif
-
/**
* Reads data from a stream and writes it to another stream.
*
* 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);
* @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);
/**
#define cx_stream_copy(src, dest, rfnc, wfnc) \
cx_stream_ncopy(src, dest, rfnc, wfnc, SIZE_MAX)
-#ifdef __cplusplus
-}
-#endif
-
#endif // UCX_STREAMS_H
#include <string.h>
+/** Convenience macro for creating a null string */
+#define CX_NULLSTR cx_mutstr(NULL)
+
/** Expands a UCX string as printf arguments. */
#define CX_SFMT(s) (int) (s).length, (s).ptr
*
* @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;
*
* @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;
*
* @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;
*
* @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;
}
#ifdef __cplusplus
-cx_attr_nodiscard
-CX_CPPDECL cxstring cx_strcast(cxmutstr str) {
- return cx_strn(str.ptr, str.length);
+CX_NODISCARD
+CX_CPPDECL cxmutstr cx_strcast_m(cxmutstr str) {
+ return str;
}
-cx_attr_nodiscard
-CX_CPPDECL cxstring cx_strcast(cxstring str) {
+CX_NODISCARD
+CX_CPPDECL cxstring cx_strcast_m(cxstring str) {
return str;
}
-cx_attr_nodiscard
-CX_CPPDECL cxstring cx_strcast(const char *str) {
+CX_NODISCARD
+CX_CPPDECL cxmutstr cx_strcast_m(char *str) {
+ return cx_mutstr(str);
+}
+CX_NODISCARD
+CX_CPPDECL cxmutstr cx_strcast_m(unsigned char *str) {
+ return cx_mutstr(reinterpret_cast<char*>(str));
+}
+CX_NODISCARD
+CX_CPPDECL cxstring cx_strcast_m(const char *str) {
return cx_str(str);
}
-cx_attr_nodiscard
-CX_CPPDECL cxstring cx_strcast(const unsigned char *str) {
+CX_NODISCARD
+CX_CPPDECL cxstring cx_strcast_m(const unsigned char *str) {
return cx_str(reinterpret_cast<const char*>(str));
}
-extern "C" {
+CX_NODISCARD
+CX_CPPDECL cxstring cx_strcast_(cxmutstr str) {
+ return cx_strn(str.ptr, str.length);
+}
+CX_NODISCARD
+CX_CPPDECL cxstring cx_strcast_(cxstring str) {
+ return str;
+}
+#define cx_strcast(s) cx_strcast_(cx_strcast_m(s))
#else
/**
* Internal function, do not use.
* @param str
* @return
+ * @see cx_strcast_m()
* @see cx_strcast()
*/
-cx_attr_nodiscard
-CX_INLINE cxstring cx_strcast_m(cxmutstr str) {
- return (cxstring) {str.ptr, str.length};
+CX_NODISCARD
+CX_INLINE cxmutstr cx_strcast_cxms(cxmutstr str) {
+ return str;
}
/**
* Internal function, do not use.
* @param str
* @return
+ * @see cx_strcast_m()
* @see cx_strcast()
*/
-cx_attr_nodiscard
-CX_INLINE cxstring cx_strcast_c(cxstring str) {
+CX_NODISCARD
+CX_INLINE cxstring cx_strcast_cxs(cxstring str) {
return str;
}
* Internal function, do not use.
* @param str
* @return
+ * @see cx_strcast_m()
+ * @see cx_strcast()
+ */
+CX_NODISCARD
+CX_INLINE cxmutstr cx_strcast_uc(unsigned char *str) {
+ return cx_mutstr((char*)str);
+}
+
+/**
+ * Internal function, do not use.
+ * @param str
+ * @return
+ * @see cx_strcast_m()
+ * @see cx_strcast()
+ */
+CX_NODISCARD
+CX_INLINE cxmutstr cx_strcast_c(char *str) {
+ return cx_mutstr(str);
+}
+
+/**
+ * Internal function, do not use.
+ * @param str
+ * @return
+ * @see cx_strcast_m()
* @see cx_strcast()
*/
-cx_attr_nodiscard
-CX_INLINE cxstring cx_strcast_u(const unsigned char *str) {
+CX_NODISCARD
+CX_INLINE cxstring cx_strcast_ucc(const unsigned char *str) {
return cx_str((const char*)str);
}
* Internal function, do not use.
* @param str
* @return
+ * @see cx_strcast_m()
* @see cx_strcast()
*/
-cx_attr_nodiscard
-CX_INLINE cxstring cx_strcast_z(const char *str) {
+CX_NODISCARD
+CX_INLINE cxstring cx_strcast_cc(const char *str) {
return cx_str(str);
}
* Wraps any string into an UCX string.
*
* @param str (any supported string type) the string to cast
- * @return (@c cxstring) the string wrapped as UCX string
- */
-#define cx_strcast(str) _Generic((str), \
- cxmutstr: cx_strcast_m, \
- cxstring: cx_strcast_c, \
- const unsigned char*: cx_strcast_u, \
- unsigned char *: cx_strcast_u, \
- const char*: cx_strcast_z, \
- char *: cx_strcast_z) (str)
+ * @return (@c cxstring) or (@c cxmutstr) the string wrapped as UCX string
+ */
+#define cx_strcast_m(str) _Generic((str), \
+ cxstring: cx_strcast_cxs, \
+ cxmutstr: cx_strcast_cxms, \
+ const unsigned char*: cx_strcast_ucc, \
+ unsigned char *: cx_strcast_uc, \
+ const char*: cx_strcast_cc, \
+ char *: cx_strcast_c) (str)
+
+/**
+ * Internal function, do not use.
+ * @param str
+ * @return
+ */
+CX_INLINE cxstring cx_strcast_1(cxmutstr str) {
+ return (cxstring){str.ptr, str.length};
+}
+
+/**
+ * Internal function, do not use.
+ * @param str
+ * @return
+ */
+CX_INLINE cxstring cx_strcast_2(cxstring str) {
+ return str;
+}
+
+/** internal conversion macro */
+#define cx_strcast_(str) _Generic((str), \
+ cxmutstr: cx_strcast_1, \
+ cxstring: cx_strcast_2)(str)
+
+/**
+ * Converts any string to a cxstring.
+ *
+ * @param str (any supported string type) the string to cast
+ * @return he string converted to a (@c cxstring)
+ */
+#define cx_strcast(str) cx_strcast_(cx_strcast_m(str))
#endif
+/**
+ * Casts away constness and converts a cxstring to a cxmutstr.
+ * For internal use only!
+ * @param str
+ * @return
+ */
+CX_INLINE cxmutstr cx_mutstrcast(cxstring str) {
+ cxmutstr s;
+ s.ptr = (char*)str.ptr;
+ s.length = str.length;
+ return s;
+}
+
/**
* Passes the pointer in this string to the cxDefaultAllocator's @c free() function.
*
*
* @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.
* @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.
* @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.
* @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.
* If @p str already contains a string, the memory will be reallocated and
* the other strings are appended. Otherwise, new memory is allocated.
*
- * If memory allocation fails, the pointer in the returned string will
- * be @c NULL. Depending on the allocator, @c errno might be set.
- *
* @note It is guaranteed that there is only one allocation for the
* resulting string.
* It is also guaranteed that the returned string is zero-terminated.
+ * If allocation fails, the @c ptr in the returned string will be @c NULL.
*
* @param alloc the allocator to use
* @param str the string the other strings shall be concatenated to
* @param ... all other UCX strings
* @return the concatenated string
*/
-cx_attr_nodiscard cx_attr_nonnull
-CX_EXPORT cxmutstr cx_strcat_ma(const CxAllocator *alloc,
+CX_EXTERN CX_NONNULL
+cxmutstr cx_strcat_a(const CxAllocator *alloc,
cxmutstr str, size_t count, ...);
-/**
- * Concatenates strings and returns a new string.
- *
- * The resulting string will be allocated by the specified allocator.
- * So developers @em must pass the return value to cx_strfree_a() eventually.
- *
-* If memory allocation fails, the pointer in the returned string will
- * be @c NULL. Depending on the allocator, @c errno might be set.
- *
- * @note It is guaranteed that there is only one allocation for the
- * resulting string.
- * It is also guaranteed that the returned string is zero-terminated.
- *
- * @param alloc (@c CxAllocator*) the allocator to use
- * @param count (@c size_t) the number of the other following strings to concatenate
- * @param ... all other UCX strings
- * @return (@c cxmutstr) the concatenated string
- */
-#define cx_strcat_a(alloc, count, ...) \
- cx_strcat_ma(alloc, cx_mutstrn(NULL, 0), count, __VA_ARGS__)
-
/**
* Concatenates strings and returns a new string.
*
* The resulting string will be allocated by the cxDefaultAllocator.
* So developers @em must pass the return value to cx_strfree() eventually.
*
-* If memory allocation fails, the pointer in the returned string will
- * be @c NULL and @c errno might be set.
- *
* @note It is guaranteed that there is only one allocation for the
* resulting string.
* It is also guaranteed that the returned string is zero-terminated.
+ * If allocation fails, the @c ptr in the returned string will be @c NULL.
*
+ * @param str (@c cxmutstr*) the string the other strings shall be concatenated to
* @param count (@c size_t) the number of the other following strings to concatenate
* @param ... all other UCX strings
- * @return (@c cxmutstr) the concatenated string
- */
-#define cx_strcat(count, ...) \
- cx_strcat_ma(cxDefaultAllocator, cx_mutstrn(NULL, 0), count, __VA_ARGS__)
-
-/**
- * Concatenates strings.
- *
- * The resulting string will be allocated by the cxDefaultAllocator.
- * So developers @em must pass the return value to cx_strfree() eventually.
- *
- * If @p str already contains a string, the memory will be reallocated and
- * the other strings are appended. Otherwise, new memory is allocated.
- *
-* If memory allocation fails, the pointer in the returned string will
- * be @c NULL and @c errno might be set.
- *
- * @note It is guaranteed that there is only one allocation for the
- * resulting string.
- * It is also guaranteed that the returned string is zero-terminated.
- *
- * @param str (@c cxmutstr) the string the other strings shall be concatenated to
- * @param count (@c size_t) the number of the other following strings to concatenate
- * @param ... all other strings
- * @return (@c cxmutstr) the concatenated string
+ * @return the concatenated string
*/
-#define cx_strcat_m(str, count, ...) \
- cx_strcat_ma(cxDefaultAllocator, str, count, __VA_ARGS__)
+#define cx_strcat(str, count, ...) \
+ cx_strcat_a(cxDefaultAllocator, str, count, __VA_ARGS__)
/**
- * Returns a substring starting at the specified location.
+ * Returns a substring.
*
- * @attention the new string references the same memory area as the
- * input string and is usually @em not zero-terminated.
- * Use cx_strdup() to get a copy.
+ * Internal function - do not use.
*
* @param string input string
* @param start start location of the substring
+ * @param length the maximum length of the returned string
* @return a substring of @p string starting at @p start
- *
* @see cx_strsubsl()
- * @see cx_strsubs_m()
- * @see cx_strsubsl_m()
*/
-cx_attr_nodiscard
-CX_EXPORT cxstring cx_strsubs(cxstring string, size_t start);
+CX_EXTERN CX_NODISCARD
+cxstring cx_strsubsl_(cxstring string, size_t start, size_t length);
/**
- * Returns a substring starting at the specified location.
- *
- * The returned string will be limited to @p length bytes or the number
- * of bytes available in @p string, whichever is smaller.
+ * Returns a substring.
*
- * @attention the new string references the same memory area as the
- * input string and is usually @em not zero-terminated.
- * Use cx_strdup() to get a copy.
+ * Internal function - do not use.
*
* @param string input string
* @param start start location of the substring
- * @param length the maximum length of the returned string
* @return a substring of @p string starting at @p start
- *
* @see cx_strsubs()
- * @see cx_strsubs_m()
- * @see cx_strsubsl_m()
*/
-cx_attr_nodiscard
-CX_EXPORT cxstring cx_strsubsl(cxstring string, size_t start, size_t length);
+CX_EXTERN CX_NODISCARD
+cxstring cx_strsubs_(cxstring string, size_t start);
+
+/**
+ * Internal conversion function - do not use.
+ * @param string
+ * @param start
+ * @return
+ */
+CX_INLINE
+cxmutstr cx_strsubs_m_(cxmutstr string, size_t start) {
+ return cx_mutstrcast(cx_strsubs_(cx_strcast(string), start));
+}
+/**
+ * Internal conversion function - do not use.
+ * @param string
+ * @param start
+ * @param length
+ * @return
+ */
+CX_INLINE
+cxmutstr cx_strsubsl_m_(cxmutstr string, size_t start, size_t length) {
+ return cx_mutstrcast(cx_strsubsl_(cx_strcast(string), start, length));
+}
+
+#ifdef __cplusplus
+CX_CPPDECL cxstring cx_strsubs_cpp_(cxstring string, size_t start) {
+ return cx_strsubs_(string, start);
+}
+CX_CPPDECL cxstring cx_strsubsl_cpp_(cxstring string, size_t start, size_t length) {
+ return cx_strsubsl_(string, start, length);
+}
+CX_CPPDECL cxmutstr cx_strsubs_cpp_(cxmutstr string, size_t start) {
+ return cx_strsubs_m_(string, start);
+}
+CX_CPPDECL cxmutstr cx_strsubsl_cpp_(cxmutstr string, size_t start, size_t length) {
+ return cx_strsubsl_m_(string, start, length);
+}
+#define cx_strsubs(string, start) cx_strsubs_cpp_(cx_strcast_m(string), start)
+#define cx_strsubsl(string, start, length) cx_strsubsl_cpp_(cx_strcast_m(string), start, length)
+#else
/**
* Returns a substring starting at the specified location.
*
* @attention the new string references the same memory area as the
- * input string and is usually @em not zero-terminated.
+ * input string and is @em not zero-terminated.
* Use cx_strdup() to get a copy.
*
* @param string input string
- * @param start start location of the substring
- * @return a substring of @p string starting at @p start
+ * @param start (@c size_t) start location of the substring
+ * @return (@c cxstring or @c cxmutstr) a substring of @p string starting at @p start
*
- * @see cx_strsubsl_m()
- * @see cx_strsubs()
* @see cx_strsubsl()
*/
-cx_attr_nodiscard
-CX_EXPORT cxmutstr cx_strsubs_m(cxmutstr string, size_t start);
+#define cx_strsubs(string, start) _Generic(cx_strcast_m(string), \
+ cxstring: cx_strsubs_, \
+ cxmutstr: cx_strsubs_m_)(cx_strcast_m(string), start)
/**
* Returns a substring starting at the specified location.
* @param length the maximum length of the returned string
* @return a substring of @p string starting at @p start
*
- * @see cx_strsubs_m()
* @see cx_strsubs()
- * @see cx_strsubsl()
*/
-cx_attr_nodiscard
-CX_EXPORT cxmutstr cx_strsubsl_m(cxmutstr string, size_t start, size_t length);
+#define cx_strsubsl(string, start, length) _Generic(cx_strcast_m(string), \
+ cxstring: cx_strsubsl_, \
+ cxmutstr: cx_strsubsl_m_)(cx_strcast_m(string), start, length)
+#endif
/**
- * Returns a substring starting at the location of the first occurrence of the
- * specified character.
- *
- * If the string does not contain the character, an empty string is returned.
+ * Returns the character at the specified index offset.
*
- * @param string the string where to locate the character
- * @param chr the character to locate
- * @return a substring starting at the first location of @p chr
+ * Internal function - do not use.
*
- * @see cx_strchr_m()
- */
-cx_attr_nodiscard
-CX_EXPORT cxstring cx_strchr(cxstring string, int chr);
+ * @param str the string
+ * @param index the index offset
+ * @return the character at the index
+ * @see cx_strat()
+ */
+CX_INLINE
+char cx_strat_(cxstring str, off_t index) {
+ size_t i;
+ if (index >= 0) {
+ i = index;
+ } else {
+ i = (size_t) (str.length + index);
+ }
+ if (i >= str.length) {
+ return '\0';
+ }
+ return str.ptr[i];
+}
/**
- * Returns a substring starting at the location of the first occurrence of the
- * specified character.
+ * Returns the character at the specified index offset.
*
- * If the string does not contain the character, an empty string is returned.
+ * When the @p index is negative, the character is counted from the end of the
+ * string where -1 denotes the last character in the string.
*
- * @param string the string where to locate the character
- * @param chr the character to locate
- * @return a substring starting at the first location of @p chr
+ * When the @p index is out of bounds, the function returns zero.
*
+ * @param str the string
+ * @param index the index offset
+ * @return the character at the index
+ * @see cx_strat()
+ */
+#define cx_strat(str, index) cx_strat_(cx_strcast(str), index)
+
+/**
+ * Searches for a character in a string.
+ * Internal function - do not use.
+ * @param string
+ * @param chr
+ * @return
* @see cx_strchr()
*/
-cx_attr_nodiscard
-CX_EXPORT cxmutstr cx_strchr_m(cxmutstr string, int chr);
+CX_EXTERN CX_NODISCARD
+cxstring cx_strchr_(cxstring string, int chr);
/**
- * Returns a substring starting at the location of the last occurrence of the
+ * Searches for a character in a string.
+ * Internal function - do not use.
+ * @param string
+ * @param chr
+ * @return
+ * @see cx_strrchr()
+ */
+CX_EXTERN CX_NODISCARD
+cxstring cx_strrchr_(cxstring string, int chr);
+
+#ifdef __cplusplus
+CX_CPPDECL cxstring cx_strchr_cpp_(cxstring string, int chr) {
+ return cx_strchr_(string, chr);
+}
+CX_CPPDECL cxmutstr cx_strchr_cpp_(cxmutstr string, int chr) {
+ return cx_mutstrcast(cx_strchr_(cx_strcast(string), chr));
+}
+#define cx_strchr(s, chr) cx_strchr_cpp_(cx_strcast_m(s), chr)
+CX_CPPDECL cxstring cx_strrchr_cpp_(cxstring string, int chr) {
+ return cx_strrchr_(string, chr);
+}
+CX_CPPDECL cxmutstr cx_strrchr_cpp_(cxmutstr string, int chr) {
+ return cx_mutstrcast(cx_strrchr_(cx_strcast(string), chr));
+}
+#define cx_strrchr(s, chr) cx_strrchr_cpp_(cx_strcast_m(s), chr)
+#else
+/**
+ * Internal conversion function - do not use.
+ * @param string
+ * @param chr
+ * @return
+ */
+CX_INLINE cxmutstr cx_strchr_m_(cxmutstr string, int chr) {
+ return cx_mutstrcast(cx_strchr_(cx_strcast(string), chr));
+}
+/**
+ * Internal conversion function - do not use.
+ * @param string
+ * @param chr
+ * @return
+ */
+CX_INLINE cxmutstr cx_strrchr_m_(cxmutstr string, int chr) {
+ return cx_mutstrcast(cx_strrchr_(cx_strcast(string), chr));
+}
+
+/**
+ * Returns a substring starting at the location of the first occurrence of the
* specified character.
*
* If the string does not contain the character, an empty string is returned.
*
* @param string the string where to locate the character
- * @param chr the character to locate
- * @return a substring starting at the last location of @p chr
- *
- * @see cx_strrchr_m()
+ * @param chr (@c int) the character to locate
+ * @return (@c cxstring or @c cxmutstr) a substring starting at the first
+ * location of @p chr
*/
-cx_attr_nodiscard
-CX_EXPORT cxstring cx_strrchr(cxstring string, int chr);
+#define cx_strchr(string, chr) _Generic(cx_strcast_m(string), \
+ cxstring: cx_strchr_, \
+ cxmutstr: cx_strchr_m_)(cx_strcast_m(string), chr)
/**
* Returns a substring starting at the location of the last occurrence of the
* If the string does not contain the character, an empty string is returned.
*
* @param string the string where to locate the character
- * @param chr the character to locate
- * @return a substring starting at the last location of @p chr
- *
- * @see cx_strrchr()
+ * @param chr (@c int) the character to locate
+ * @return (@c cxstring or @c cxmutstr) a substring starting at the last
+ * location of @p chr
*/
-cx_attr_nodiscard
-CX_EXPORT cxmutstr cx_strrchr_m(cxmutstr string, int chr);
+#define cx_strrchr(string, chr) _Generic(cx_strcast_m(string), \
+ cxstring: cx_strrchr_, \
+ cxmutstr: cx_strrchr_m_)(cx_strcast_m(string), chr)
+#endif
/**
* Searches for a specific substring.
* or an empty string, if the sequence is not contained
* @see cx_strstr()
*/
-cx_attr_nodiscard
-CX_EXPORT cxstring cx_strstr_(cxstring haystack, cxstring needle);
-
-/**
- * Returns a substring starting at the location of the first occurrence of the
- * specified string.
- *
- * If @p haystack does not contain @p needle, an empty string is returned.
- *
- * If @p needle is an empty string, the complete @p haystack is
- * returned.
- *
- * @param haystack (@c cxstring) the string to be scanned
- * @param needle string containing the sequence of characters to match
- * @return (@c cxstring) a substring starting at the first occurrence of
- * @p needle, or an empty string, if the sequence is not contained
- * @see cx_strstr_m()
- */
-#define cx_strstr(haystack, needle) cx_strstr_(haystack, cx_strcast(needle))
+CX_EXTERN CX_NODISCARD
+cxstring cx_strstr_(cxstring haystack, cxstring needle);
+#ifdef __cplusplus
+CX_CPPDECL cxstring cx_strstr_cpp_(cxstring haystack, cxstring needle) {
+ return cx_strstr_(haystack, needle);
+}
+CX_CPPDECL cxmutstr cx_strstr_cpp_(cxmutstr haystack, cxstring needle) {
+ return cx_mutstrcast(cx_strstr_(cx_strcast(haystack), needle));
+}
+#define cx_strstr(h,n) cx_strstr_cpp_(cx_strcast_m(h), cx_strcast(n))
+#else
/**
- * Searches for a specific substring.
- *
- * Internal function - do not use.
- *
- * @param haystack the string to be scanned
- * @param needle string containing the sequence of characters to match
- * @return a substring starting at the first occurrence of @p needle,
- * or an empty string, if the sequence is not contained
- * @see cx_strstr_m()
+ * Internal conversion - do not use.
+ * @param haystack
+ * @param needle
+ * @return
*/
-cx_attr_nodiscard
-CX_EXPORT cxmutstr cx_strstr_m_(cxmutstr haystack, cxstring needle);
+CX_INLINE cxmutstr cx_strstr_m_(cxmutstr haystack, cxstring needle) {
+ return cx_mutstrcast(cx_strstr_(cx_strcast(haystack), needle));
+}
/**
* Returns a substring starting at the location of the first occurrence of the
* If @p needle is an empty string, the complete @p haystack is
* returned.
*
- * @param haystack (@c cxmutstr) the string to be scanned
+ * @param haystack the string to be scanned
* @param needle string containing the sequence of characters to match
- * @return (@c cxmutstr) a substring starting at the first occurrence of
- * @p needle, or an empty string, if the sequence is not contained
- * @see cx_strstr()
+ * @return (@c cxstring or @c cxmutstr) a substring starting at the first
+ * occurrence of @p needle, or an empty string, if the sequence is not contained
*/
-#define cx_strstr_m(haystack, needle) cx_strstr_m_(haystack, cx_strcast(needle))
+#define cx_strstr(haystack, needle) _Generic(cx_strcast_m(haystack), \
+ cxstring: cx_strstr_,\
+ cxmutstr: cx_strstr_m_)(cx_strcast_m(haystack), cx_strcast(needle))
+#endif
/**
* Splits a given string using a delimiter string.
* @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);
/**
* @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);
* @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);
/**
* @return the actual number of split items
* @see cx_strsplit_ma()
*/
-cx_attr_nodiscard cx_attr_nonnull cx_attr_access_w(5)
-CX_EXPORT size_t cx_strsplit_ma_(const CxAllocator *allocator,
+CX_EXTERN CX_NODISCARD CX_NONNULL CX_ACCESS_W(5)
+size_t cx_strsplit_ma_(const CxAllocator *allocator,
cxmutstr string, cxstring delim, size_t limit,
cxmutstr **output);
+#ifdef __cplusplus
+CX_CPPDECL size_t cx_strsplit_cpp_(cxstring string, cxstring delim,
+ size_t limit, cxstring *output) {
+ return cx_strsplit_(string, delim, limit, output);
+}
+CX_CPPDECL size_t cx_strsplit_cpp_(cxmutstr string, cxstring delim,
+ size_t limit, cxmutstr *output) {
+ return cx_strsplit_m_(string, delim, limit, output);
+}
+CX_CPPDECL size_t cx_strsplit_a_cpp_(const CxAllocator *allocator,
+ cxstring string, cxstring delim, size_t limit, cxstring **output) {
+ return cx_strsplit_a_(allocator, string, delim, limit, output);
+}
+CX_CPPDECL size_t cx_strsplit_a_cpp_(const CxAllocator *allocator,
+ cxmutstr string, cxstring delim, size_t limit, cxmutstr **output) {
+ return cx_strsplit_ma_(allocator, string, delim, limit, output);
+}
+#define cx_strsplit(string, delim, limit, output) \
+ cx_strsplit_cpp_(cx_strcast_m(string), cx_strcast(delim), limit, output)
+#define cx_strsplit_a(allocator, string, delim, limit, output) \
+ cx_strsplit_a_cpp_(allocator, cx_strcast_m(string), cx_strcast(delim), limit, output)
+#else
/**
* Splits a given string using a delimiter string.
*
* @note The resulting array contains strings that point to the source
* @p string. Use cx_strdup() to get copies.
*
- * @param string (@c cxstring) the string to split
+ * @param string the string to split
* @param delim the delimiter
* @param limit (@c size_t) the maximum number of split items
- * @param output (@c cxstring*) a preallocated array of at least @p limit length
+ * @param output (@c cxstring* or @c cxmutstr*) a preallocated array of at
+ * least @p limit length
* @return the actual number of split items
*/
#define cx_strsplit(string, delim, limit, output) \
- cx_strsplit_(string, cx_strcast(delim), limit, output)
+ _Generic(cx_strcast_m(string), \
+ cxstring: cx_strsplit_, \
+ cxmutstr: cx_strsplit_m_)\
+ (cx_strcast_m(string), cx_strcast(delim), limit, output)
/**
* Splits a given string using a delimiter string.
* @p output and the number returned will be zero.
*
* @param allocator (@c CxAllocator*) the allocator to use for allocating the resulting array
- * @param string (@c cxstring) the string to split
+ * @param string the string to split
* @param delim the delimiter
* @param limit (@c size_t) the maximum number of split items
- * @param output (@c cxstring**) a pointer where the address of the allocated
- * array shall be written to
+ * @param output (@c cxstring** or @c cxmutstr**) a pointer where the address
+ * of the allocated array shall be written to
* @return the actual number of split items
*/
#define cx_strsplit_a(allocator, string, delim, limit, output) \
- cx_strsplit_a_(allocator, string, cx_strcast(delim), limit, output)
-
-
-/**
- * Splits a given string using a delimiter string.
- *
- * @note The resulting array contains strings that point to the source
- * @p string. Use cx_strdup() to get copies.
- *
- * @param string (@c cxmutstr) the string to split
- * @param delim the delimiter
- * @param limit (@c size_t) the maximum number of split items
- * @param output (@c cxmutstr*) a preallocated array of at least @p limit length
- * @return the actual number of split items
- */
-#define cx_strsplit_m(string, delim, limit, output) \
- cx_strsplit_m_(string, cx_strcast(delim), limit, output)
-
-/**
- * Splits a given string using a delimiter string.
- *
- * The array pointed to by @p output will be allocated by @p allocator.
- *
- * @note The resulting array contains strings that point to the source
- * @p string. Use cx_strdup() to get copies.
- *
- * @attention If allocation fails, the @c NULL pointer will be written to
- * @p output and the number returned will be zero.
- *
- * @param allocator (@c CxAllocator*) the allocator to use for allocating the resulting array
- * @param string (@c cxmutstr) the string to split
- * @param delim the delimiter
- * @param limit (@c size_t) the maximum number of split items
- * @param output (@c cxmutstr**) a pointer where the address of the allocated
- * array shall be written to
- * @return the actual number of split items
- */
-#define cx_strsplit_ma(allocator, string, delim, limit, output) \
- cx_strsplit_ma_(allocator, string, cx_strcast(delim), limit, output)
+ _Generic(cx_strcast_m(string), \
+ cxstring: cx_strsplit_a_, \
+ cxmutstr: cx_strsplit_ma_)\
+ (allocator, cx_strcast_m(string), cx_strcast(delim), limit, output)
+#endif
/**
* Compares two strings.
* @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.
* @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.
* @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.
* @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.
* @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.
#define cx_strdup(string) cx_strdup_a(cxDefaultAllocator, string)
/**
- * Omits leading and trailing spaces.
- *
- * @note the returned string references the same memory, thus you
- * must @em not free the returned memory.
- *
- * @param string the string that shall be trimmed
- * @return the trimmed string
+ * Trims a string.
+ * Internal function - do not use.
+ * @param string
+ * @return
+ */
+CX_EXTERN CX_NODISCARD
+cxstring cx_strtrim_(cxstring string);
+
+#ifdef __cplusplus
+CX_CPPDECL cxstring cx_strtrim_cpp_(cxstring string) {
+ return cx_strtrim_(string);
+}
+CX_CPPDECL cxmutstr cx_strtrim_cpp_(cxmutstr string) {
+ return cx_mutstrcast(cx_strtrim_(cx_strcast(string)));
+}
+#define cx_strtrim(string) cx_strtrim_cpp_(cx_strcast_m(string))
+#else
+/**
+ * Internal conversion function.
+ * @param string
+ * @return
*/
-cx_attr_nodiscard
-CX_EXPORT cxstring cx_strtrim(cxstring string);
+CX_INLINE cxmutstr cx_strtrim_m_(cxmutstr string) {
+ return cx_mutstrcast(cx_strtrim_(cx_strcast(string)));
+}
/**
* Omits leading and trailing spaces.
* must @em not free the returned memory.
*
* @param string the string that shall be trimmed
- * @return the trimmed string
+ * @return (@c cxstring or @c cxmutstr) the trimmed string
*/
-cx_attr_nodiscard
-CX_EXPORT cxmutstr cx_strtrim_m(cxmutstr string);
+#define cx_strtrim(string) _Generic(cx_strcast_m(string), \
+ cxstring: cx_strtrim_, \
+ cxmutstr: cx_strtrim_m_)(cx_strcast_m(string))
+#endif
/**
* Checks if a string has a specific prefix.
* @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.
* @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.
* @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.
* @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.
*/
#define cx_strcasesuffix(string, suffix) cx_strcasesuffix_(cx_strcast(string), cx_strcast(suffix))
-
/**
* Replaces a string with another string.
*
* @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);
/**
* @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.
* @return true if successful, false if the limit or the end of the string
* has been reached
*/
-cx_attr_nonnull cx_attr_nodiscard cx_attr_access_w(2)
-CX_EXPORT bool cx_strtok_next(CxStrtokCtx *ctx, cxstring *token);
+CX_EXTERN CX_NONNULL CX_NODISCARD CX_ACCESS_W(2)
+bool cx_strtok_next_(CxStrtokCtx *ctx, cxstring *token);
+#ifdef __cplusplus
+CX_CPPDECL cx_strtok_next(CxStrtokCtx *ctx, cxstring *token) {
+ return cx_strtok_next_(ctx, token);
+}
+CX_CPPDECL cx_strtok_next(CxStrtokCtx *ctx, cxmutstr *token) {
+ // Note: this is actually UB - fixed with start_lifetime_as() in C++23
+ // but it works on all supported platforms
+ return cx_strtok_next_(ctx, reinterpret_cast<cxstring*>(token));
+}
+#else // ! __cplusplus
/**
- * Returns the next token of a mutable string.
+ * Returns the next token.
*
* The token will point to the source string.
*
- * @attention
- * If the context was not initialized over a mutable string, modifying
- * the data of the returned token is undefined behavior.
- *
- * @param ctx the tokenization context
- * @param token a pointer to memory where the next token shall be stored
+ * @param ctx (@c CxStrtokCtx*) the tokenization context
+ * @param token a pointer to either a @c cxstring or @c cxmutstr
+ * where the next token shall be stored
* @return true if successful, false if the limit or the end of the string
* has been reached
*/
-cx_attr_nonnull cx_attr_nodiscard cx_attr_access_w(2)
-CX_EXPORT bool cx_strtok_next_m(CxStrtokCtx *ctx, cxmutstr *token);
+#define cx_strtok_next(ctx, token) _Generic((token), \
+ cxstring*: cx_strtok_next_, \
+ cxmutstr*: cx_strtok_next_)(ctx, (cxstring*)token)
+#endif
/**
* Defines an array of more delimiters for the specified tokenization context.
* @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 *
* @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.
* @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.
* @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.
* @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.
* @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.
* @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.
* @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.
* @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.
* @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.
* @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.
* @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.
* @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.
* @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.
* @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.
* @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.
* @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.
* @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.
* @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.
* @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.
*/
#define cx_strtod(str, output) cx_strtod_lc_(cx_strcast(str), output, '.', ",")
-#ifdef __cplusplus
-} // extern "C"
-#endif
-
#endif //UCX_STRING_H
#include <string.h>
#include <setjmp.h>
-#ifdef __cplusplus
-extern "C" {
-#endif
-
#ifndef __FUNCTION__
/**
* Alias for the <code>__func__</code> preprocessor macro.
* @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) {
* @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) {
* @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);
#define CX_TEST_CALL_SUBROUTINE(name,...) \
name(_suite_,_output_,_writefnc_,_env_,__VA_ARGS__)
-#ifdef __cplusplus
-}
-#endif
-
#endif /* UCX_TEST_H */
#include "collection.h"
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/**
- * A depth-first tree iterator.
- *
- * This iterator is not position-aware in a strict sense, as it does not assume
- * a particular order of elements in the tree. However, the iterator keeps track
- * of the number of nodes it has passed in a counter-variable.
- * Each node, regardless of the number of passes, is counted only once.
- *
- * @note Objects that are pointed to by an iterator are mutable through that
- * iterator. However, if the
- * underlying data structure is mutated by other means than this iterator (e.g.,
- * elements added or removed), the iterator becomes invalid (regardless of what
- * cxIteratorValid() returns).
- *
- * @see CxIterator
- */
-typedef struct cx_tree_iterator_s {
- /**
- * Base members.
- */
- CX_ITERATOR_BASE;
- /**
- * Indicates whether the subtree below the current node shall be skipped.
- */
- bool skip;
- /**
- * Set to true, when the iterator shall visit a node again
- * when all its children have been processed.
- */
- bool visit_on_exit;
- /**
- * True, if this iterator is currently leaving the node.
- */
- bool exiting;
- /**
- * Offset in the node struct for the children linked list.
- */
- ptrdiff_t loc_children;
- /**
- * Offset in the node struct for the next pointer.
- */
- ptrdiff_t loc_next;
- /**
- * The total number of distinct nodes that have been passed so far.
- * This includes the current node.
- */
- size_t counter;
- /**
- * The currently observed node.
- *
- * This is the same what cxIteratorCurrent() would return.
- */
- void *node;
- /**
- * Stores a copy of the pointer to the successor of the visited node.
- * Allows freeing a node on exit without corrupting the iteration.
- */
- void *node_next;
- /**
- * Internal stack.
- * Will be automatically freed once the iterator becomes invalid.
- *
- * If you want to discard the iterator before, you need to manually
- * call cxTreeIteratorDispose().
- */
- void **stack;
- /**
- * Internal capacity of the stack.
- */
- size_t stack_capacity;
- union {
- /**
- * Internal stack size.
- */
- size_t stack_size;
- /**
- * The current depth in the tree.
- * The node with which the iteration starts has depth 1.
- */
- size_t depth;
- };
-} CxTreeIterator;
-
/**
* An element in a visitor queue.
*/
};
/**
- * A breadth-first tree iterator.
- *
- * This iterator needs to maintain a visitor queue that will be automatically
- * freed once the iterator becomes invalid.
- * If you want to discard the iterator before, you MUST manually call
- * cxTreeVisitorDispose().
- *
- * This iterator is not position-aware in a strict sense, as it does not assume
- * a particular order of elements in the tree. However, the iterator keeps track
- * of the number of nodes it has passed in a counter-variable.
- * Each node, regardless of the number of passes, is counted only once.
- *
- * @note Objects that are pointed to by an iterator are mutable through that
- * iterator. However, if the
- * underlying data structure is mutated by other means than this iterator (e.g.,
- * elements added or removed), the iterator becomes invalid (regardless of what
- * cxIteratorValid() returns).
- *
- * @see CxIterator
+ * An iterator (DFS) or visitor (BFS) for a tree.
*/
-typedef struct cx_tree_visitor_s {
+typedef struct cx_tree_combined_iterator_s {
/**
* Base members.
*/
CX_ITERATOR_BASE;
- /**
- * Indicates whether the subtree below the current node shall be skipped.
- */
- bool skip;
/**
* Offset in the node struct for the children linked list.
*/
* This includes the currently visited node.
*/
size_t counter;
+ /**
+ * The current depth in the tree.
+ */
+ size_t depth;
/**
* The currently observed node.
*
*/
void *node;
/**
- * The current depth in the tree.
+ * Memory for BFS or DFS-specific data.
*/
- size_t depth;
+ union {
+ struct {
+ /**
+ * Stores a copy of the pointer to the successor of the visited node.
+ * Allows freeing a node on exit without corrupting the iteration.
+ */
+ void *node_next;
+ /**
+ * Internal stack.
+ * Will be automatically freed once the iterator becomes invalid.
+ *
+ * If you want to discard the iterator before, you need to manually
+ * call cxTreeIteratorDispose().
+ */
+ void **stack;
+ /**
+ * Internal capacity of the stack.
+ */
+ size_t stack_capacity;
+ };
+ struct {
+ /**
+ * The next element in the visitor queue.
+ */
+ struct cx_tree_visitor_queue_s *queue_next;
+ /**
+ * The last element in the visitor queue.
+ */
+ struct cx_tree_visitor_queue_s *queue_last;
+ };
+ };
/**
- * The next element in the visitor queue.
+ * Indicates whether the subtree below the current node shall be skipped.
*/
- struct cx_tree_visitor_queue_s *queue_next;
+ bool skip;
/**
- * The last element in the visitor queue.
+ * Set to true, when the iterator shall visit a node again
+ * when all its children have been processed.
*/
- struct cx_tree_visitor_queue_s *queue_last;
-} CxTreeVisitor;
+ bool visit_on_exit;
+ /**
+ * True, if this iterator is currently leaving the node.
+ */
+ bool exiting;
+ /**
+ * Indicates whether the @c iterator (true) or the @c visitor (false) aspect is active.
+ */
+ bool use_dfs;
+} CxTreeIterator;
/**
* Releases internal memory of the given tree iterator.
* @param iter the iterator
*/
-cx_attr_nonnull
-CX_EXPORT void cxTreeIteratorDispose(CxTreeIterator *iter);
-
-/**
- * Releases internal memory of the given tree visitor.
- * @param visitor the visitor
- */
-cx_attr_nonnull
-CX_EXPORT void cxTreeVisitorDispose(CxTreeVisitor *visitor);
+CX_EXTERN CX_NONNULL
+void cxTreeIteratorDispose(CxTreeIterator *iter);
/**
* Advises the iterator to skip the subtree below the current node and
*/
#define cxTreeIteratorContinue(iterator) (iterator).skip = true; continue
-/**
- * Advises the visitor to skip the subtree below the current node and
- * also continues the current loop.
- *
- * @param visitor (@c CxTreeVisitor) the visitor
- */
-#define cxTreeVisitorContinue(visitor) cxTreeIteratorContinue(visitor)
-
/**
* Links a node to a (new) parent.
*
* the last child in the linked list (negative if there is no such pointer)
* @param loc_prev optional offset in the node struct for the prev pointer
* @param loc_next offset in the node struct for the next pointer
- * @see cx_tree_unlink()
+ * @see cx_tree_remove()
*/
-cx_attr_nonnull
-CX_EXPORT void cx_tree_link(void *parent, void *node,
+CX_EXTERN CX_NONNULL
+void cx_tree_add(void *parent, void *node,
ptrdiff_t loc_parent, ptrdiff_t loc_children, ptrdiff_t loc_last_child,
ptrdiff_t loc_prev, ptrdiff_t loc_next);
* the last child in the linked list (negative if there is no such pointer)
* @param loc_prev optional offset in the node struct for the prev pointer
* @param loc_next offset in the node struct for the next pointer
- * @see cx_tree_link()
+ * @see cx_tree_add()
*/
-cx_attr_nonnull
-CX_EXPORT void cx_tree_unlink(void *node,
+CX_EXTERN CX_NONNULL
+void cx_tree_remove(void *node,
ptrdiff_t loc_parent, ptrdiff_t loc_children, ptrdiff_t loc_last_child,
ptrdiff_t loc_prev, ptrdiff_t loc_next);
* positive if one of the children might contain the data,
* negative if neither the node nor the children contains the data
*/
-typedef int (*cx_tree_search_data_func)(const void *node, const void *data);
-
-
-/**
- * Function pointer for a search function.
- *
- * A function of this kind shall check if the specified @p node
- * contains the same @p data as @p new_node or if one of the children might
- * contain the data.
- *
- * The function should use the returned integer to indicate how close the
- * match is, where a negative number means that it does not match at all.
- * Zero means exact match and a positive number is an implementation defined
- * measure for the distance to an exact match.
- *
- * For example, consider a tree that stores file path information.
- * A node which is describing a parent directory of a searched file shall
- * return a positive number to indicate that a child node might contain the
- * searched item. On the other hand, if the node denotes a path that is not a
- * prefix of the searched filename, the function would return -1 to indicate
- * that the search does not need to be continued in that branch.
- *
- * @param node the node that is currently investigated
- * @param new_node a new node with the information which is searched
- *
- * @return 0 if @p node contains the same data as @p new_node,
- * positive if one of the children might contain the data,
- * negative if neither the node nor the children contains the data
- */
-typedef int (*cx_tree_search_func)(const void *node, const void *new_node);
+typedef int (*cx_tree_search_func)(const void *node, const void *data);
/**
* Searches for data in a tree.
*
* When the data cannot be found exactly, the search function might return the
* closest result, which might be a good starting point for adding a new node
- * to the tree (see also #cx_tree_add()).
+ * to the tree.
*
* Depending on the tree structure, it is not necessarily guaranteed that the
* "closest" match is uniquely defined. This function will search for a node
* node matching the criteria is returned.
*
* @param root the root node
- * @param depth the maximum depth (zero=indefinite, one=just root)
+ * @param max_depth the maximum depth (zero=indefinite, one=just root)
* @param data the data to search for
* @param sfunc the search function
* @param result where the result shall be stored
* could contain the node (but doesn't right now), negative if the tree does not
* contain any node that might be related to the searched data
*/
-cx_attr_nonnull cx_attr_access_w(5)
-CX_EXPORT int cx_tree_search_data(const void *root, size_t depth,
- const void *data, cx_tree_search_data_func sfunc,
- void **result, ptrdiff_t loc_children, ptrdiff_t loc_next);
-
-/**
- * Searches for a node in a tree.
- *
- * When no node with the same data can be found, the search function might
- * return the closest result, which might be a good starting point for adding the
- * new node to the tree (see also #cx_tree_add()).
- *
- * Depending on the tree structure, it is not necessarily guaranteed that the
- * "closest" match is uniquely defined. This function will search for a node
- * with the best match according to the @p sfunc (meaning: the return value of
- * @p sfunc which is closest to zero). If that is also ambiguous, an arbitrary
- * node matching the criteria is returned.
- *
- * @param root the root node
-* @param depth the maximum depth (zero=indefinite, one=just root)
- * @param node the node to search for
- * @param sfunc the search function
- * @param result where the result shall be stored
- * @param loc_children offset in the node struct for the children linked list
- * @param loc_next offset in the node struct for the next pointer
- * @return zero if the node was found exactly, positive if a node was found that
- * could contain the node (but doesn't right now), negative if the tree does not
- * contain any node that might be related to the searched data
- */
-cx_attr_nonnull cx_attr_access_w(5)
-CX_EXPORT int cx_tree_search(const void *root, size_t depth,
- const void *node, cx_tree_search_func sfunc,
- void **result, ptrdiff_t loc_children, ptrdiff_t loc_next);
+CX_EXTERN CX_NONNULL_ARG(4, 5) CX_ACCESS_W(5)
+int cx_tree_search(const void *root, size_t max_depth,
+ const void *data, cx_tree_search_func sfunc, void **result,
+ ptrdiff_t loc_children, ptrdiff_t loc_next);
/**
* Creates a depth-first iterator for a tree with the specified root node.
* @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);
/**
* is allocated using the cxDefaultAllocator.
* When the visitor becomes invalid, this memory is automatically released.
* However, if you wish to cancel the iteration before the visitor becomes
- * invalid by itself, you MUST call cxTreeVisitorDispose() manually to release
+ * invalid by itself, you MUST call cxTreeIteratorDispose() manually to release
* the memory.
*
* @remark The returned iterator does not support cxIteratorFlagRemoval().
* @param loc_children offset in the node struct for the children linked list
* @param loc_next offset in the node struct for the next pointer
* @return the new tree visitor
- * @see cxTreeVisitorDispose()
+ * @see cxTreeIteratorDispose()
*/
-cx_attr_nodiscard
-CX_EXPORT CxTreeVisitor cx_tree_visitor(void *root,
+CX_EXTERN CX_NODISCARD
+CxTreeIterator cx_tree_visitor(void *root,
ptrdiff_t loc_children, ptrdiff_t loc_next);
-/**
- * Describes a function that creates a tree node from the specified data.
- * The first argument points to the data the node shall contain, and
- * the second argument may be used for additional data (e.g., an allocator).
- * Functions of this type shall either return a new pointer to a newly
- * created node or @c NULL when allocation fails.
- *
- * @note the function may leave the node pointers in the struct uninitialized.
- * The caller is responsible to set them according to the intended use case.
- */
-typedef void *(*cx_tree_node_create_func)(const void *, void *);
-
-/**
- * The local search depth for a new subtree when adding multiple elements.
- * The default value is 3.
- * This variable is used by #cx_tree_add_array() and #cx_tree_add_iter() to
- * implement optimized insertion of multiple elements into a tree.
- */
-CX_EXPORT extern unsigned int cx_tree_add_look_around_depth;
-
-/**
- * Adds multiple elements efficiently to a tree.
- *
- * Once an element cannot be added to the tree, this function returns, leaving
- * the iterator in a valid state pointing to the element that could not be
- * added.
- * Also, the pointer of the created node will be stored to @p failed.
- * The integer returned by this function denotes the number of elements obtained
- * from the @p iter that have been successfully processed.
- * When all elements could be processed, a @c NULL pointer will be written to
- * @p failed.
- *
- * The advantage of this function compared to multiple invocations of
- * #cx_tree_add() is that the search for the insert locations is not always
- * started from the root node.
- * Instead, the function checks #cx_tree_add_look_around_depth many parent nodes
- * of the current insert location before starting from the root node again.
- * When the variable is set to zero, only the last found location is checked
- * again.
- *
- * Refer to the documentation of #cx_tree_add() for more details.
- *
- * @param iter a pointer to an arbitrary iterator
- * @param num the maximum number of elements to obtain from the iterator
- * @param sfunc a search function
- * @param cfunc a node creation function
- * @param cdata optional additional data
- * @param root the root node of the tree
- * @param failed location where the pointer to a failed node shall be stored
- * @param loc_parent offset in the node struct for the parent pointer
- * @param loc_children offset in the node struct for the children linked list
- * @param loc_last_child optional offset in the node struct for the pointer to
- * the last child in the linked list (negative if there is no such pointer)
- * @param loc_prev optional offset in the node struct for the prev pointer
- * @param loc_next offset in the node struct for the next pointer
- * @return the number of nodes created and added
- * @see cx_tree_add()
- */
-cx_attr_nonnull_arg(1, 3, 4, 6, 7) cx_attr_access_w(6)
-CX_EXPORT size_t cx_tree_add_iter(struct cx_iterator_base_s *iter, size_t num,
- cx_tree_search_func sfunc, cx_tree_node_create_func cfunc,
- void *cdata, void **failed, void *root,
- ptrdiff_t loc_parent, ptrdiff_t loc_children, ptrdiff_t loc_last_child,
- ptrdiff_t loc_prev, ptrdiff_t loc_next);
-
-/**
- * Adds multiple elements efficiently to a tree.
- *
- * Once an element cannot be added to the tree, this function returns, storing
- * the pointer of the created node to @p failed.
- * The integer returned by this function denotes the number of elements from
- * the @p src array that have been successfully processed.
- * When all elements could be processed, a @c NULL pointer will be written to
- * @p failed.
- *
- * The advantage of this function compared to multiple invocations of
- * #cx_tree_add() is that the search for the insert locations is not always
- * started from the root node.
- * Instead, the function checks #cx_tree_add_look_around_depth many parent nodes
- * of the current insert location before starting from the root node again.
- * When the variable is set to zero, only the last found location is checked
- * again.
- *
- * Refer to the documentation of #cx_tree_add() for more details.
- *
- * @param src a pointer to the source data array
- * @param num the number of elements in the @p src array
- * @param elem_size the size of each element in the @p src array
- * @param sfunc a search function
- * @param cfunc a node creation function
- * @param cdata optional additional data
- * @param failed location where the pointer to a failed node shall be stored
- * @param root the root node of the tree
- * @param loc_parent offset in the node struct for the parent pointer
- * @param loc_children offset in the node struct for the children linked list
- * @param loc_last_child optional offset in the node struct for the pointer to
- * the last child in the linked list (negative if there is no such pointer)
- * @param loc_prev optional offset in the node struct for the prev pointer
- * @param loc_next offset in the node struct for the next pointer
- * @return the number of array elements successfully processed
- * @see cx_tree_add()
- */
-cx_attr_nonnull_arg(1, 4, 5, 7, 8) cx_attr_access_w(7)
-CX_EXPORT size_t cx_tree_add_array(const void *src, size_t num, size_t elem_size,
- cx_tree_search_func sfunc, cx_tree_node_create_func cfunc,
- void *cdata, void **failed, void *root,
- ptrdiff_t loc_parent, ptrdiff_t loc_children, ptrdiff_t loc_last_child,
- ptrdiff_t loc_prev, ptrdiff_t loc_next);
-
-/**
- * Adds data to a tree.
- *
- * An adequate location where to add the new tree node is searched with the
- * specified @p sfunc.
- *
- * When a location is found, the @p cfunc will be invoked with @p cdata.
- *
- * The node returned by @p cfunc will be linked into the tree.
- * When @p sfunc returns a positive integer, the new node will be linked as a
- * child. The other children (now siblings of the new node) are then checked
- * with @p sfunc, whether they could be children of the new node and re-linked
- * accordingly.
- *
- * When @p sfunc returns zero and the found node has a parent, the new
- * node will be added as a sibling - otherwise, the new node will be added
- * as a child.
- *
- * When @p sfunc returns a negative value, the new node will not be added to
- * the tree, and this function returns a non-zero value.
- * The caller should check if @p cnode contains a node pointer and deal with the
- * node that could not be added.
- *
- * This function also returns a non-zero value when @p cfunc tries to allocate
- * a new node but fails to do so. In that case, the pointer stored to @p cnode
- * will be @c NULL.
- *
- * Multiple elements can be added more efficiently with
- * #cx_tree_add_array() or #cx_tree_add_iter().
- *
- * @param src a pointer to the data
- * @param sfunc a search function
- * @param cfunc a node creation function
- * @param cdata optional additional data
- * @param cnode the location where a pointer to the new node is stored
- * @param root the root node of the tree
- * @param loc_parent offset in the node struct for the parent pointer
- * @param loc_children offset in the node struct for the children linked list
- * @param loc_last_child optional offset in the node struct for the pointer to
- * the last child in the linked list (negative if there is no such pointer)
- * @param loc_prev optional offset in the node struct for the prev pointer
- * @param loc_next offset in the node struct for the next pointer
- * @return zero when a new node was created and added to the tree,
- * non-zero otherwise
- */
-cx_attr_nonnull_arg(1, 2, 3, 5, 6) cx_attr_access_w(5)
-CX_EXPORT int cx_tree_add(const void *src,
- cx_tree_search_func sfunc, cx_tree_node_create_func cfunc,
- void *cdata, void **cnode, void *root,
- ptrdiff_t loc_parent, ptrdiff_t loc_children, ptrdiff_t loc_last_child,
- ptrdiff_t loc_prev, ptrdiff_t loc_next);
-
-
-/**
- * Tree class type.
- */
-typedef struct cx_tree_class_s cx_tree_class;
-
/**
* Base structure that can be used for tree nodes in a #CxTree.
*/
/**
* Structure for holding the base data of a tree.
*/
-struct cx_tree_s {
+typedef struct cx_tree_s {
+ /** Base attributes. */
CX_COLLECTION_BASE;
- /**
- * The tree class definition.
- */
- const cx_tree_class *cl;
-
/**
* A pointer to the root node.
*
void *root;
/**
- * A function to create new nodes.
- *
- * Invocations to this function will receive a pointer to this tree
- * structure as the second argument.
- *
- * Nodes MAY use #cx_tree_node_base_s as the base layout, but do not need to.
- */
- cx_tree_node_create_func node_create;
-
- /**
- * A function to compare two nodes.
+ * The size of the node structure.
*/
- cx_tree_search_func search;
-
- /**
- * A function to compare a node with data.
- */
- cx_tree_search_data_func search_data;
+ size_t node_size;
/**
* Offset in the node struct for the parent pointer.
* Offset in the node struct for the next sibling pointer.
*/
ptrdiff_t loc_next;
-};
+
+ /**
+ * Offset in the node struct where the payload is located.
+ */
+ ptrdiff_t loc_data;
+} CxTree;
/**
* Macro to roll out the #cx_tree_node_base_s structure with a custom
*
* @param type the data type for the nodes
*/
-#define CX_TREE_NODE_BASE(type) \
+#define CX_TREE_NODE(type) \
type *parent; \
type *children;\
type *last_child;\
type *next
/**
- * Macro for specifying the layout of a base node tree.
+ * Macro for specifying the layout of a tree node.
*
- * When your tree uses #CX_TREE_NODE_BASE, you can use this
+ * When your tree uses #CX_TREE_NODE, you can use this
* macro in all tree functions that expect the layout parameters
* @c loc_parent, @c loc_children, @c loc_last_child, @c loc_prev,
* and @c loc_next.
+ * @param struct_name the name of the node structure
*/
-#define cx_tree_node_base_layout \
- offsetof(struct cx_tree_node_base_s, parent),\
- offsetof(struct cx_tree_node_base_s, children),\
- offsetof(struct cx_tree_node_base_s, last_child),\
- offsetof(struct cx_tree_node_base_s, prev), \
- offsetof(struct cx_tree_node_base_s, next)
-
-/**
- * The class definition for arbitrary trees.
- */
-struct cx_tree_class_s {
- /**
- * Member function for inserting a single element.
- *
- * Implementations SHALL NOT simply invoke @p insert_many as this comes
- * with too much overhead.
- */
- int (*insert_element)(struct cx_tree_s *tree, const void *data);
-
- /**
- * Member function for inserting multiple elements.
- *
- * Implementations SHALL avoid performing a full search in the tree for
- * every element even though the source data MAY be unsorted.
- */
- size_t (*insert_many)(struct cx_tree_s *tree, struct cx_iterator_base_s *iter, size_t n);
-
- /**
- * Member function for finding a node.
- */
- void *(*find)(struct cx_tree_s *tree, const void *subtree, const void *data, size_t depth);
-};
-
-/**
- * Common type for all tree implementations.
- */
-typedef struct cx_tree_s CxTree;
-
+#define cx_tree_node_layout(struct_name) \
+ offsetof(struct_name, parent),\
+ offsetof(struct_name, children),\
+ offsetof(struct_name, last_child),\
+ offsetof(struct_name, prev), \
+ offsetof(struct_name, next)
/**
* Destroys a node and its subtree.
* and would therefore result in a double-free.
*
* @param tree the tree
- * @param node the node to remove
+ * @param node the node being the root of the subtree to remove
* @see cxTreeFree()
*/
-cx_attr_nonnull
-CX_EXPORT void cxTreeDestroySubtree(CxTree *tree, void *node);
+CX_EXTERN CX_NONNULL
+void cxTreeDestroySubtree(CxTree *tree, void *node);
/**
* @param tree the tree
* @see cxTreeDestroySubtree()
*/
-#define cxTreeClear(tree) cxTreeDestroySubtree(tree, tree->root)
+CX_INLINE
+void cxTreeClear(CxTree *tree) {
+ if (tree->root != NULL) {
+ cxTreeDestroySubtree(tree, tree->root);
+ }
+}
/**
* Deallocates the tree structure.
*
* @param tree the tree to free
*/
-CX_EXPORT void cxTreeFree(CxTree *tree);
+CX_EXTERN
+void cxTreeFree(CxTree *tree);
/**
- * Creates a new tree structure based on the specified layout.
+ * Creates a new tree.
*
* The specified @p allocator will be used for creating the tree struct
- * and SHALL be used by @p create_func to allocate memory for the nodes.
+ * @em and the nodes.
*
- * @note This function will also register an advanced destructor which
- * will free the nodes with the allocator's free() method.
+ * When you do not specify an existing @p root, the tree will be created
+ * empty. Additionally, cxFree() is registered as the advanced destructor for
+ * the tree so that all nodes that you will add to the tree are automatically
+ * freed together with the tree.
+ * When @p root is not @c NULL, no destructors are registered automatically.
*
- * @param allocator the allocator that shall be used
- * (if @c NULL, the cxDefaultAllocator will be used)
- * @param create_func a function that creates new nodes
- * @param search_func a function that compares two nodes
- * @param search_data_func a function that compares a node with data
- * @param loc_parent offset in the node struct for the parent pointer
- * @param loc_children offset in the node struct for the children linked list
- * @param loc_last_child optional offset in the node struct for the pointer to
- * the last child in the linked list (negative if there is no such pointer)
- * @param loc_prev optional offset in the node struct for the prev pointer
- * @param loc_next offset in the node struct for the next pointer
- * @return the new tree
- * @see cxTreeCreateSimple()
- * @see cxTreeCreateWrapped()
- */
-cx_attr_nonnull_arg(2, 3, 4) cx_attr_nodiscard cx_attr_malloc cx_attr_dealloc(cxTreeFree, 1)
-CX_EXPORT CxTree *cxTreeCreate(const CxAllocator *allocator, cx_tree_node_create_func create_func,
- cx_tree_search_func search_func, cx_tree_search_data_func search_data_func,
- ptrdiff_t loc_parent, ptrdiff_t loc_children, ptrdiff_t loc_last_child,
- ptrdiff_t loc_prev, ptrdiff_t loc_next);
-
-/**
- * Creates a new tree structure based on a default layout.
- *
- * Nodes created by @p create_func MUST contain #cx_tree_node_base_s as the first
- * member (or at least respect the default offsets specified in the tree
- * struct), and they MUST be allocated with the specified allocator.
- *
- * @note This function will also register an advanced destructor which
- * will free the nodes with the allocator's free() method.
- *
- * @param allocator (@c CxAllocator*) the allocator that shall be used
- * @param create_func (@c cx_tree_node_create_func) a function that creates new nodes
- * @param search_func (@c cx_tree_search_func) a function that compares two nodes
- * @param search_data_func (@c cx_tree_search_data_func) a function that compares a node with data
- * @return (@c CxTree*) the new tree
- * @see cxTreeCreate()
- */
-#define cxTreeCreateSimple(allocator, create_func, search_func, search_data_func) \
- cxTreeCreate(allocator, create_func, search_func, search_data_func, cx_tree_node_base_layout)
-
-/**
- * Creates a new tree structure based on an existing tree.
- *
- * The specified @p allocator will be used for creating the tree struct.
- *
- * @attention This function will create an incompletely defined tree structure
- * where neither the create function, the search function, nor a destructor
- * will be set. If you wish to use any of this functionality for the wrapped
- * tree, you need to specify those functions afterward.
- *
- * @param allocator the allocator that was used for nodes of the wrapped tree
+ * @param allocator the allocator to use
* (if @c NULL, the cxDefaultAllocator is assumed)
- * @param root the root node of the tree that shall be wrapped
+ * @param node_size the complete size of one node
+ * @param elem_size the size of the payload stored in the node
+ * (@c CX_STORE_POINTERS is also supported)
+ * @param root an optional already existing root node
+ * @param loc_data optional offset in the node struct for the payload
+ * (when negative, cxTreeAddData() is not supported)
* @param loc_parent offset in the node struct for the parent pointer
* @param loc_children offset in the node struct for the children linked list
* @param loc_last_child optional offset in the node struct for the pointer to
* @return the new tree
* @see cxTreeCreate()
*/
-cx_attr_nonnull_arg(2) cx_attr_nodiscard cx_attr_malloc cx_attr_dealloc(cxTreeFree, 1)
-CX_EXPORT CxTree *cxTreeCreateWrapped(const CxAllocator *allocator, void *root,
+CX_EXTERN CX_NODISCARD CX_MALLOC CX_DEALLOC(cxTreeFree, 1)
+CxTree *cxTreeCreate(const CxAllocator *allocator,
+ size_t node_size, size_t elem_size, void *root, ptrdiff_t loc_data,
ptrdiff_t loc_parent, ptrdiff_t loc_children, ptrdiff_t loc_last_child,
ptrdiff_t loc_prev, ptrdiff_t loc_next);
/**
- * Inserts data into the tree.
- *
- * @remark For this function to work, the tree needs specified search and
- * create functions, which might not be available for wrapped trees
- * (see #cxTreeCreateWrapped()).
- *
- * @param tree the tree
- * @param data the data to insert
- * @retval zero success
- * @retval non-zero failure
- */
-cx_attr_nonnull
-CX_EXPORT int cxTreeInsert(CxTree *tree, const void *data);
-
-/**
- * Inserts elements provided by an iterator efficiently into the tree.
+ * Searches the data in the specified subtree.
*
- * @remark For this function to work, the tree needs specified search and
- * create functions, which might not be available for wrapped trees
- * (see #cxTreeCreateWrapped()).
+ * When @p max_depth is zero, the depth is not limited.
+ * The @p subtree_root itself is on depth 1 and its children have depth 2.
*
- * @param tree the tree
- * @param iter the iterator providing the elements
- * @param n the maximum number of elements to insert
- * @return the number of elements that could be successfully inserted
- */
-cx_attr_nonnull
-CX_EXPORT size_t cxTreeInsertIter(CxTree *tree, CxIteratorBase *iter, size_t n);
-
-/**
- * Inserts an array of data efficiently into the tree.
+ * @note When @p subtree_root is not @c NULL and not part of the @p tree,
+ * the behavior is undefined.
*
- * @remark For this function to work, the tree needs specified search and
- * create functions, which might not be available for wrapped trees
- * (see #cxTreeCreateWrapped()).
+ * @attention When @p loc_data is not available, this function immediately returns
+ * @c NULL.
*
* @param tree the tree
- * @param data the array of data to insert
- * @param elem_size the size of each element in the array
- * @param n the number of elements in the array
- * @return the number of elements that could be successfully inserted
+ * @param data the data to search for
+ * @param subtree_root the node where to start (@c NULL to start from root)
+ * @param max_depth the maximum search depth
+ * @param use_dfs @c true when depth-first search should be used;
+ * @c false when breadth-first search should be used
+ * @return the first matching node, or @c NULL when the data cannot be found
+ * @see cxTreeFind()
*/
-cx_attr_nonnull
-CX_EXPORT size_t cxTreeInsertArray(CxTree *tree, const void *data, size_t elem_size, size_t n);
+CX_EXTERN CX_NONNULL_ARG(1, 2) CX_NODISCARD
+void *cxTreeFindInSubtree(CxTree *tree, const void *data, void *subtree_root,
+ size_t max_depth, bool use_dfs);
/**
* Searches the data in the specified tree.
*
- * @remark For this function to work, the tree needs a specified @c search_data
- * function, which might not be available wrapped trees
- * (see #cxTreeCreateWrapped()).
+ * @attention When @p loc_data is not available, this function immediately returns
+ * @c NULL.
*
* @param tree the tree
* @param data the data to search for
+ * @param use_dfs @c true when depth-first search should be used;
+ * @c false when breadth-first search should be used
* @return the first matching node, or @c NULL when the data cannot be found
+ * @see cxTreeFindInSubtree()
+ * @see cxTreeFindFast()
*/
-cx_attr_nonnull cx_attr_nodiscard
-CX_EXPORT void *cxTreeFind(CxTree *tree, const void *data);
+CX_INLINE CX_NONNULL CX_NODISCARD
+void *cxTreeFind(CxTree *tree, const void *data, bool use_dfs) {
+ if (tree->root == NULL) return NULL;
+ return cxTreeFindInSubtree(tree, data, tree->root, 0, use_dfs);
+}
/**
- * Searches the data in the specified subtree.
+ * Performs an efficient depth-first search in a branch of the specified tree.
*
* When @p max_depth is zero, the depth is not limited.
* The @p subtree_root itself is on depth 1 and its children have depth 2.
*
- * @note When @p subtree_root is not part of the @p tree, the behavior is
- * undefined.
- *
- * @remark For this function to work, the tree needs a specified @c search_data
- * function, which might not be the case for wrapped trees
- * (see #cxTreeCreateWrapped()).
+ * @note When @p subtree_root is not @c NULL and not part of the @p tree,
+ * the behavior is undefined.
*
* @param tree the tree
* @param data the data to search for
- * @param subtree_root the node where to start
+ * @param sfunc the search function
+ * @param subtree_root the node where to start (@c NULL to start from root)
* @param max_depth the maximum search depth
* @return the first matching node, or @c NULL when the data cannot be found
+ * @see cxTreeFindInSubtree()
+ */
+CX_EXTERN CX_NONNULL CX_NODISCARD
+void *cxTreeFindFastInSubtree(CxTree *tree, const void *data,
+ cx_tree_search_func sfunc, void *subtree_root, size_t max_depth);
+
+/**
+ * Performs an efficient depth-first search in the tree.
+ *
+ * @param tree the tree
+ * @param data the data to search for
+ * @param sfunc the search function
+ * @return the first matching node, or @c NULL when the data cannot be found
+ * @see cxTreeFind()
*/
-cx_attr_nonnull cx_attr_nodiscard
-CX_EXPORT void *cxTreeFindInSubtree(CxTree *tree, const void *data, void *subtree_root, size_t max_depth);
+CX_INLINE CX_NONNULL CX_NODISCARD
+void *cxTreeFindFast(CxTree *tree, const void *data, cx_tree_search_func sfunc) {
+ return cxTreeFindFastInSubtree(tree, data, sfunc, tree->root, 0);
+}
/**
* Determines the size of the specified subtree.
* @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.
* @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.
* @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.
* @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.
* @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.
* @return a tree visitor (a.k.a. breadth-first iterator)
* @see cxTreeIterate()
*/
-cx_attr_nonnull cx_attr_nodiscard
-CX_EXPORT CxTreeVisitor cxTreeVisitSubtree(CxTree *tree, void *node);
+CX_EXTERN CX_NONNULL CX_NODISCARD
+CxTreeIterator cxTreeVisitSubtree(CxTree *tree, void *node);
/**
* Creates a depth-first iterator for the specified tree.
* @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.
* @return a tree visitor (a.k.a. breadth-first iterator)
* @see cxTreeIterate()
*/
-cx_attr_nonnull cx_attr_nodiscard
-CX_EXPORT CxTreeVisitor cxTreeVisit(CxTree *tree);
+CX_EXTERN CX_NONNULL CX_NODISCARD
+CxTreeIterator cxTreeVisit(CxTree *tree);
/**
* Sets the (new) parent of the specified child.
*
* If the @p child is not already a member of the tree, this function behaves
- * as #cxTreeAddChildNode().
+ * as #cxTreeAddNode().
*
* @param tree the tree
* @param parent the (new) parent of the child
* @param child the node to add
- * @see cxTreeAddChildNode()
+ * @see cxTreeAddNode()
*/
-cx_attr_nonnull
-CX_EXPORT void cxTreeSetParent(CxTree *tree, void *parent, void *child);
+CX_EXTERN CX_NONNULL
+void cxTreeSetParent(CxTree *tree, void *parent, void *child);
/**
* Adds a new node to the tree.
* Use #cxTreeSetParent() if you want to move a subtree to another location.
*
* @attention The node may be externally created, but MUST obey the same rules
- * as if it was created by the tree itself with #cxTreeAddChild() (e.g., use
- * the same allocator).
+ * as if it was created by the tree itself with #cxTreeAddData() (e.g., use
+ * the tree's allocator).
*
* @param tree the tree
* @param parent the parent of the node to add
* @param child the node to add
* @see cxTreeSetParent()
+ * @see cxTreeAddData()
*/
-cx_attr_nonnull
-CX_EXPORT void cxTreeAddChildNode(CxTree *tree, void *parent, void *child);
+CX_EXTERN CX_NONNULL
+void cxTreeAddNode(CxTree *tree, void *parent, void *child);
/**
* Creates a new node and adds it to the tree.
*
- * With this function you can decide where exactly the new node shall be added.
- * If you specified an appropriate search function, you may want to consider
- * leaving this task to the tree by using #cxTreeInsert().
- *
- * Be aware that adding nodes at arbitrary locations in the tree might cause
- * wrong or undesired results when subsequently invoking #cxTreeInsert(), and
- * the invariant imposed by the search function does not hold any longer.
- *
* @param tree the tree
* @param parent the parent node of the new node
* @param data the data that will be submitted to the create function
- * @return zero when the new node was created, non-zero on allocation failure
- * @see cxTreeInsert()
+ * @return the added node or @c NULL when the allocation failed
+ * @see cxTreeAdd()
+ */
+CX_EXTERN CX_NONNULL
+void *cxTreeAddData(CxTree *tree, void *parent, const void *data);
+
+/**
+ * Creates a new node and adds it to the tree.
+ *
+ * @param tree the tree
+ * @param parent the parent node of the new node
+ * @return the added node or @c NULL when the allocation failed
*/
-cx_attr_nonnull
-CX_EXPORT int cxTreeAddChild(CxTree *tree, void *parent, const void *data);
+CX_EXTERN CX_NODISCARD CX_NONNULL
+void *cxTreeCreateNode(CxTree *tree, void *parent);
+
+/**
+ * Creates a new root node or returns the existing root node.
+ *
+ * @param tree the tree
+ * @return the new root node, the existing root node, or @c NULL when the allocation failed
+ * @see cxTreeCreateRootData()
+ */
+CX_EXTERN CX_NODISCARD CX_NONNULL
+void *cxTreeCreateRoot(CxTree *tree);
+
+/**
+ * Creates a new root node or uses the existing root node and writes the specified data to that node.
+ *
+ * @note This function immediately returns @c NULL when @c loc_data was not initialized with a positive value.
+ *
+ * @param tree the tree
+ * @param data the data for the root node
+ * @return the new root node, the existing root node,
+ * or @c NULL when the allocation failed or the data location is not known
+ * @see cxTreeCreateRoot()
+ */
+CX_EXTERN CX_NODISCARD CX_NONNULL
+void *cxTreeCreateRootData(CxTree *tree, const void *data);
+
+/**
+ * Exchanges the root of the tree.
+ *
+ * @attention The old tree nodes might need to be deallocated by the caller.
+ * On the other hand, when the tree has destructors registered, keep in mind
+ * that they will be applied to the new tree.
+ * In particular, using cxTreeCreate() with a @c NULL root and setting the
+ * root with this function is @em not equivalent to creating the tree with
+ * a reference to an existing root because trees created without a root will
+ * have destructors registered.
+ *
+ * @param tree the tree
+ * @param new_root the new root node
+ * @return the old root node (or @c NULL when the tree was empty)
+ */
+CX_EXTERN CX_NONNULL_ARG(1) CX_NODISCARD
+void *cxTreeSetRoot(CxTree *tree, void *new_root);
/**
* A function that is invoked when a node needs to be re-linked to a new parent.
* 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.
* @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.
* 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
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
;
}
key->hash = h;
}
-
-uint32_t cx_hash_u32(uint32_t x) {
- x = ((x >> 16) ^ x) * 0x45d9f3bu;
- x = ((x >> 16) ^ x) * 0x45d9f3bu;
- x = (x >> 16) ^ x;
- return x;
-}
-
-uint64_t cx_hash_u64(uint64_t x) {
- x = (x ^ (x >> 30)) * UINT64_C(0xbf58476d1ce4e5b9);
- x = (x ^ (x >> 27)) * UINT64_C(0x94d049bb133111eb);
- x = x ^ (x >> 31);
- return x;
-}
-
-CxHashKey cx_hash_key_str(const char *str) {
- CxHashKey key;
- key.data = str;
- key.len = str == NULL ? 0 : strlen(str);
- cx_hash_murmur(&key);
- return key;
-}
-
-CxHashKey cx_hash_key_ustr(unsigned const char *str) {
- CxHashKey key;
- key.data = str;
- key.len = str == NULL ? 0 : strlen((const char*)str);
- cx_hash_murmur(&key);
- return key;
-}
-
-CxHashKey cx_hash_key_cxstr(cxstring str) {
- return cx_hash_key(str.ptr, str.length);
-}
-
-CxHashKey cx_hash_key_mutstr(cxmutstr str) {
- return cx_hash_key(str.ptr, str.length);
-}
-
-CxHashKey cx_hash_key_bytes(
- const unsigned char *bytes,
- size_t len
-) {
- CxHashKey key;
- key.data = bytes;
- key.len = len;
- cx_hash_murmur(&key);
- return key;
-}
-
CxHashKey cx_hash_key(
const void *obj,
size_t len
return key;
}
-CxHashKey cx_hash_key_u32(uint32_t x) {
- CxHashKey key;
- key.data = NULL;
- key.len = 0;
- key.hash = cx_hash_u32(x);
- return key;
-}
-
-CxHashKey cx_hash_key_u64(uint64_t x) {
- CxHashKey key;
- key.data = NULL;
- key.len = 0;
- key.hash = cx_hash_u64(x);
- return key;
-}
-
int cx_hash_key_cmp(const void *l, const void *r) {
const CxHashKey *left = l;
const CxHashKey *right = r;
static CxJsonToken token_create(CxJson *json, bool isstring, size_t start, size_t end) {
cxmutstr str = cx_mutstrn(json->buffer.space + start, end - start);
bool allocated = false;
- if (json->uncompleted.tokentype != CX_JSON_NO_TOKEN) {
+ if (json->uncompleted_tokentype != CX_JSON_NO_TOKEN) {
allocated = true;
- str = cx_strcat_m(json->uncompleted.content, 1, str);
- if (str.ptr == NULL) { // LCOV_EXCL_START
- return (CxJsonToken){CX_JSON_NO_TOKEN, false, {NULL, 0}};
- } // LCOV_EXCL_STOP
+ str = cx_strcat(json->uncompleted_content, 1, str);
+ if (str.ptr == NULL) {
+ return (CxJsonToken){CX_JSON_NO_TOKEN, false, CX_NULLSTR}; // LCOV_EXCL_LINE
+ }
+ json->uncompleted_content = CX_NULLSTR;
+ json->uncompleted_tokentype = CX_JSON_NO_TOKEN;
}
- json->uncompleted = (CxJsonToken){0};
CxJsonTokenType ttype;
if (isstring) {
ttype = CX_JSON_TOKEN_STRING;
} else {
- cxstring s = cx_strcast(str);
- if (!cx_strcmp(s, "true") || !cx_strcmp(s, "false")
- || !cx_strcmp(s, "null")) {
+ if (!cx_strcmp(str, "true") || !cx_strcmp(str, "false")
+ || !cx_strcmp(str, "null")) {
ttype = CX_JSON_TOKEN_LITERAL;
} else {
ttype = token_numbertype(str.ptr, str.length);
if (allocated) {
cx_strfree(&str);
}
- return (CxJsonToken){CX_JSON_TOKEN_ERROR, false, {NULL, 0}};
+ return (CxJsonToken){CX_JSON_TOKEN_ERROR, false, CX_NULLSTR};
}
return (CxJsonToken){ttype, allocated, str};
}
static enum cx_json_status token_parse_next(CxJson *json, CxJsonToken *result) {
// check if there is data in the buffer
if (cxBufferEof(&json->buffer)) {
- return json->uncompleted.tokentype == CX_JSON_NO_TOKEN ?
+ return json->uncompleted_tokentype == CX_JSON_NO_TOKEN ?
CX_JSON_NO_DATA : CX_JSON_INCOMPLETE_DATA;
}
// current token type and start index
- CxJsonTokenType ttype = json->uncompleted.tokentype;
+ CxJsonTokenType ttype = json->uncompleted_tokentype;
size_t token_part_start = json->buffer.pos;
bool escape_end_of_string = ttype == CX_JSON_TOKEN_STRING
- && json->uncompleted.content.ptr[json->uncompleted.content.length-1] == '\\';
+ && cx_strat(json->uncompleted_content, -1) == '\\';
for (size_t i = json->buffer.pos; i < json->buffer.size; i++) {
char c = json->buffer.space[i];
} else if (ctype != CX_JSON_NO_TOKEN) {
// single-char token
json->buffer.pos = i + 1;
- *result = (CxJsonToken){ctype, false, {NULL, 0}};
+ *result = (CxJsonToken){ctype, false, CX_NULLSTR};
return CX_JSON_NO_ERROR;
} else {
ttype = CX_JSON_TOKEN_LITERAL; // number or literal
return CX_JSON_NO_DATA;
} else {
// uncompleted token
- size_t uncompleted_len = json->buffer.size - token_part_start;
- if (json->uncompleted.tokentype == CX_JSON_NO_TOKEN) {
- // current token is uncompleted
- // save current token content
- CxJsonToken uncompleted = {
- ttype, true,
- cx_strdup(cx_strn(json->buffer.space + token_part_start, uncompleted_len))
- };
- if (uncompleted.content.ptr == NULL) {
+ cxstring uncompleted = cx_strn(json->buffer.space + token_part_start, json->buffer.size - token_part_start);
+ if (json->uncompleted_tokentype == CX_JSON_NO_TOKEN) {
+ assert(json->uncompleted_content.ptr == NULL);
+ json->uncompleted_content = cx_strdup(uncompleted);
+ if (json->uncompleted_content.ptr == NULL) {
return CX_JSON_BUFFER_ALLOC_FAILED; // LCOV_EXCL_LINE
}
- json->uncompleted = uncompleted;
+ json->uncompleted_tokentype = ttype;
} else {
- // previously we also had an uncompleted token
+ // previously we already had an uncompleted token
// combine the uncompleted token with the current token
- assert(json->uncompleted.allocated);
- cxmutstr str = cx_strcat_m(json->uncompleted.content, 1,
- cx_strn(json->buffer.space + token_part_start, uncompleted_len));
- if (str.ptr == NULL) {
+ cxmutstr s = cx_strcat(json->uncompleted_content, 1, uncompleted);
+ if (s.ptr == NULL) {
return CX_JSON_BUFFER_ALLOC_FAILED; // LCOV_EXCL_LINE
}
- json->uncompleted.content = str;
+ json->uncompleted_content = s;
}
// advance the buffer position - we saved the stuff in the uncompleted token
- json->buffer.pos += uncompleted_len;
+ json->buffer.pos += uncompleted.length;
return CX_JSON_INCOMPLETE_DATA;
}
}
}
cxJsonValueFree(json->parsed);
json->parsed = NULL;
- token_destroy(&json->uncompleted);
+ json->uncompleted_tokentype = CX_JSON_NO_TOKEN;
+ cx_strfree(&json->uncompleted_content);
cx_strfree_a(json->allocator, &json->uncompleted_member_name);
}
CxBuffer buffer;
if (cxBufferInit(&buffer, allocator, NULL, 128,
CX_BUFFER_AUTO_EXTEND | CX_BUFFER_DO_NOT_FREE)) {
- return (cxmutstr){NULL, 0};
+ return CX_NULLSTR; // LCOV_EXCL_LINE
}
if (cx_json_write_rec(&buffer, value, cxBufferWriteFunc, writer, 0)
|| cxBufferTerminate(&buffer)) {
// LCOV_EXCL_START
buffer.flags &= ~CX_BUFFER_DO_NOT_FREE;
cxBufferDestroy(&buffer);
- return (cxmutstr){NULL, 0};
+ return CX_NULLSTR;
// LCOV_EXCL_STOP
} else {
cxmutstr str = cx_bstr_m(&buffer);
return cx_vcmp_double(json->number, cxJsonAsDouble(other));
case CX_JSON_LITERAL:
return json->literal == other->literal ? 0 : -1;
- default:
- // LCOV_EXCL_START
+ default: // LCOV_EXCL_START
// unreachable
assert(false);
return -1;
}
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;
}
return ret; \
} else { \
*target = *ret; \
- cxFree(allocator, ret); \
+ ret->type = CX_JSON_UNINITIALIZED; \
+ cxJsonValueFree(ret); \
return target; \
} \
}
arr->array.size = elem_count;
for (size_t i = 0 ; i < elem_count ; i++) {
CxJsonValue *e = cx_json_clone_func(NULL, source->array.data[i], allocator, NULL);
- if (e == NULL) {
- // LCOV_EXCL_START
+ if (e == NULL) { // LCOV_EXCL_START
cxJsonValueFree(arr);
return NULL;
// LCOV_EXCL_STOP
return_value(cxJsonCreateNumber(allocator, source->number));
case CX_JSON_LITERAL:
return_value(cxJsonCreateLiteral(allocator, source->literal));
- default:
- // LCOV_EXCL_START
+ default: // LCOV_EXCL_START
// unreachable
assert(false);
return NULL;
}
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;
void cx_linked_list_extra_data(cx_linked_list *list, size_t len) {
list->extra_data_len = len;
- off_t loc_extra = list->loc_data + list->base.collection.elem_size;
+ off_t loc_extra = list->loc_data + (off_t) list->base.collection.elem_size;
size_t alignment = alignof(void*);
- size_t padding = alignment - (loc_extra % alignment);
- list->loc_extra = loc_extra + padding;
+ size_t padding = alignment - ((size_t)loc_extra % alignment);
+ list->loc_extra = loc_extra + (off_t) padding;
}
// <editor-fold desc="empty list implementation">
-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;
\r
// <editor-fold desc="empty map implementation">\r
\r
-static void cx_empty_map_noop(cx_attr_unused CxMap *map) {\r
+static void cx_empty_map_noop(CX_UNUSED CxMap *map) {\r
// this is a noop, but MUST be implemented\r
}\r
\r
static void *cx_empty_map_get(\r
- cx_attr_unused const CxMap *map,\r
- cx_attr_unused CxHashKey key\r
+ CX_UNUSED const CxMap *map,\r
+ CX_UNUSED CxHashKey key\r
) {\r
return NULL;\r
}\r
\r
-static bool cx_empty_map_iter_valid(cx_attr_unused const void *iter) {\r
+static bool cx_empty_map_iter_valid(CX_UNUSED const void *iter) {\r
return false;\r
}\r
\r
static CxMapIterator cx_empty_map_iterator(\r
const struct cx_map_s *map,\r
- cx_attr_unused enum cx_map_iterator_type type\r
+ CX_UNUSED enum cx_map_iterator_type type\r
) {\r
CxMapIterator iter = {0};\r
iter.map = (CxMap*) map;\r
cxstring nl = cx_strchr(input, '\n');
while (nl.length > 0) {
// check for line continuation
- char previous = nl.ptr > input.ptr ? nl.ptr[-1] : prop->buffer.space[prop->buffer.size-1];
+ char previous = nl.ptr > input.ptr ? nl.ptr[-1] : cx_strat(cx_bstr(&prop->buffer), -1);
if (previous == continuation) {
// this nl is a line continuation, check the next newline
nl = cx_strchr(cx_strsubs(nl, 1), '\n');
if (cxBufferAppend(input.ptr, 1,
len_until_nl, &prop->buffer) < len_until_nl) {
- return CX_PROPERTIES_BUFFER_ALLOC_FAILED;
+ return CX_PROPERTIES_BUFFER_ALLOC_FAILED; // LCOV_EXCL_LINE
}
// advance the position in the input buffer
cxBufferReset(&prop->buffer);
}
if (cxBufferAppend(buf, 1, len, &prop->buffer) < len) {
- return CX_PROPERTIES_BUFFER_ALLOC_FAILED;
+ return CX_PROPERTIES_BUFFER_ALLOC_FAILED; // LCOV_EXCL_LINE
}
// reset the input buffer (make way for a re-fill)
cxBufferReset(&prop->input);
prop->buffer.size = 0;
prop->buffer.pos = 0;
if (cxBufferWrite(val.ptr, 1, val.length, &prop->buffer) != val.length) {
- return CX_PROPERTIES_BUFFER_ALLOC_FAILED;
+ return CX_PROPERTIES_BUFFER_ALLOC_FAILED; // LCOV_EXCL_LINE
}
val.ptr = prop->buffer.space;
ptr = prop->buffer.space;
}
// initialize the parser
- char linebuf[cx_properties_load_buf_size];
- char fillbuf[cx_properties_load_fill_size];
+ char linebuf[CX_PROPERTIES_LOAD_BUF_SIZE];
+ char fillbuf[CX_PROPERTIES_LOAD_FILL_SIZE];
CxPropertiesStatus status;
CxProperties parser;
cxPropertiesInit(&parser, config);
- cxPropertiesUseStack(&parser, linebuf, cx_properties_load_buf_size);
+ cxPropertiesUseStack(&parser, linebuf, CX_PROPERTIES_LOAD_BUF_SIZE);
// read/fill/parse loop
status = CX_PROPERTIES_NO_DATA;
while (true) {
size_t r = fread(fillbuf, 1, cx_properties_load_fill_size, f);
if (ferror(f)) {
+ // LCOV_EXCL_START
status = CX_PROPERTIES_FILE_ERROR;
break;
+ // LCOV_EXCL_STOP
}
if (r == 0) {
break;
}
if (cxPropertiesFilln(&parser, fillbuf, r)) {
+ // LCOV_EXCL_START
status = CX_PROPERTIES_BUFFER_ALLOC_FAILED;
break;
+ // LCOV_EXCL_STOP
}
cxstring key, value;
while (true) {
break;
} else {
cxmutstr v = cx_strdup_a(allocator, value);
+ // LCOV_EXCL_START
if (v.ptr == NULL) {
status = CX_PROPERTIES_MAP_ERROR;
break;
}
+ // LCOV_EXCL_STOP
void *mv = use_cstring ? (void*)v.ptr : &v;
if (cxMapPut(target, key, mv)) {
+ // LCOV_EXCL_START
cx_strfree(&v);
status = CX_PROPERTIES_MAP_ERROR;
break;
+ // LCOV_EXCL_STOP
}
keys_found++;
}
#include <ctype.h>
#ifdef _WIN32
-#define cx_strcasecmp_impl _strnicmp
+static int cx_fixed_strnicmp(const char* s1, const char* s2, size_t count) {
+ // Microsoft's implementation crashes when count == 0 and either string is NULL
+ if (count == 0) return 0;
+ return _strnicmp(s1, s2, count);
+}
+#define cx_strcasecmp_impl cx_fixed_strnicmp
#else
#include <strings.h>
#define cx_strcasecmp_impl strncasecmp
return size;
}
-cxmutstr cx_strcat_ma(
+cxmutstr cx_strcat_a(
const CxAllocator *alloc,
cxmutstr str,
size_t count,
...
) {
- if (count == 0) return str;
+ if (count == 0) {
+ if (cxReallocate(alloc, &str.ptr, str.length + 1)) {
+ return CX_NULLSTR; // LCOV_EXCL_LINE
+ }
+ str.ptr[str.length] = '\0';
+ return str;
+ }
va_list ap;
va_start(ap, count);
va_list ap2;
if (overflow) {
va_end(ap2);
errno = EOVERFLOW;
- return (cxmutstr) { NULL, 0 };
+ return CX_NULLSTR;
}
- // reallocate or create new string
- char *newstr;
- if (str.ptr == NULL) {
- newstr = cxMalloc(alloc, slen + 1);
- } else {
- newstr = cxRealloc(alloc, str.ptr, slen + 1);
- }
- if (newstr == NULL) { // LCOV_EXCL_START
+ // reallocate or create a new string
+ if (cxReallocate(alloc, &str.ptr, slen + 1)) {
+ // LCOV_EXCL_START
va_end(ap2);
- return (cxmutstr) {NULL, 0};
- } // LCOV_EXCL_STOP
- str.ptr = newstr;
+ return CX_NULLSTR;
+ // LCOV_EXCL_STOP
+ }
// concatenate strings
size_t pos = str.length;
return str;
}
-cxstring cx_strsubs(
+cxstring cx_strsubs_(
cxstring string,
size_t start
) {
- return cx_strsubsl(string, start, string.length - start);
+ return cx_strsubsl_(string, start, string.length);
}
-cxmutstr cx_strsubs_m(
- cxmutstr string,
- size_t start
-) {
- return cx_strsubsl_m(string, start, string.length - start);
-}
-
-cxstring cx_strsubsl(
+cxstring cx_strsubsl_(
cxstring string,
size_t start,
size_t length
return (cxstring) {string.ptr + start, length};
}
-cxmutstr cx_strsubsl_m(
- cxmutstr string,
- size_t start,
- size_t length
-) {
- cxstring result = cx_strsubsl(cx_strcast(string), start, length);
- return (cxmutstr) {(char *) result.ptr, result.length};
-}
-
-cxstring cx_strchr(
+cxstring cx_strchr_(
cxstring string,
int chr
) {
return (cxstring) {ret, string.length - (ret - string.ptr)};
}
-cxmutstr cx_strchr_m(
- cxmutstr string,
- int chr
-) {
- cxstring result = cx_strchr(cx_strcast(string), chr);
- return (cxmutstr) {(char *) result.ptr, result.length};
-}
-
-cxstring cx_strrchr(
+cxstring cx_strrchr_(
cxstring string,
int chr
) {
#endif
}
-cxmutstr cx_strrchr_m(
- cxmutstr string,
- int chr
-) {
- cxstring result = cx_strrchr(cx_strcast(string), chr);
- return (cxmutstr) {(char *) result.ptr, result.length};
-}
-
#ifndef CX_STRSTR_SBO_SIZE
#define CX_STRSTR_SBO_SIZE 128
#endif
return result;
}
-cxmutstr cx_strstr_m_(
- cxmutstr haystack,
- cxstring needle
-) {
- cxstring result = cx_strstr(cx_strcast(haystack), needle);
- return (cxmutstr) {(char *) result.ptr, result.length};
-}
-
size_t cx_strsplit_(
cxstring string,
cxstring delim,
return result;
}
-cxstring cx_strtrim(cxstring string) {
+cxstring cx_strtrim_(cxstring string) {
cxstring result = string;
- while (result.length > 0 && isspace((unsigned char)(result.ptr[0]))) {
+ while (isspace((unsigned char)cx_strat(result, 0))) {
result.ptr++;
result.length--;
}
- while (result.length > 0 && isspace((unsigned char)result.ptr[result.length - 1])) {
+ while (isspace((unsigned char)cx_strat(result, -1))) {
result.length--;
}
return result;
}
-cxmutstr cx_strtrim_m(cxmutstr string) {
- cxstring result = cx_strtrim(cx_strcast(string));
- return (cxmutstr) {(char *) result.ptr, result.length};
-}
-
bool cx_strprefix_(
cxstring string,
cxstring prefix
return ctx;
}
-bool cx_strtok_next(
+bool cx_strtok_next_(
CxStrtokCtx *ctx,
cxstring *token
) {
return true;
}
-bool cx_strtok_next_m(
- CxStrtokCtx *ctx,
- cxmutstr *token
-) {
- return cx_strtok_next(ctx, (cxstring *) token);
-}
-
void cx_strtok_delim(
CxStrtokCtx *ctx,
const cxstring *delim,
#include "cx/tree.h"
#include <assert.h>
+#include <string.h>
#define CX_TREE_PTR(cur, off) (*(void**)(((char*)(cur))+(off)))
#define tree_parent(node) CX_TREE_PTR(node, loc_parent)
#define tree_prev(node) CX_TREE_PTR(node, loc_prev)
#define tree_next(node) CX_TREE_PTR(node, loc_next)
-#define cx_tree_ptr_locations \
- loc_parent, loc_children, loc_last_child, loc_prev, loc_next
-
-#define cx_tree_node_layout(tree) \
+#define tree_layout(tree) \
(tree)->loc_parent,\
(tree)->loc_children,\
(tree)->loc_last_child,\
(tree)->loc_prev, \
(tree)->loc_next
-static void cx_tree_zero_pointers(
- void *node,
- ptrdiff_t loc_parent,
- ptrdiff_t loc_children,
- ptrdiff_t loc_last_child,
- ptrdiff_t loc_prev,
- ptrdiff_t loc_next
-) {
- tree_parent(node) = NULL;
- if (loc_prev >= 0) {
- tree_prev(node) = NULL;
- }
- tree_next(node) = NULL;
- tree_children(node) = NULL;
- if (loc_last_child >= 0) {
- tree_last_child(node) = NULL;
- }
-}
-
-void cx_tree_link(
+void cx_tree_add(
void *parent,
void *node,
ptrdiff_t loc_parent,
void *current_parent = tree_parent(node);
if (current_parent == parent) return;
if (current_parent != NULL) {
- cx_tree_unlink(node, cx_tree_ptr_locations);
+ cx_tree_remove(node, loc_parent, loc_children,
+ loc_last_child, loc_prev, loc_next);
}
if (tree_children(parent) == NULL) {
}
}
-void cx_tree_unlink(
+void cx_tree_remove(
void *node,
ptrdiff_t loc_parent,
ptrdiff_t loc_children,
}
}
-int cx_tree_search(
- const void *root,
- size_t depth,
- const void *node,
- cx_tree_search_func sfunc,
- void **result,
- ptrdiff_t loc_children,
- ptrdiff_t loc_next
-) {
+int cx_tree_search(const void *root, size_t max_depth,
+ const void *data, cx_tree_search_func sfunc, void **result,
+ ptrdiff_t loc_children, ptrdiff_t loc_next) {
// help avoiding bugs due to uninitialized memory
assert(result != NULL);
*result = NULL;
+ // NULL root? exit!
+ if (root == NULL) {
+ return -1;
+ }
+
// remember return value for best match
- int ret = sfunc(root, node);
+ int ret = sfunc(root, data);
if (ret < 0) {
// not contained, exit
return -1;
}
// when depth is one, we are already done
- if (depth == 1) {
+ if (max_depth == 1) {
return ret;
}
// special case: indefinite depth
- if (depth == 0) {
- depth = SIZE_MAX;
+ if (max_depth == 0) {
+ max_depth = SIZE_MAX;
}
// create an iterator
// loop through the remaining tree
cx_foreach(void *, elem, iter) {
// investigate the current node
- int ret_elem = sfunc(elem, node);
+ int ret_elem = sfunc(elem, data);
if (ret_elem == 0) {
// if found, exit the search
*result = elem;
}
// when we reached the max depth, skip the subtree
- if (iter.depth == depth) {
+ if (iter.depth == max_depth) {
cxTreeIteratorContinue(iter);
}
}
- // dispose the iterator as we might have exited the loop early
+ // dispose of the iterator as we might have exited the loop early
cxTreeIteratorDispose(&iter);
assert(ret < 0 || *result != NULL);
return ret;
}
-int cx_tree_search_data(
- const void *root,
- size_t depth,
- const void *data,
- cx_tree_search_data_func sfunc,
- void **result,
- ptrdiff_t loc_children,
- ptrdiff_t loc_next
-) {
- // it is basically the same implementation
- return cx_tree_search(
- root, depth, data,
- (cx_tree_search_func) sfunc,
- result,
- loc_children, loc_next);
-}
-
static bool cx_tree_iter_valid(const void *it) {
- const struct cx_tree_iterator_s *iter = it;
+ const CxTreeIterator *iter = it;
return iter->node != NULL;
}
static void *cx_tree_iter_current(const void *it) {
- const struct cx_tree_iterator_s *iter = it;
+ const CxTreeIterator *iter = it;
return iter->node;
}
static void cx_tree_iter_next(void *it) {
- struct cx_tree_iterator_s *iter = it;
+ CxTreeIterator *iter = it;
ptrdiff_t const loc_next = iter->loc_next;
ptrdiff_t const loc_children = iter->loc_children;
// protect us from misuse
}
} else {
// node has children, push the first child onto the stack and enter it
- if (iter->stack_size >= iter->stack_capacity) {
+ if (iter->depth >= iter->stack_capacity) {
const size_t newcap = iter->stack_capacity + 8;
- if (cxReallocArrayDefault(&iter->stack, newcap, sizeof(void*))) {
+ if (cxReallocateArrayDefault(&iter->stack, newcap, sizeof(void*))) {
// we cannot return an error in this function
abort(); // LCOV_EXCL_LINE
}
iter->stack_capacity = newcap;
}
- iter->stack[iter->stack_size] = children;
- iter->stack_size++;
+ iter->stack[iter->depth] = children;
+ iter->depth++;
iter->node = children;
iter->counter++;
}
ptrdiff_t loc_children,
ptrdiff_t loc_next
) {
- CxTreeIterator iter;
- iter.loc_children = loc_children;
- iter.loc_next = loc_next;
- iter.visit_on_exit = visit_on_exit;
+ CxTreeIterator ret;
+ ret.use_dfs = true;
+ ret.loc_children = loc_children;
+ ret.loc_next = loc_next;
+ ret.visit_on_exit = visit_on_exit;
// initialize members
- iter.node_next = NULL;
- iter.exiting = false;
- iter.skip = false;
+ ret.node_next = NULL;
+ ret.exiting = false;
+ ret.skip = false;
// assign base iterator functions
- iter.base.allow_remove = false;
- iter.base.remove = false;
- iter.base.current_impl = NULL;
- iter.base.valid = cx_tree_iter_valid;
- iter.base.next = cx_tree_iter_next;
- iter.base.current = cx_tree_iter_current;
+ ret.base.allow_remove = false;
+ ret.base.remove = false;
+ ret.base.current_impl = NULL;
+ ret.base.valid = cx_tree_iter_valid;
+ ret.base.next = cx_tree_iter_next;
+ ret.base.current = cx_tree_iter_current;
// visit the root node
- iter.node = root;
+ ret.node = root;
if (root != NULL) {
- iter.stack_capacity = 16;
- iter.stack = cxMallocDefault(sizeof(void *) * 16);
- iter.stack[0] = root;
- iter.counter = 1;
- iter.depth = 1;
+ ret.stack_capacity = 16;
+ ret.stack = cxMallocDefault(sizeof(void *) * 16);
+ ret.stack[0] = root;
+ ret.counter = 1;
+ ret.depth = 1;
} else {
- iter.stack_capacity = 0;
- iter.stack = NULL;
- iter.counter = 0;
- iter.depth = 0;
+ ret.stack_capacity = 0;
+ ret.stack = NULL;
+ ret.counter = 0;
+ ret.depth = 0;
}
- return iter;
+ return ret;
}
static bool cx_tree_visitor_valid(const void *it) {
- const struct cx_tree_visitor_s *iter = it;
+ const CxTreeIterator *iter = it;
return iter->node != NULL;
}
static void *cx_tree_visitor_current(const void *it) {
- const struct cx_tree_visitor_s *iter = it;
+ const CxTreeIterator *iter = it;
return iter->node;
}
-cx_attr_nonnull
+CX_NONNULL
static void cx_tree_visitor_enqueue_siblings(
- struct cx_tree_visitor_s *iter, void *node, ptrdiff_t loc_next) {
+ CxTreeIterator *iter, void *node, ptrdiff_t loc_next) {
node = tree_next(node);
while (node != NULL) {
struct cx_tree_visitor_queue_s *q;
}
static void cx_tree_visitor_next(void *it) {
- struct cx_tree_visitor_s *iter = it;
+ CxTreeIterator *iter = it;
// protect us from misuse
if (!iter->base.valid(iter)) return;
iter->counter++;
}
-CxTreeVisitor cx_tree_visitor(
+CxTreeIterator cx_tree_visitor(
void *root,
ptrdiff_t loc_children,
ptrdiff_t loc_next
) {
- CxTreeVisitor iter;
- iter.loc_children = loc_children;
- iter.loc_next = loc_next;
+ CxTreeIterator ret;
+ ret.visit_on_exit = false;
+ ret.exiting = false;
+ ret.use_dfs = false;
+ ret.loc_children = loc_children;
+ ret.loc_next = loc_next;
// initialize members
- iter.skip = false;
- iter.queue_next = NULL;
- iter.queue_last = NULL;
+ ret.skip = false;
+ ret.queue_next = NULL;
+ ret.queue_last = NULL;
// assign base iterator functions
- iter.base.allow_remove = false;
- iter.base.remove = false;
- iter.base.current_impl = NULL;
- iter.base.valid = cx_tree_visitor_valid;
- iter.base.next = cx_tree_visitor_next;
- iter.base.current = cx_tree_visitor_current;
+ ret.base.allow_remove = false;
+ ret.base.remove = false;
+ ret.base.current_impl = NULL;
+ ret.base.valid = cx_tree_visitor_valid;
+ ret.base.next = cx_tree_visitor_next;
+ ret.base.current = cx_tree_visitor_current;
// visit the root node
- iter.node = root;
+ ret.node = root;
if (root != NULL) {
- iter.counter = 1;
- iter.depth = 1;
- } else {
- iter.counter = 0;
- iter.depth = 0;
- }
-
- return iter;
-}
-
-static void cx_tree_add_link_duplicate(
- void *original, void *duplicate,
- ptrdiff_t loc_parent, ptrdiff_t loc_children, ptrdiff_t loc_last_child,
- ptrdiff_t loc_prev, ptrdiff_t loc_next
-) {
- void *shared_parent = tree_parent(original);
- if (shared_parent == NULL) {
- cx_tree_link(original, duplicate, cx_tree_ptr_locations);
- } else {
- cx_tree_link(shared_parent, duplicate, cx_tree_ptr_locations);
- }
-}
-
-static void cx_tree_add_link_new(
- void *parent, void *node, cx_tree_search_func sfunc,
- ptrdiff_t loc_parent, ptrdiff_t loc_children, ptrdiff_t loc_last_child,
- ptrdiff_t loc_prev, ptrdiff_t loc_next
-) {
- // check the current children one by one,
- // if they could be children of the new node
- void *child = tree_children(parent);
- while (child != NULL) {
- void *next = tree_next(child);
-
- if (sfunc(node, child) > 0) {
- // the sibling could be a child -> re-link
- cx_tree_link(node, child, cx_tree_ptr_locations);
- }
-
- child = next;
- }
-
- // add new node as new child
- cx_tree_link(parent, node, cx_tree_ptr_locations);
-}
-
-int cx_tree_add(
- const void *src,
- cx_tree_search_func sfunc,
- cx_tree_node_create_func cfunc,
- void *cdata,
- void **cnode,
- void *root,
- ptrdiff_t loc_parent,
- ptrdiff_t loc_children,
- ptrdiff_t loc_last_child,
- ptrdiff_t loc_prev,
- ptrdiff_t loc_next
-) {
- *cnode = cfunc(src, cdata);
- if (*cnode == NULL) return 1; // LCOV_EXCL_LINE
- cx_tree_zero_pointers(*cnode, cx_tree_ptr_locations);
-
- void *match = NULL;
- int result = cx_tree_search(
- root,
- 0,
- *cnode,
- sfunc,
- &match,
- loc_children,
- loc_next
- );
-
- if (result < 0) {
- // node does not fit into the tree - return non-zero value
- return 1;
- } else if (result == 0) {
- // data already found in the tree, link duplicate
- cx_tree_add_link_duplicate(match, *cnode, cx_tree_ptr_locations);
+ ret.counter = 1;
+ ret.depth = 1;
} else {
- // closest match found, add new node
- cx_tree_add_link_new(match, *cnode, sfunc, cx_tree_ptr_locations);
+ ret.counter = 0;
+ ret.depth = 0;
}
- return 0;
+ return ret;
}
-unsigned int cx_tree_add_look_around_depth = 3;
-
-size_t cx_tree_add_iter(
- struct cx_iterator_base_s *iter,
- size_t num,
- cx_tree_search_func sfunc,
- cx_tree_node_create_func cfunc,
- void *cdata,
- void **failed,
- void *root,
- ptrdiff_t loc_parent,
- ptrdiff_t loc_children,
- ptrdiff_t loc_last_child,
- ptrdiff_t loc_prev,
- ptrdiff_t loc_next
-) {
- // erase the failed pointer
- *failed = NULL;
-
- // iter not valid? cancel...
- if (!iter->valid(iter)) return 0;
-
- size_t processed = 0;
- void *current_node = root;
- const void *elem;
-
- for (void **eptr; processed < num &&
- iter->valid(iter) && (eptr = iter->current(iter)) != NULL;
- iter->next(iter)) {
- elem = *eptr;
-
- // create the new node
- void *new_node = cfunc(elem, cdata);
- if (new_node == NULL) return processed; // LCOV_EXCL_LINE
- cx_tree_zero_pointers(new_node, cx_tree_ptr_locations);
-
- // start searching from current node
- void *match;
- int result;
- unsigned int look_around_retries = cx_tree_add_look_around_depth;
- cx_tree_add_look_around_retry:
- result = cx_tree_search(
- current_node,
- 0,
- new_node,
- sfunc,
- &match,
- loc_children,
- loc_next
- );
-
- if (result < 0) {
- // traverse upwards and try to find better parents
- void *parent = tree_parent(current_node);
- if (parent != NULL) {
- if (look_around_retries > 0) {
- look_around_retries--;
- current_node = parent;
- } else {
- // look around retries exhausted, start from the root
- current_node = root;
- }
- goto cx_tree_add_look_around_retry;
- } else {
- // no parents. so we failed
- *failed = new_node;
- return processed;
- }
- } else if (result == 0) {
- // data already found in the tree, link duplicate
- cx_tree_add_link_duplicate(match, new_node, cx_tree_ptr_locations);
- // but stick with the original match, in case we needed a new root
- current_node = match;
- } else {
- // closest match found, add new node as child
- cx_tree_add_link_new(match, new_node, sfunc,
- cx_tree_ptr_locations);
- current_node = match;
- }
-
- processed++;
+size_t cx_tree_size(void *root, ptrdiff_t loc_children, ptrdiff_t loc_next) {
+ CxTreeIterator iter = cx_tree_iterator(root, false, loc_children, loc_next);
+ while (cxIteratorValid(iter)) {
+ cxIteratorNext(iter);
}
- return processed;
+ return iter.counter;
}
-size_t cx_tree_add_array(
- const void *src,
- size_t num,
- size_t elem_size,
- cx_tree_search_func sfunc,
- cx_tree_node_create_func cfunc,
- void *cdata,
- void **failed,
- void *root,
- ptrdiff_t loc_parent,
- ptrdiff_t loc_children,
- ptrdiff_t loc_last_child,
- ptrdiff_t loc_prev,
- ptrdiff_t loc_next
-) {
- // erase failed pointer
- *failed = NULL;
-
- // super special case: zero elements
- if (num == 0) {
- return 0;
- }
-
- // special case: one element does not need an iterator
- if (num == 1) {
- void *node;
- if (0 == cx_tree_add(
- src, sfunc, cfunc, cdata, &node, root,
- loc_parent, loc_children, loc_last_child,
- loc_prev, loc_next)) {
- return 1;
- } else {
- *failed = node;
- return 0;
+size_t cx_tree_depth(void *root, ptrdiff_t loc_children, ptrdiff_t loc_next) {
+ CxTreeIterator iter = cx_tree_iterator(root, false, loc_children, loc_next);
+ size_t depth = 0;
+ while (cxIteratorValid(iter)) {
+ if (iter.depth > depth) {
+ depth = iter.depth;
}
+ cxIteratorNext(iter);
}
-
- // otherwise, create iterator and hand over to other function
- CxIterator iter = cxIterator(src, elem_size, num);
- return cx_tree_add_iter(cxIteratorRef(iter), num, sfunc,
- cfunc, cdata, failed, root,
- loc_parent, loc_children, loc_last_child,
- loc_prev, loc_next);
-}
-
-static int cx_tree_default_insert_element(
- CxTree *tree,
- const void *data
-) {
- void *node;
- if (tree->root == NULL) {
- node = tree->node_create(data, tree);
- if (node == NULL) return 1; // LCOV_EXCL_LINE
- cx_tree_zero_pointers(node, cx_tree_node_layout(tree));
- tree->root = node;
- tree->collection.size = 1;
- return 0;
- }
- int result = cx_tree_add(data, tree->search, tree->node_create,
- tree, &node, tree->root, cx_tree_node_layout(tree));
- if (0 == result) {
- tree->collection.size++;
- } else {
- cxFree(tree->collection.allocator, node);
- }
- return result;
+ return depth;
}
-static size_t cx_tree_default_insert_many(
- CxTree *tree,
- CxIteratorBase *iter,
- size_t n
-) {
- size_t ins = 0;
- if (!iter->valid(iter)) return 0;
- if (tree->root == NULL) {
- // use the first element from the iter to create the root node
- void **eptr = iter->current(iter);
- void *node = tree->node_create(*eptr, tree);
- if (node == NULL) return 0; // LCOV_EXCL_LINE
- cx_tree_zero_pointers(node, cx_tree_node_layout(tree));
- tree->root = node;
- ins = 1;
- iter->next(iter);
- }
- void *failed;
- ins += cx_tree_add_iter(iter, n, tree->search, tree->node_create,
- tree, &failed, tree->root, cx_tree_node_layout(tree));
- tree->collection.size += ins;
- if (ins < n) {
- cxFree(tree->collection.allocator, failed);
- }
- return ins;
-}
-
-static void *cx_tree_default_find(
- CxTree *tree,
- const void *subtree,
- const void *data,
- size_t depth
-) {
- if (tree->root == NULL) return NULL; // LCOV_EXCL_LINE
-
- void *found;
- if (0 == cx_tree_search_data(
- subtree,
- depth,
- data,
- tree->search_data,
- &found,
- tree->loc_children,
- tree->loc_next
- )) {
- return found;
- } else {
- return NULL;
- }
-}
-
-static cx_tree_class cx_tree_default_class = {
- cx_tree_default_insert_element,
- cx_tree_default_insert_many,
- cx_tree_default_find
-};
-
CxTree *cxTreeCreate(const CxAllocator *allocator,
- cx_tree_node_create_func create_func,
- cx_tree_search_func search_func,
- cx_tree_search_data_func search_data_func,
+ size_t node_size, size_t elem_size, void *root, ptrdiff_t loc_data,
ptrdiff_t loc_parent, ptrdiff_t loc_children, ptrdiff_t loc_last_child,
- ptrdiff_t loc_prev, ptrdiff_t loc_next
-) {
+ ptrdiff_t loc_prev, ptrdiff_t loc_next) {
+
if (allocator == NULL) {
allocator = cxDefaultAllocator;
}
- assert(create_func != NULL);
- assert(search_func != NULL);
- assert(search_data_func != NULL);
CxTree *tree = cxZalloc(allocator, sizeof(CxTree));
if (tree == NULL) return NULL; // LCOV_EXCL_LINE
-
- tree->cl = &cx_tree_default_class;
tree->collection.allocator = allocator;
- tree->node_create = create_func;
- tree->search = search_func;
- tree->search_data = search_data_func;
- tree->collection.advanced_destructor = (cx_destructor_func2) cxFree;
- tree->collection.destructor_data = (void *) allocator;
+
+ if (elem_size == CX_STORE_POINTERS) {
+ tree->collection.store_pointer = true;
+ tree->collection.elem_size = sizeof(void*);
+ } else {
+ tree->collection.elem_size = elem_size;
+ }
+
+ tree->root = root;
+ tree->node_size = node_size;
tree->loc_parent = loc_parent;
tree->loc_children = loc_children;
tree->loc_last_child = loc_last_child;
tree->loc_prev = loc_prev;
tree->loc_next = loc_next;
+ tree->loc_data = loc_data;
+
+ if (root == NULL) {
+ cxSetAdvancedDestructor(tree, cxFree, (void*)allocator);
+ } else {
+ tree->collection.size = cx_tree_size(root, loc_children, loc_next);
+ }
return tree;
}
cxFree(tree->collection.allocator, tree);
}
-CxTree *cxTreeCreateWrapped(const CxAllocator *allocator, void *root,
- ptrdiff_t loc_parent, ptrdiff_t loc_children, ptrdiff_t loc_last_child,
- ptrdiff_t loc_prev, ptrdiff_t loc_next) {
- if (allocator == NULL) {
- allocator = cxDefaultAllocator;
- }
- assert(root != NULL);
-
- CxTree *tree = cxZalloc(allocator, sizeof(CxTree));
- if (tree == NULL) return NULL; // LCOV_EXCL_LINE
-
- tree->cl = &cx_tree_default_class;
- // set the allocator anyway, just in case...
- tree->collection.allocator = allocator;
- tree->loc_parent = loc_parent;
- tree->loc_children = loc_children;
- tree->loc_last_child = loc_last_child;
- tree->loc_prev = loc_prev;
- tree->loc_next = loc_next;
- tree->root = root;
- tree->collection.size = cxTreeSubtreeSize(tree, root);
- return tree;
-}
-
void cxTreeSetParent(CxTree *tree, void *parent, void *child) {
size_t loc_parent = tree->loc_parent;
if (tree_parent(child) == NULL) {
tree->collection.size++;
}
- cx_tree_link(parent, child, cx_tree_node_layout(tree));
+ cx_tree_add(parent, child, tree_layout(tree));
}
-void cxTreeAddChildNode(CxTree *tree, void *parent, void *child) {
- cx_tree_link(parent, child, cx_tree_node_layout(tree));
+void cxTreeAddNode(CxTree *tree, void *parent, void *child) {
+ cx_tree_add(parent, child, tree_layout(tree));
tree->collection.size++;
}
-int cxTreeAddChild(CxTree *tree, void *parent, const void *data) {
- void *node = tree->node_create(data, tree);
- if (node == NULL) return 1; // LCOV_EXCL_LINE
- cx_tree_zero_pointers(node, cx_tree_node_layout(tree));
- cx_tree_link(parent, node, cx_tree_node_layout(tree));
+void *cxTreeCreateNode(CxTree *tree, void *parent) {
+ void *node = cxZalloc(tree->collection.allocator, tree->node_size);
+ if (node == NULL) return NULL; // LCOV_EXCL_LINE
+ cx_tree_add(parent, node, tree_layout(tree));
tree->collection.size++;
- return 0;
+ return node;
}
-int cxTreeInsert(CxTree *tree, const void *data) {
- return tree->cl->insert_element(tree, data);
+void *cxTreeAddData(CxTree *tree, void *parent, const void *data) {
+ if (tree->loc_data < 0) return NULL;
+
+ void *node = cxTreeCreateNode(tree, parent);
+ if (node == NULL) return NULL; // LCOV_EXCL_LINE
+
+ char *dst = node;
+ dst += tree->loc_data;
+ const void *src = cxCollectionStoresPointers(tree) ? (const void*)&data : data;
+ memcpy(dst, src, tree->collection.elem_size);
+
+ return node;
}
-size_t cxTreeInsertIter(CxTree *tree, CxIteratorBase *iter, size_t n) {
- return tree->cl->insert_many(tree, iter, n);
+void *cxTreeCreateRoot(CxTree *tree) {
+ if (tree->root != NULL) {
+ return tree->root;
+ }
+
+ void *node = cxZalloc(tree->collection.allocator, tree->node_size);
+ if (node == NULL) return NULL; // LCOV_EXCL_LINE
+ tree->root = node;
+ tree->collection.size = 1;
+ return node;
}
-size_t cxTreeInsertArray(CxTree *tree, const void *data, size_t elem_size, size_t n) {
- if (n == 0) return 0;
- if (n == 1) return 0 == cxTreeInsert(tree, data) ? 1 : 0;
- CxIterator iter = cxIterator(data, elem_size, n);
- return cxTreeInsertIter(tree, cxIteratorRef(iter), n);
+void *cxTreeCreateRootData(CxTree *tree, const void *data) {
+ if (tree->loc_data < 0) return NULL;
+
+ void *node = cxTreeCreateRoot(tree);
+ if (node == NULL) return NULL; // LCOV_EXCL_LINE
+
+ char *dst = node;
+ dst += tree->loc_data;
+ const void *src = cxCollectionStoresPointers(tree) ? (const void*)&data : data;
+ memcpy(dst, src, tree->collection.elem_size);
+
+ return node;
}
-void *cxTreeFind( CxTree *tree, const void *data) {
- return tree->cl->find(tree, tree->root, data, 0);
+void *cxTreeSetRoot(CxTree *tree, void *new_root) {
+ void *old_root = tree->root;
+ tree->root = new_root;
+ return old_root;
}
-void *cxTreeFindInSubtree(CxTree *tree, const void *data, void *subtree_root, size_t max_depth) {
- return tree->cl->find(tree, subtree_root, data, max_depth);
+void *cxTreeFindInSubtree(CxTree *tree, const void *data,
+ void *subtree_root, size_t max_depth, bool use_dfs) {
+ if (tree->loc_data < 0 || subtree_root == NULL) {
+ return NULL;
+ }
+
+ CxTreeIterator iter = use_dfs
+ ? cx_tree_iterator(subtree_root, false, tree->loc_children, tree->loc_next)
+ : cx_tree_visitor(subtree_root, tree->loc_children, tree->loc_next);
+
+ cx_foreach(char*, node, iter) {
+ char *node_data = node + tree->loc_data;
+ if (cxCollectionStoresPointers(tree)) {
+ node_data = *(void**)node_data;
+ }
+ if (cx_invoke_compare_func(tree, node_data, data) == 0) {
+ cxTreeIteratorDispose(&iter);
+ return node;
+ }
+ if (iter.depth == max_depth) {
+ cxTreeIteratorContinue(iter);
+ }
+ }
+ return NULL;
+}
+
+void *cxTreeFindFastInSubtree(CxTree *tree, const void *data,
+ cx_tree_search_func sfunc, void *root, size_t max_depth) {
+ void *result;
+ int ret = cx_tree_search(root, max_depth, data, sfunc, &result,
+ tree->loc_children, tree->loc_next);
+ if (ret == 0) {
+ return result;
+ } else {
+ return NULL;
+ }
}
size_t cxTreeSubtreeSize(CxTree *tree, void *subtree_root) {
- CxTreeVisitor visitor = cx_tree_visitor(
- subtree_root,
- tree->loc_children,
- tree->loc_next
- );
- while (cxIteratorValid(visitor)) {
- cxIteratorNext(visitor);
+ if (subtree_root == tree->root) {
+ return tree->collection.size;
}
- return visitor.counter;
+ return cx_tree_size(subtree_root, tree->loc_children, tree->loc_next);
}
size_t cxTreeSubtreeDepth(CxTree *tree, void *subtree_root) {
- CxTreeVisitor visitor = cx_tree_visitor(
- subtree_root,
- tree->loc_children,
- tree->loc_next
- );
- while (cxIteratorValid(visitor)) {
- cxIteratorNext(visitor);
- }
- return visitor.depth;
+ return cx_tree_depth(subtree_root, tree->loc_children, tree->loc_next);
}
size_t cxTreeSize(CxTree *tree) {
}
size_t cxTreeDepth(CxTree *tree) {
- CxTreeVisitor visitor = cx_tree_visitor(
- tree->root, tree->loc_children, tree->loc_next
- );
- while (cxIteratorValid(visitor)) {
- cxIteratorNext(visitor);
- }
- return visitor.depth;
+ return cx_tree_depth(tree->root, tree->loc_children, tree->loc_next);
}
int cxTreeRemoveNode(
void *new_parent = tree_parent(node);
// first, unlink from the parent
- cx_tree_unlink(node, cx_tree_node_layout(tree));
+ cx_tree_remove(node, tree_layout(tree));
// then relink each child
ptrdiff_t loc_children = tree->loc_children;
}
// link to new parent
- cx_tree_link(new_parent, child, cx_tree_node_layout(tree));
+ cx_tree_add(new_parent, child, tree_layout(tree));
// proceed to next child
child = tree_next(child);
return;
}
size_t subtree_size = cxTreeSubtreeSize(tree, node);
- cx_tree_unlink(node, cx_tree_node_layout(tree));
+ cx_tree_remove(node, tree_layout(tree));
tree->collection.size -= subtree_size;
}
) {
int result = cxTreeRemoveNode(tree, node, relink_func);
if (result == 0) {
- cx_invoke_destructor(tree, node);
+ cx_invoke_destructor_raw(tree, node);
return 0;
} else {
return result;
}
void cxTreeDestroySubtree(CxTree *tree, void *node) {
- cx_tree_unlink(node, cx_tree_node_layout(tree));
+ cx_tree_remove(node, tree_layout(tree));
CxTreeIterator iter = cx_tree_iterator(
node, true,
tree->loc_children, tree->loc_next
);
cx_foreach(void *, child, iter) {
if (iter.exiting) {
- cx_invoke_destructor(tree, child);
+ // always call the destructors with the node!
+ cx_invoke_destructor_raw(tree, child);
}
}
tree->collection.size -= iter.counter;
}
void cxTreeIteratorDispose(CxTreeIterator *iter) {
- cxFreeDefault(iter->stack);
- iter->stack = NULL;
-}
-
-void cxTreeVisitorDispose(CxTreeVisitor *visitor) {
- struct cx_tree_visitor_queue_s *q = visitor->queue_next;
- while (q != NULL) {
- struct cx_tree_visitor_queue_s *next = q->next;
- cxFreeDefault(q);
- q = next;
+ if (iter->use_dfs) {
+ cxFreeDefault(iter->stack);
+ iter->stack = NULL;
+ } else {
+ struct cx_tree_visitor_queue_s *q = iter->queue_next;
+ while (q != NULL) {
+ struct cx_tree_visitor_queue_s *next = q->next;
+ cxFreeDefault(q);
+ q = next;
+ }
+ iter->queue_next = iter->queue_last = NULL;
}
- visitor->queue_next = visitor->queue_last = NULL;
}
CxTreeIterator cxTreeIterateSubtree(CxTree *tree, void *node, bool visit_on_exit) {
);
}
-CxTreeVisitor cxTreeVisitSubtree(CxTree *tree, void *node) {
+CxTreeIterator cxTreeVisitSubtree(CxTree *tree, void *node) {
return cx_tree_visitor(
node, tree->loc_children, tree->loc_next
);
return cxTreeIterateSubtree(tree, tree->root, visit_on_exit);
}
-CxTreeVisitor cxTreeVisit(CxTree *tree) {
+CxTreeIterator cxTreeVisit(CxTree *tree) {
return cxTreeVisitSubtree(tree, tree->root);
}
self = [super init];
_columnspacing = 0;
_rowspacing = 0;
- _children = cxArrayListCreateSimple(sizeof(GridElm), 32);
+ _children = cxArrayListCreate(NULL, sizeof(GridElm), 32);
_preferredSize.width = -1;
_preferredSize.height = -1;
max = INT_MAX;
}
- CxList *sublists = cxArrayListCreate(a, NULL, sizeof(UiSubList), args->numsublists);
+ CxList *sublists = cxArrayListCreate(a, sizeof(UiSubList), args->numsublists);
sublists->collection.advanced_destructor = (cx_destructor_func2)sublist_free;
for(int i=0;i<max;i++) {
v->observers = ui_add_observer(v->observers, f, data);
break;
}
+ case UI_VAR_GENERIC: break;
+ case UI_VAR_SPECIAL: break;
}
}
+void ui_int_add_observer(UiInteger *i, ui_callback f, void *data) {
+ i->observers = ui_add_observer(i->observers, f, data);
+}
+
+void ui_double_add_observer(UiDouble *d, ui_callback f, void *data) {
+ d->observers = ui_add_observer(d->observers, f, data);
+}
+
+void ui_range_add_observer(UiRange *r, ui_callback f, void *data) {
+ r->observers = ui_add_observer(r->observers, f, data);
+}
+
+void ui_string_add_observer(UiString *s, ui_callback f, void *data) {
+ s->observers = ui_add_observer(s->observers, f, data);
+}
+
+void ui_text_add_observer(UiText *t, ui_callback f, void *data) {
+ t->observers = ui_add_observer(t->observers, f, data);
+}
+
+void ui_list_add_observer(UiList *l, ui_callback f, void *data) {
+ l->observers = ui_add_observer(l->observers, f, data);
+}
+
UiInteger* ui_get_int_var(UiContext *ctx, const char *name) {
UiVar *var = uic_get_var_t(ctx, name, UI_VAR_INTEGER);
return var ? var->value : NULL;
#elif UI_GTK2 || UI_GTK3
GtkAccelGroup *accel_group;
#endif
+#endif
+#ifdef UI_WIN32
+ CxMap *command_map; // key: int, value: UiCommand
+ uint64_t command_id_counter;
#endif
// allow only one document to be attached
}
UiObject* uic_object_new_toplevel(void) {
- fflush(stdout);
CxMempool *mp = cxMempoolCreateSimple(256);
UiObject *obj = cxCalloc(mp->allocator, 1, sizeof(UiObjectPrivate));
- fflush(stdout);
obj->ctx = uic_context(obj, mp);
obj->ctx->parent = ui_global_context();
- fflush(stdout);
uic_object_created(obj);
- fflush(stdout);
return obj;
}
#define RADIOBUTTON_GET_ACTIVE(button) gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button))
#endif
-static void radiobutton_toggled(void *widget, UiVarEventData *event) {
- gboolean active = RADIOBUTTON_GET_ACTIVE(widget);
-
+static void radiobutton_toggled(void *widget, UiEventData *event) {
UiEvent e;
e.obj = event->obj;
e.window = event->obj->window;
e.document = event->obj->ctx->document;
e.eventdata = NULL;
e.eventdatatype = 0;
- e.intval = active;
+ e.intval = RADIOBUTTON_GET_ACTIVE(widget);
e.set = ui_get_setop();
-
- if(event->callback) {
- event->callback(&e, event->userdata);
- }
-
- if(active && event->var) {
- UiInteger *i = event->var->value;
-
- e.intval = i->get(i);
- ui_notify_evt(i->observers, &e);
- }
+ event->callback(&e, event->userdata);
}
typedef struct UiRadioButtonData {
- UiObject *obj;
- UiVar *var;
+ UiInteger *value;
+ UiVarEventData *eventdata;
UiBool first;
} UiRadioButtonData;
static void destroy_radiobutton(GtkWidget *w, UiRadioButtonData *data) {
if(data->first) {
- UiInteger *value = data->var->value;
- ui_destroy_boundvar(data->obj->ctx, data->var);
- g_slist_free(value->obj);
+ ui_destroy_vardata(w, data->eventdata);
+ g_slist_free(data->value->obj);
+ data->value->obj = NULL;
+ data->value->get = NULL;
+ data->value->set = NULL;
+ } else {
+ free(data->eventdata);
}
free(data);
}
GtkWidget *rbutton = RADIOBUTTON_NEW(rg, args->label);
ui_set_name_and_style(rbutton, args->name, args->style_class);
ui_set_widget_states(obj->ctx, rbutton, args->states);
-
- UiVarEventData *event = malloc(sizeof(UiVarEventData));
- event->obj = obj;
- event->var = var;
- event->observers = NULL;
- event->callback = args->onchange;
- event->userdata = args->onchangedata;
- event->customint1 = 0;
- event->customint2 = 0;
-
if(rgroup) {
#if GTK_MAJOR_VERSION >= 4
if(rg) {
ui_radiobutton_set(rgroup, rgroup->value);
+ UiVarEventData *event = malloc(sizeof(UiVarEventData));
+ event->obj = obj;
+ event->var = var;
+ event->observers = NULL;
+ event->callback = NULL;
+ event->userdata = NULL;
+ event->customint1 = 0;
+ event->customint2 = 0;
+
UiRadioButtonData *rbdata = malloc(sizeof(UiRadioButtonData));
- rbdata->obj = obj;
- rbdata->var = var;
+ rbdata->value = rgroup;
+ rbdata->eventdata = event;
rbdata->first = first;
+ g_signal_connect(
+ rbutton,
+ "toggled",
+ G_CALLBACK(ui_radio_obs),
+ event);
g_signal_connect(
rbutton,
"destroy",
G_CALLBACK(destroy_radiobutton),
rbdata);
}
+
+ if(args->onchange) {
+ UiEventData *event = malloc(sizeof(UiEventData));
+ event->obj = obj;
+ event->userdata = args->onchangedata;
+ event->callback = args->onchange;
+ event->value = 0;
+ event->customdata = NULL;
+ event->customint = 0;
- g_signal_connect(
- rbutton,
- "toggled",
- G_CALLBACK(radiobutton_toggled),
- event);
- g_signal_connect(
- rbutton,
- "destroy",
- G_CALLBACK(ui_destroy_userdata),
- event);
+ g_signal_connect(
+ rbutton,
+ "toggled",
+ G_CALLBACK(radiobutton_toggled),
+ event);
+ g_signal_connect(
+ rbutton,
+ "destroy",
+ G_CALLBACK(ui_destroy_userdata),
+ event);
+ }
UiContainerPrivate *ct = (UiContainerPrivate*)obj->container_end;
UiLayout layout = UI_ARGS2LAYOUT(args);
return rbutton;
}
+void ui_radio_obs(GtkToggleButton *widget, UiVarEventData *event) {
+ UiInteger *i = event->var->value;
+
+ UiEvent e;
+ e.obj = event->obj;
+ e.window = event->obj->window;
+ e.document = event->obj->ctx->document;
+ e.eventdata = NULL;
+ e.eventdatatype = 0;
+ e.intval = i->get(i);
+
+ ui_notify_evt(i->observers, &e);
+}
+
#if GTK_MAJOR_VERSION >= 4
int64_t ui_radiobutton_get(UiInteger *value) {
int selection = 0;
void *data = listview->getvalue(list, elm, row, c, listview->getvaluedata, &freevalue);
UiModelType type = model->types[i];
-
+ UiTextStyle cstyle = { 0, 0 };
if(getstyle) {
// in case the column is icon+text, only get a style for the text column
int style_col = c;
// Get the individual column style
// The column style overrides the row style, however if no column style
// is provided, we stick with the row style
- if(getstyle(list, elm, row, style_col, listview->getstyledata, &style)) {
+ if(getstyle(list, elm, row, style_col, listview->getstyledata, &cstyle)) {
style_set = TRUE;
+ cstyle.text_style |= style.text_style;
+ if(!cstyle.fg_set) {
+ cstyle.fg_set = style.fg_set;
+ cstyle.fg = style.fg;
+ }
+ } else {
+ cstyle = style;
}
}
GValue style_weight_value = G_VALUE_INIT;
g_value_init(&style_weight_value, G_TYPE_INT);
- if(style.text_style & UI_TEXT_STYLE_BOLD) {
+ if(cstyle.text_style & UI_TEXT_STYLE_BOLD) {
g_value_set_int(&style_weight_value, 600);
} else {
g_value_set_int(&style_weight_value, 400);
GValue style_underline_value = G_VALUE_INIT;
g_value_init(&style_underline_value, G_TYPE_INT);
- if(style.text_style & UI_TEXT_STYLE_UNDERLINE) {
+ if(cstyle.text_style & UI_TEXT_STYLE_UNDERLINE) {
g_value_set_int(&style_underline_value, PANGO_UNDERLINE_SINGLE);
} else {
g_value_set_int(&style_underline_value, PANGO_UNDERLINE_NONE);
GValue style_italic_value = G_VALUE_INIT;
g_value_init(&style_italic_value, G_TYPE_INT);
- if(style.text_style & UI_TEXT_STYLE_ITALIC) {
+ if(cstyle.text_style & UI_TEXT_STYLE_ITALIC) {
g_value_set_int(&style_italic_value, PANGO_STYLE_ITALIC);
} else {
g_value_set_int(&style_italic_value, PANGO_STYLE_NORMAL);
GValue style_fgset_value = G_VALUE_INIT;
g_value_init(&style_fgset_value, G_TYPE_BOOLEAN);
- g_value_set_boolean(&style_fgset_value, style.fg_set);
+ g_value_set_boolean(&style_fgset_value, cstyle.fg_set);
gtk_list_store_set_value(store, iter, soff + 4, &style_fgset_value);
- if(style.fg_set) {
+ if(cstyle.fg_set) {
char buf[8];
- snprintf(buf, 8, "#%02X%02X%02X", (int)style.fg.red, (int)style.fg.green, (int)style.fg.blue);
+ snprintf(buf, 8, "#%02X%02X%02X", (int)cstyle.fg.red, (int)cstyle.fg.green, (int)cstyle.fg.blue);
GValue style_fg_value = G_VALUE_INIT;
g_value_init(&style_fg_value, G_TYPE_STRING);
gtk_combo_box_set_active(GTK_COMBO_BOX(dropdown), index);
}
+static void table_cell_toggled(
+ GtkCellRendererToggle *renderer,
+ gchar *path,
+ gpointer user_data)
+{
+ printf("cell toggled\n");
+}
+
+static void table_cell_edited(
+ GtkCellRendererText *renderer,
+ gchar *path,
+ gchar *new_text,
+ gpointer user_data)
+{
+ printf("cell edited\n");
+}
+
UIWIDGET ui_table_create(UiObject *obj, UiListArgs *args) {
// create treeview
GtkWidget *view = gtk_tree_view_new();
"pixbuf",
i + addi,
NULL);
+ } else if (model->types[i] == UI_BOOL_EDITABLE) {
+ GtkCellRenderer *renderer = gtk_cell_renderer_toggle_new();
+ column = gtk_tree_view_column_new_with_attributes(
+ model->titles[i],
+ renderer,
+ "active",
+ i + addi,
+ NULL);
+ g_signal_connect(renderer, "toggled", G_CALLBACK(table_cell_toggled), NULL);
} else {
GtkCellRenderer *textrenderer = gtk_cell_renderer_text_new();
+ if(model->types[i] == UI_STRING_EDITABLE) {
+ g_object_set(textrenderer, "editable", TRUE, NULL);
+ }
column = gtk_tree_view_column_new_with_attributes(
model->titles[i],
textrenderer,
UIMENU menu = data->customdata3;
g_object_set_data(G_OBJECT(button), "ui-button-popup", menu);
+#if GTK_CHECK_VERSION(4, 0, 0)
gtk_popover_popup(GTK_POPOVER(menu));
+#else
+ ui_contextmenu_popup(menu, button, 0, 0);
+#endif
}
}
event
);
gtk_widget_set_visible(button, FALSE);
+ WIDGET_NO_SHOW_ALL(button);
g_object_set_data(G_OBJECT(row), "ui-listbox-row-button", button);
LISTBOX_ROW_REMOVE_CHILD(row);
listbox_fill_row(listbox, GTK_WIDGET(row), sublist, &item, index);
+ LISTBOX_ROW_SHOW(row);
// cleanup
free(item.label);
#endif
listbox_fill_row(listbox, row, sublist, &item, index);
+ LISTBOX_ROW_SHOW(row);
if(index == first_index) {
// first row in the sublist, set ui_listbox data to the row
// which is then used by the headerfunc
GtkWidget *widget = gtk_check_menu_item_new_with_mnemonic(ci->label);
gtk_menu_shell_append(GTK_MENU_SHELL(p), widget);
- if(ci->callback) {
- UiEventData *event = malloc(sizeof(UiEventData));
- event->obj = obj;
- event->userdata = ci->userdata;
- event->callback = ci->callback;
- event->value = 0;
- event->customdata = NULL;
-
- g_signal_connect(
- widget,
- "toggled",
- G_CALLBACK(ui_menu_event_toggled),
- event);
- g_signal_connect(
- widget,
- "destroy",
- G_CALLBACK(ui_destroy_userdata),
- event);
+ UiVarEventData *event = malloc(sizeof(UiVarEventData));
+ memset(event, 0, sizeof(UiVarEventData));
+ event->obj = obj;
+ event->userdata = ci->userdata;
+ event->callback = ci->callback;
+ event->var = uic_widget_var(obj->ctx, obj->ctx, NULL, ci->varname, UI_VAR_INTEGER);
+ if(event->var) {
+ UiInteger *v = event->var->value;
+ v->obj = widget;
+ v->get = ui_checkitem_get;
+ v->set = ui_checkitem_set;
+ if(v->value != 0) {
+ gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(widget), TRUE);
+ }
+ }
+
+ g_signal_connect(
+ widget,
+ "toggled",
+ G_CALLBACK(ui_menu_event_toggled),
+ event);
+ g_signal_connect(
+ widget,
+ "destroy",
+ G_CALLBACK(ui_destroy_userdata),
+ event);
+}
+
+static void ui_menu_event_radio_item_toggled(GtkRadioMenuItem *ri, UiVarEventData *event) {
+ UiInteger *i = event->var->value;
+
+ UiEvent evt;
+ evt.obj = event->obj;
+ evt.window = event->obj->window;
+ evt.document = event->obj->ctx->document;
+ evt.eventdata = i;
+ evt.eventdatatype = i ? UI_EVENT_DATA_INTEGER_VALUE : 0;
+ evt.intval = gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(ri));
+
+ if(event->callback) {
+ event->callback(&evt, event->userdata);
+ }
+
+ if(evt.intval) {
+ evt.intval = ui_get(i);
+ ui_notify_evt(i->observers, &evt);
}
}
+static void ui_destroy_menu_radio_item(GtkWidget *unused, UiVarEventData *event) {
+ if(event->customint1) {
+ uic_unbind_var(event->var);
+ }
+ free(event);
+}
+
void add_radioitem_widget(GtkWidget *p, int index, UiMenuItemI *item, UiObject *obj) {
- // TODO
+ UiMenuRadioItem *ri = (UiMenuRadioItem*)item;
+
+ UiVar *var = uic_widget_var(obj->ctx, obj->ctx, NULL, ri->varname, UI_VAR_INTEGER);
+ if(!var) {
+ fprintf(stderr, "Error: menu radioitem varname is null\n");
+ return;
+ }
+ int first = 0;
+ UiInteger *i = var->value;
+ GSList *group = i->obj;
+ GtkWidget *widget = gtk_radio_menu_item_new_with_label(group, ri->label);
+ gtk_menu_shell_append(GTK_MENU_SHELL(p), widget);
+ if(!group) {
+ i->get = ui_radioitem_get;
+ i->set = ui_radioitem_set;
+ first = 1;
+ }
+ i->obj = gtk_radio_menu_item_get_group(GTK_RADIO_MENU_ITEM(widget));
+
+ UiVarEventData *event = malloc(sizeof(UiVarEventData));
+ memset(event, 0, sizeof(UiVarEventData));
+ event->obj = obj;
+ event->var = var;
+ event->callback = ri->callback;
+ event->userdata = ri->userdata;
+ event->customint1 = first;
+
+ g_signal_connect(
+ widget,
+ "toggled",
+ G_CALLBACK(ui_menu_event_radio_item_toggled),
+ event);
+ g_signal_connect(
+ widget,
+ "destroy",
+ G_CALLBACK(ui_destroy_menu_radio_item),
+ event);
}
static void menuitem_list_remove_binding(void *obj) {
uic_set_tmp_eventdata(NULL, 0);
}
-void ui_menu_event_toggled(GtkCheckMenuItem *ci, UiEventData *event) {
+void ui_menu_event_toggled(GtkCheckMenuItem *ci, UiVarEventData *event) {
+ UiInteger *i = event->var ? event->var->value : NULL;
+
UiEvent evt;
evt.obj = event->obj;
evt.window = event->obj->window;
evt.document = event->obj->ctx->document;
- evt.eventdata = NULL;
+ evt.eventdata = i;
+ evt.eventdatatype = i ? UI_EVENT_DATA_INTEGER_VALUE : 0;
evt.intval = gtk_check_menu_item_get_active(ci);
- event->callback(&evt, event->userdata);
+ if(event->callback) {
+ event->callback(&evt, event->userdata);
+ }
+
+ if(i) {
+ ui_notify_evt(i->observers, &evt);
+ }
}
int64_t ui_checkitem_get(UiInteger *i) {
void ui_checkitem_set(UiInteger *i, int64_t value) {
i->value = value;
- gtk_check_menu_item_set_active(i->obj, value);
+ gtk_check_menu_item_set_active(i->obj, (gboolean)value);
+}
+
+int64_t ui_radioitem_get(UiInteger *value) {
+ int selection = 0;
+ GSList *ls = value->obj;
+ guint len = g_slist_length(ls);
+ int i = 0;
+ while(ls) {
+ if(gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(ls->data))) {
+ selection = len - i;
+ break;
+ }
+ ls = ls->next;
+ i++;
+ }
+
+ value->value = selection;
+ return selection;
+}
+
+void ui_radioitem_set(UiInteger *i, int64_t value) {
+ GSList *ls = i->obj;
+
+ int len = g_slist_length(ls);
+ if(value > len) {
+ value = len;
+ }
+ int s = len - value;
+ int j = 0;
+ int unset = 1;
+ while(ls) {
+ if(j == s) {
+ gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(ls->data), TRUE);
+ unset = 0;
+ break;
+ }
+ ls = ls->next;
+ j++;
+ }
+
+ i->value = value;
}
void ui_menulist_update(UiList *list, int ignored);
void ui_update_menuitem_list(UiActiveMenuItemList *list);
void ui_menu_event_wrapper(GtkMenuItem *item, UiEventData *event);
-void ui_menu_event_toggled(GtkCheckMenuItem *ci, UiEventData *event);
+void ui_menu_event_toggled(GtkCheckMenuItem *ci, UiVarEventData *event);
int64_t ui_checkitem_get(UiInteger *i);
void ui_checkitem_set(UiInteger *i, int64_t value);
+int64_t ui_radioitem_get(UiInteger *i);
+void ui_radioitem_set(UiInteger *i, int64_t value);
#endif /* GTK_MAJOR_VERSION <= 3 */
#if UI_GTK2 || UI_GTK3
-GtkWidget* ui_create_toolbar(UiObject *obj) {
+GtkWidget* ui_create_toolbar(UiObject *obj, UiBool sidebar) {
GtkWidget *toolbar = gtk_toolbar_new();
#ifdef UI_GTK3
gtk_style_context_add_class(
CxList *left_defaults = uic_get_toolbar_defaults(UI_TOOLBAR_LEFT);
CxList *center_defaults = uic_get_toolbar_defaults(UI_TOOLBAR_CENTER);
CxList *right_defaults = uic_get_toolbar_defaults(UI_TOOLBAR_RIGHT);
+ CxList *sidebar_left = uic_get_toolbar_defaults(UI_TOOLBAR_SIDEBAR_LEFT);
+ CxList *sidebar_right = uic_get_toolbar_defaults(UI_TOOLBAR_SIDEBAR_RIGHT);
+ CxList *rightpanel_left = uic_get_toolbar_defaults(UI_TOOLBAR_RIGHTPANEL_LEFT);
+ CxList *rightpanel_center = uic_get_toolbar_defaults(UI_TOOLBAR_RIGHTPANEL_CENTER);
+ CxList *rightpanel_right = uic_get_toolbar_defaults(UI_TOOLBAR_RIGHTPANEL_RIGHT);
+
+ if(sidebar) {
+ ui_toolbar_add_items(obj, toolbar, items, sidebar_left);
+ ui_toolbar_add_items(obj, toolbar, items, sidebar_right);
+ }
ui_toolbar_add_items(obj, toolbar, items, left_defaults);
ui_toolbar_add_items(obj, toolbar, items, center_defaults);
ui_toolbar_add_items(obj, toolbar, items, right_defaults);
- /*
- GtkToolbar *tb = GTK_TOOLBAR(toolbar);
- CxIterator i = cxListIterator(defaults);
- cx_foreach(char *, def, i) {
- UiToolItemI *item = cxMapGet(toolbar_items, def);
- if(item) {
- item->add_to(tb, item, obj);
- } else if(!strcmp(def, "@separator")) {
- gtk_toolbar_insert(tb, gtk_separator_tool_item_new(), -1);
- } else {
- fprintf(stderr, "UI Error: Unknown toolbar item: %s\n", def);
- }
- }
- */
+ ui_toolbar_add_items(obj, toolbar, items, rightpanel_left);
+ ui_toolbar_add_items(obj, toolbar, items, rightpanel_center);
+ ui_toolbar_add_items(obj, toolbar, items, rightpanel_right);
return toolbar;
}
void *userdata,
va_list ap);
-GtkWidget* ui_create_toolbar(UiObject *obj);
+GtkWidget* ui_create_toolbar(UiObject *obj, UiBool sidebar);
void ui_toolbar_add_items(UiObject *obj, GtkWidget *toolbar, CxMap *items, CxList *defaults);
gtk_widget_set_visible(widget, visible);
#else
if(visible) {
+ gtk_widget_set_no_show_all(widget, FALSE);
gtk_widget_show_all(widget);
} else {
- gtk_widget_set_no_show_all(widget, FALSE);
+ gtk_widget_set_no_show_all(widget, TRUE);
gtk_widget_hide(widget);
}
#endif
free(userdata);
}
-void ui_destroy_vardata(GtkWidget *object, UiVarEventData *data) {
+void ui_destroy_vardata(GtkWidget *unused, UiVarEventData *data) {
if(data->var) {
ui_destroy_boundvar(data->obj->ctx, data->var);
}
#define WINDOW_SHOW(window) gtk_window_present(GTK_WINDOW(window))
#define WINDOW_DESTROY(window) gtk_window_destroy(GTK_WINDOW(window))
#define WINDOW_SET_CONTENT(window, child) gtk_window_set_child(GTK_WINDOW(window), child)
+#define WIDGET_NO_SHOW_ALL(widget)
#define BOX_ADD(box, child) gtk_box_append(GTK_BOX(box), child)
#define BOX_ADD_EXPAND(box, child) gtk_widget_set_hexpand(child, TRUE); gtk_widget_set_vexpand(child, TRUE); gtk_box_append(GTK_BOX(box), child)
#define BOX_ADD_NO_EXPAND(box, child) gtk_box_append(GTK_BOX(box), child)
#define LISTBOX_REMOVE(listbox, row) gtk_list_box_remove(GTK_LIST_BOX(listbox), row)
#define LISTBOX_ROW_SET_CHILD(row, child) gtk_list_box_row_set_child(GTK_LIST_BOX_ROW(row), child)
#define LISTBOX_ROW_REMOVE_CHILD(row) gtk_list_box_row_set_child(GTK_LIST_BOX_ROW(row), NULL)
+#define LISTBOX_ROW_SHOW(row)
#define PANED_SET_CHILD1(paned, child) gtk_paned_set_start_child(GTK_PANED(paned), child)
#define PANED_SET_CHILD2(paned, child) gtk_paned_set_end_child(GTK_PANED(paned), child)
#else
#define WINDOW_SHOW(window) gtk_widget_show_all(window)
#define WINDOW_DESTROY(window) gtk_widget_destroy(window)
#define WINDOW_SET_CONTENT(window, child) gtk_container_add(GTK_CONTAINER(window), child)
+#define WIDGET_NO_SHOW_ALL(widget) gtk_widget_set_no_show_all(widget, TRUE)
#define BOX_ADD(box, child) gtk_container_add(GTK_CONTAINER(box), child)
#define BOX_ADD_EXPAND(box, child) gtk_box_pack_start(GTK_BOX(box), child, TRUE, TRUE, 0)
#define BOX_ADD_NO_EXPAND(box, child) gtk_box_pack_start(GTK_BOX(box), child, TRUE, FALSE, 0)
#define LISTBOX_REMOVE(listbox, row) gtk_container_remove(GTK_CONTAINER(listbox), row)
#define LISTBOX_ROW_SET_CHILD(row, child) gtk_container_add(GTK_CONTAINER(row), child)
#define LISTBOX_ROW_REMOVE_CHILD(row) gtk_container_remove(GTK_CONTAINER(row), gtk_bin_get_child(GTK_BIN(row)))
+#define LISTBOX_ROW_SHOW(row) gtk_widget_show_all(GTK_WIDGET(row))
#define PANED_SET_CHILD1(paned, child) gtk_paned_pack1(GTK_PANED(paned), child, TRUE, TRUE)
#define PANED_SET_CHILD2(paned, child) gtk_paned_pack2(GTK_PANED(paned), child, TRUE, TRUE)
#endif
void ui_set_widget_nvisibility_states(UiContext *ctx, GtkWidget *widget, const int *states, size_t ngroups);
void ui_destroy_userdata(GtkWidget *object, void *userdata);
-void ui_destroy_vardata(GtkWidget *object, UiVarEventData *data);
+void ui_destroy_vardata(GtkWidget *unused, UiVarEventData *data);
void ui_destroy_widget_var(GtkWidget *object, UiVar *var);
void ui_destroy_boundvar(UiContext *ctx, UiVar *var);
// TODO: gtk4 toolbar
#else
if(uic_toolbar_isenabled()) {
- GtkWidget *tb = ui_create_toolbar(obj);
+ GtkWidget *tb = ui_create_toolbar(obj, sidebar);
if(tb) {
BOX_ADD(vbox, tb);
}
cxmutstr url;
if(add_separator) {
- url = cx_strcat(3, base, cx_str("/"), path);
+ url = cx_strcat(CX_NULLSTR, 3, base, cx_str("/"), path);
} else {
- url = cx_strcat(2, base, path);
+ url = cx_strcat(CX_NULLSTR, 2, base, path);
}
return url;
UIEXPORT void ui_var_add_observer(UiContext *ctx, const char *varname, ui_callback f, void *data);
+UIEXPORT void ui_int_add_observer(UiInteger *i, ui_callback f, void *data);
+UIEXPORT void ui_double_add_observer(UiDouble *d, ui_callback f, void *data);
+UIEXPORT void ui_range_add_observer(UiRange *r, ui_callback f, void *data);
+UIEXPORT void ui_string_add_observer(UiString *s, ui_callback f, void *data);
+UIEXPORT void ui_text_add_observer(UiText *t, ui_callback f, void *data);
+UIEXPORT void ui_list_add_observer(UiList *l, ui_callback f, void *data);
+
UIEXPORT UiObserver* ui_observer_new(ui_callback f, void *data);
UIEXPORT UiObserver* ui_obsvlist_add(UiObserver *list, UiObserver *observer);
UIEXPORT UiObserver* ui_add_observer(UiObserver *list, ui_callback f, void *data);