cx_attr_unused CxArrayReallocator *alloc
) {
size_t n;
+ // LCOV_EXCL_START
if (cx_szmul(new_capacity, elem_size, &n)) {
errno = EOVERFLOW;
return NULL;
- }
+ } // LCOV_EXCL_STOP
return cxReallocDefault(array, n);
}
CxArrayReallocator cx_array_default_reallocator_impl = {
- cx_array_default_realloc, NULL, NULL, 0, 0
+ cx_array_default_realloc, NULL, NULL
};
CxArrayReallocator *cx_array_default_reallocator = &cx_array_default_reallocator_impl;
) {
// check for overflow
size_t n;
+ // LCOV_EXCL_START
if (cx_szmul(new_capacity, elem_size, &n)) {
errno = EOVERFLOW;
return NULL;
- }
+ } // LCOV_EXCL_STOP
// retrieve the pointer to the actual allocator
- const CxAllocator *al = alloc->ptr1;
+ const CxAllocator *al = alloc->allocator;
// check if the array is still located on the stack
void *newmem;
- if (array == alloc->ptr2) {
+ if (array == alloc->stack_ptr) {
newmem = cxMalloc(al, n);
if (newmem != NULL && array != NULL) {
memcpy(newmem, array, old_capacity*elem_size);
struct cx_array_reallocator_s cx_array_reallocator(
const struct cx_allocator_s *allocator,
- const void *stackmem
+ const void *stack_ptr
) {
if (allocator == NULL) {
allocator = cxDefaultAllocator;
}
return (struct cx_array_reallocator_s) {
cx_array_advanced_realloc,
- (void*) allocator, (void*) stackmem,
- 0, 0
+ allocator, stack_ptr,
};
}
// LOW LEVEL ARRAY LIST FUNCTIONS
-static size_t cx_array_align_capacity(
- size_t cap,
- size_t alignment,
- size_t max
+/**
+ * Intelligently calculates a new capacity, reserving some more
+ * elements than required to prevent too many allocations.
+ *
+ * @param current_capacity the current capacity of the array
+ * @param needed_capacity the required capacity of the array
+ * @return the new capacity
+ */
+static size_t cx_array_grow_capacity(
+ size_t current_capacity,
+ size_t needed_capacity
) {
- if (cap > max - alignment) {
- return cap;
- } else {
- return cap - (cap % alignment) + alignment;
+ if (current_capacity >= needed_capacity) {
+ return current_capacity;
}
+ size_t cap = needed_capacity;
+ size_t alignment;
+ if (cap < 128) alignment = 16;
+ else if (cap < 1024) alignment = 64;
+ else if (cap < 8192) alignment = 512;
+ else alignment = 1024;
+ return cap - (cap % alignment) + alignment;
}
int cx_array_reserve(
// reallocate if possible
if (newcap > oldcap) {
- // calculate new capacity (next number divisible by 16)
- newcap = cx_array_align_capacity(newcap, 16, max_size);
-
- // perform reallocation
void *newmem = reallocator->realloc(
*array, oldcap, newcap, elem_size, reallocator
);
}
// check if resize is required
- size_t minsize = index + elem_count;
- size_t newsize = oldsize < minsize ? minsize : oldsize;
+ const size_t minsize = index + elem_count;
+ const size_t newsize = oldsize < minsize ? minsize : oldsize;
- // reallocate if possible
- size_t newcap = oldcap;
- if (newsize > oldcap) {
- // check, if we need to repair the src pointer
+ // reallocate if necessary
+ const size_t newcap = cx_array_grow_capacity(oldcap, newsize);
+ if (newcap > oldcap) {
+ // check if we need to repair the src pointer
uintptr_t targetaddr = (uintptr_t) *target;
uintptr_t srcaddr = (uintptr_t) src;
bool repairsrc = targetaddr <= srcaddr
&& srcaddr < targetaddr + oldcap * elem_size;
- // calculate new capacity (next number divisible by 16)
- newcap = cx_array_align_capacity(newsize, 16, max_size);
- assert(newcap > newsize);
-
// perform reallocation
void *newmem = reallocator->realloc(
*target, oldcap, newcap, elem_size, reallocator
if (elem_count == 0) return 0;
// overflow check
+ // LCOV_EXCL_START
if (elem_count > SIZE_MAX - *size) {
errno = EOVERFLOW;
return 1;
}
+ // LCOV_EXCL_STOP
// store some counts
- size_t old_size = *size;
- size_t old_capacity = *capacity;
+ const size_t old_size = *size;
+ const size_t old_capacity = *capacity;
// the necessary capacity is the worst case assumption, including duplicates
- size_t needed_capacity = old_size + elem_count;
+ const size_t needed_capacity = cx_array_grow_capacity(old_capacity, old_size + elem_count);
// if we need more than we have, try a reallocation
if (needed_capacity > old_capacity) {
- size_t new_capacity = cx_array_align_capacity(needed_capacity, 16, SIZE_MAX);
void *new_mem = reallocator->realloc(
- *target, old_capacity, new_capacity, elem_size, reallocator
+ *target, old_capacity, needed_capacity, elem_size, reallocator
);
if (new_mem == NULL) {
// give it up right away, there is no contract
return 1; // LCOV_EXCL_LINE
}
*target = new_mem;
- *capacity = new_capacity;
+ *capacity = needed_capacity;
}
// now we have guaranteed that we can insert everything
// while there are both source and buffered elements left,
// copy them interleaving
while (si < elem_count && bi < new_size) {
- // determine how many source elements can be inserted
+ // determine how many source elements can be inserted.
+ // the first element that shall not be inserted is the smallest element
+ // that is strictly larger than the first buffered element
+ // (located at the index of the infimum plus one).
+ // the infimum is guaranteed to exist:
+ // - if all src elements are larger,
+ // there is no buffer, and this loop is skipped
+ // - if any src element is smaller or equal, the infimum exists
+ // - when all src elements that are smaller are copied, the second part
+ // of this loop body will copy the remaining buffer (emptying it)
+ // Therefore, the buffer can never contain an element that is smaller
+ // than any element in the source and the infimum exists.
size_t copy_len, bytes_copied;
- copy_len = cx_array_binary_search_sup(
- src,
- elem_count - si,
- elem_size,
- bptr,
- cmp_func
+ copy_len = cx_array_binary_search_inf(
+ src, elem_count - si, elem_size, bptr, cmp_func
);
- // binary search gives us the smallest index;
- // we also want to include equal elements here
- while (si + copy_len < elem_count
- && cmp_func(bptr, src+copy_len*elem_size) == 0) {
- copy_len++;
- }
+ copy_len++;
// copy the source elements
if (copy_len > 0) {
// duplicates allowed or nothing inserted yet: simply copy everything
memcpy(dest, src, elem_size * (elem_count - si));
} else {
- if (dest != *target) {
- // skip all source elements that equal the last element
- char *last = dest - elem_size;
- while (si < elem_count) {
- if (last != NULL && cmp_func(last, src) == 0) {
- src += elem_size;
- si++;
- (*size)--;
- } else {
- break;
- }
- }
- }
- // we must check the elements in the chunk one by one
+ // we must check the remaining source elements one by one
+ // to skip the duplicates.
+ // Note that no source element can equal the last element in the
+ // destination, because that would have created an insertion point
+ // and a buffer, s.t. the above loop already handled the duplicates
while (si < elem_count) {
// find a chain of elements that can be copied
size_t copy_len = 1, skip_len = 0;
{
const char *left_src = src;
- while (si + copy_len < elem_count) {
+ while (si + copy_len + skip_len < elem_count) {
const char *right_src = left_src + elem_size;
int d = cmp_func(left_src, right_src);
if (d < 0) {
cmp_func, sorted_data, elem_size, elem_count, reallocator, false);
}
-size_t cx_array_binary_search_inf(
+// implementation that finds ANY index
+static size_t cx_array_binary_search_inf_impl(
const void *arr,
size_t size,
size_t elem_size,
result = cmp_func(elem, arr_elem);
if (result == 0) {
// found it!
- // check previous elements;
- // when they are equal, report the smallest index
- arr_elem -= elem_size;
- while (pivot_index > 0 && cmp_func(elem, arr_elem) == 0) {
- pivot_index--;
- arr_elem -= elem_size;
- }
return pivot_index;
} else if (result < 0) {
// element is smaller than pivot, continue search left
return result < 0 ? (pivot_index - 1) : pivot_index;
}
+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
+) {
+ size_t index = cx_array_binary_search_inf_impl(
+ arr, size, elem_size, elem, cmp_func);
+ // in case of equality, report the largest index
+ const char *e = ((const char *) arr) + (index + 1) * elem_size;
+ while (index + 1 < size && cmp_func(e, elem) == 0) {
+ e += elem_size;
+ index++;
+ }
+ return index;
+}
+
size_t cx_array_binary_search(
const void *arr,
size_t size,
const void *elem,
cx_compare_func cmp_func
) {
- size_t inf = cx_array_binary_search_inf(
+ size_t index = cx_array_binary_search_inf_impl(
arr, size, elem_size, elem, cmp_func
);
- if (inf == size) {
- // no infimum means, first element is supremum
+ const char *e = ((const char *) arr) + index * elem_size;
+ if (index == size) {
+ // no infimum means the first element is supremum
return 0;
- } else if (cmp_func(((const char *) arr) + inf * elem_size, elem) == 0) {
- return inf;
+ } else if (cmp_func(e, elem) == 0) {
+ // found an equal element, search the smallest index
+ e -= elem_size; // e now contains the element at index-1
+ while (index > 0 && cmp_func(e, elem) == 0) {
+ e -= elem_size;
+ index--;
+ }
+ return index;
} else {
- return inf + 1;
+ // we already have the largest index of the infimum (by design)
+ // the next element is the supremum (or there is no supremum)
+ return index + 1;
}
}
// guarantee enough capacity
if (arl->capacity < list->collection.size + n) {
- size_t new_capacity = list->collection.size + n;
- new_capacity = new_capacity - (new_capacity % 16) + 16;
+ const size_t new_capacity = cx_array_grow_capacity(arl->capacity,list->collection.size + n);
if (cxReallocateArray(
list->collection.allocator,
&arl->data, new_capacity,
list->collection.elem_size)
) {
- return 0;
+ return 0; // LCOV_EXCL_LINE
}
arl->capacity = new_capacity;
}
&arl->reallocator
)) {
// array list implementation is "all or nothing"
- return 0;
+ return 0; // LCOV_EXCL_LINE
} else {
return n;
}
&arl->reallocator
)) {
// array list implementation is "all or nothing"
- return 0;
+ return 0; // LCOV_EXCL_LINE
} else {
return n;
}
const void *elem,
int prepend
) {
- struct cx_list_s *list = iter->src_handle.m;
+ struct cx_list_s *list = iter->src_handle;
if (iter->index < list->collection.size) {
if (cx_arl_insert_element(list,
iter->index + 1 - prepend, elem) == NULL) {
- return 1;
+ return 1; // LCOV_EXCL_LINE
}
iter->elem_count++;
if (prepend != 0) {
return 0;
} else {
if (cx_arl_insert_element(list, list->collection.size, elem) == NULL) {
- return 1;
+ return 1; // LCOV_EXCL_LINE
}
iter->elem_count++;
iter->index = list->collection.size;
static bool cx_arl_iter_valid(const void *it) {
const struct cx_iterator_s *iter = it;
- const struct cx_list_s *list = iter->src_handle.c;
+ const struct cx_list_s *list = iter->src_handle;
return iter->index < list->collection.size;
}
struct cx_iterator_s *iter = it;
if (iter->base.remove) {
iter->base.remove = false;
- cx_arl_remove(iter->src_handle.m, iter->index, 1, NULL);
+ cx_arl_remove(iter->src_handle, iter->index, 1, NULL);
iter->elem_count--;
} else {
iter->index++;
iter->elem_handle =
((char *) iter->elem_handle)
- + ((const struct cx_list_s *) iter->src_handle.c)->collection.elem_size;
+ + ((const struct cx_list_s *) iter->src_handle)->collection.elem_size;
}
}
static void cx_arl_iter_prev(void *it) {
struct cx_iterator_s *iter = it;
- const cx_array_list *list = iter->src_handle.c;
if (iter->base.remove) {
iter->base.remove = false;
- cx_arl_remove(iter->src_handle.m, iter->index, 1, NULL);
+ cx_arl_remove(iter->src_handle, iter->index, 1, NULL);
iter->elem_count--;
}
iter->index--;
+ cx_array_list *list = iter->src_handle;
if (iter->index < list->base.collection.size) {
iter->elem_handle = ((char *) list->data)
+ iter->index * list->base.collection.elem_size;
}
}
+static int cx_arl_change_capacity(
+ struct cx_list_s *list,
+ size_t new_capacity
+) {
+ cx_array_list *arl = (cx_array_list *)list;
+ return cxReallocateArray(list->collection.allocator,
+ &arl->data, new_capacity, list->collection.elem_size);
+}
static struct cx_iterator_s cx_arl_iterator(
const struct cx_list_s *list,
struct cx_iterator_s iter;
iter.index = index;
- iter.src_handle.c = list;
+ iter.src_handle = (void*)list;
iter.elem_handle = cx_arl_at(list, index);
iter.elem_size = list->collection.elem_size;
iter.elem_count = list->collection.size;
iter.base.current = cx_arl_iter_current;
iter.base.next = backwards ? cx_arl_iter_prev : cx_arl_iter_next;
iter.base.remove = false;
- iter.base.mutating = false;
+ iter.base.allow_remove = true;
return iter;
}
cx_arl_sort,
cx_arl_compare,
cx_arl_reverse,
+ cx_arl_change_capacity,
cx_arl_iterator,
};
#ifdef _WIN32
#include <Windows.h>
#include <sysinfoapi.h>
-static unsigned long system_page_size() {
+static unsigned long system_page_size(void) {
static unsigned long ps = 0;
if (ps == 0) {
SYSTEM_INFO sysinfo;
}
return ps;
}
-#define SYSTEM_PAGE_SIZE system_page_size()
#else
#include <unistd.h>
-#define SYSTEM_PAGE_SIZE sysconf(_SC_PAGESIZE)
+static unsigned long system_page_size(void) {
+ static unsigned long ps = 0;
+ if (ps == 0) {
+ long sc = sysconf(_SC_PAGESIZE);
+ if (sc < 0) {
+ // fallback for systems which do not report a value here
+ ps = 4096; // LCOV_EXCL_LINE
+ } else {
+ ps = (unsigned long) sc;
+ }
+ }
+ return ps;
+}
#endif
static int buffer_copy_on_write(CxBuffer* buffer) {
if (0 == (buffer->flags & CX_BUFFER_COPY_ON_WRITE)) return 0;
void *newspace = cxMalloc(buffer->allocator, buffer->capacity);
- if (NULL == newspace) return -1;
+ if (NULL == newspace) return -1; // LCOV_EXCL_LINE
memcpy(newspace, buffer->space, buffer->size);
buffer->space = newspace;
buffer->flags &= ~CX_BUFFER_COPY_ON_WRITE;
buffer->flags = flags;
if (!space) {
buffer->bytes = cxMalloc(allocator, capacity);
- if (buffer->bytes == NULL) {
- return -1; // LCOV_EXCL_LINE
- }
+ if (buffer->bytes == NULL) return -1; // LCOV_EXCL_LINE
buffer->flags |= CX_BUFFER_FREE_CONTENTS;
} else {
buffer->bytes = space;
allocator = cxDefaultAllocator;
}
CxBuffer *buf = cxMalloc(allocator, sizeof(CxBuffer));
- if (buf == NULL) return NULL;
+ if (buf == NULL) return NULL; // LCOV_EXCL_LINE
if (0 == cxBufferInit(buf, space, capacity, allocator, flags)) {
return buf;
} else {
}
+size_t cxBufferPop(CxBuffer *buffer, size_t size, size_t nitems) {
+ size_t len;
+ if (cx_szmul(size, nitems, &len)) {
+ // LCOV_EXCL_START
+ errno = EOVERFLOW;
+ return 0;
+ // LCOV_EXCL_STOP
+ }
+ if (len == 0) return 0;
+ if (len > buffer->size) {
+ if (size == 1) {
+ // simple case: everything can be discarded
+ len = buffer->size;
+ } else {
+ // complicated case: misaligned bytes must stay
+ size_t misalignment = buffer->size % size;
+ len = buffer->size - misalignment;
+ }
+ }
+ buffer->size -= len;
+
+ // adjust position, if required
+ if (buffer->pos > buffer->size) {
+ buffer->pos = buffer->size;
+ }
+
+ return len / size;
+}
+
void cxBufferClear(CxBuffer *buffer) {
if (0 == (buffer->flags & CX_BUFFER_COPY_ON_WRITE)) {
memset(buffer->bytes, 0, buffer->size);
return buffer->pos >= buffer->size;
}
-int cxBufferMinimumCapacity(
- CxBuffer *buffer,
- size_t newcap
-) {
+int cxBufferReserve(CxBuffer *buffer, size_t newcap) {
if (newcap <= buffer->capacity) {
return 0;
}
-
- unsigned long pagesize = SYSTEM_PAGE_SIZE;
- // if page size is larger than 64 KB - for some reason - truncate to 64 KB
- if (pagesize > 65536) pagesize = 65536;
- if (newcap < pagesize) {
- // when smaller as one page, map to the next power of two
- newcap--;
- newcap |= newcap >> 1;
- newcap |= newcap >> 2;
- newcap |= newcap >> 4;
- // last operation only needed for pages larger 4096 bytes
- // but if/else would be more expensive than just doing this
- newcap |= newcap >> 8;
- newcap++;
- } else {
- // otherwise, map to a multiple of the page size
- newcap -= newcap % pagesize;
- newcap += pagesize;
- // note: if newcap is already page aligned,
- // this gives a full additional page (which is good)
- }
-
-
const int force_copy_flags = CX_BUFFER_COPY_ON_WRITE | CX_BUFFER_COPY_ON_EXTEND;
if (buffer->flags & force_copy_flags) {
void *newspace = cxMalloc(buffer->allocator, newcap);
}
}
+static size_t cx_buffer_calculate_minimum_capacity(size_t mincap) {
+ unsigned long pagesize = system_page_size();
+ // if page size is larger than 64 KB - for some reason - truncate to 64 KB
+ if (pagesize > 65536) pagesize = 65536;
+ if (mincap < pagesize) {
+ // when smaller as one page, map to the next power of two
+ mincap--;
+ mincap |= mincap >> 1;
+ mincap |= mincap >> 2;
+ mincap |= mincap >> 4;
+ // last operation only needed for pages larger 4096 bytes
+ // but if/else would be more expensive than just doing this
+ mincap |= mincap >> 8;
+ mincap++;
+ } else {
+ // otherwise, map to a multiple of the page size
+ mincap -= mincap % pagesize;
+ mincap += pagesize;
+ // note: if newcap is already page aligned,
+ // this gives a full additional page (which is good)
+ }
+ return mincap;
+}
+
+int cxBufferMinimumCapacity(CxBuffer *buffer, size_t newcap) {
+ if (newcap <= buffer->capacity) {
+ return 0;
+ }
+ newcap = cx_buffer_calculate_minimum_capacity(newcap);
+ return cxBufferReserve(buffer, newcap);
+}
+
void cxBufferShrink(
CxBuffer *buffer,
size_t reserve
bool perform_flush = false;
if (required > buffer->capacity) {
if (buffer->flags & CX_BUFFER_AUTO_EXTEND) {
- if (buffer->flush != NULL && required > buffer->flush->threshold) {
- perform_flush = true;
+ if (buffer->flush != NULL) {
+ size_t newcap = cx_buffer_calculate_minimum_capacity(required);
+ if (newcap > buffer->flush->threshold) {
+ newcap = buffer->flush->threshold;
+ }
+ if (cxBufferReserve(buffer, newcap)) {
+ return total_flushed; // LCOV_EXCL_LINE
+ }
+ if (required > newcap) {
+ perform_flush = true;
+ }
} else {
if (cxBufferMinimumCapacity(buffer, required)) {
return total_flushed; // LCOV_EXCL_LINE
/**
* The allocator's malloc() implementation.
*/
- void *(*malloc)(
- void *data,
- size_t n
- );
+ void *(*malloc)(void *data, size_t n);
/**
* The allocator's realloc() implementation.
*/
- void *(*realloc)(
- void *data,
- void *mem,
- size_t n
- );
+ void *(*realloc)(void *data, void *mem, size_t n);
/**
* The allocator's calloc() implementation.
*/
- void *(*calloc)(
- void *data,
- size_t nmemb,
- size_t size
- );
+ void *(*calloc)(void *data, size_t nmemb, size_t size);
/**
* The allocator's free() implementation.
*/
- void (*free)(
- void *data,
- void *mem
- );
+ void (*free)(void *data, void *mem);
} cx_allocator_class;
/**
/**
* A pre-defined allocator using standard library malloc() etc.
*/
-cx_attr_export
-extern const CxAllocator * const cxStdlibAllocator;
+CX_EXPORT extern const CxAllocator * const cxStdlibAllocator;
/**
* The default allocator that is used by UCX.
* Initialized with cxStdlibAllocator, but you may change it.
*/
-cx_attr_export
-extern const CxAllocator * cxDefaultAllocator;
+CX_EXPORT extern const CxAllocator * cxDefaultAllocator;
/**
* Function pointer type for destructor functions.
* @param data an optional pointer to custom data
* @param memory a pointer to the object to destruct
*/
-typedef void (*cx_destructor_func2)(
- void *data,
- void *memory
-);
+typedef void (*cx_destructor_func2)(void *data, void *memory);
+
+
+/**
+ * Function pointer type for clone functions.
+ *
+ * A clone function is supposed to create a deep copy of the memory pointed to
+ * by the @p source pointer.
+ * If the @p target pointer is non-null, the clone function is supposed to store
+ * the copy into that memory region.
+ * Otherwise, the clone function shall use the specified @p allocator to create
+ * a new object.
+ *
+ * The return value of a clone function is always a pointer to the target
+ * memory region, or @c NULL if any allocation failed.
+ * A clone function SHOULD NOT fail for any other reason than an allocation
+ * failure.
+ *
+ * @param target the target memory or @c NULL, if memory shall be allocated
+ * @param source the source memory
+ * @param allocator the allocator that shall be used
+ * @param data optional additional data
+ * @return either the specified @p target, a pointer to the allocated memory,
+ * or @c NULL, if any error occurred
+ */
+typedef void*(cx_clone_func)(void *target, const void *source,
+ const CxAllocator *allocator, void *data);
/**
* Reallocate a previously allocated block and changes the pointer in-place,
* @retval non-zero failure
* @see cx_reallocatearray()
*/
-cx_attr_nonnull
-cx_attr_nodiscard
-cx_attr_export
-int cx_reallocate_(
- void **mem,
- size_t n
-);
+cx_attr_nonnull cx_attr_nodiscard
+CX_EXPORT int cx_reallocate_(void **mem, size_t n);
/**
* Reallocate a previously allocated block and changes the pointer in-place,
* @retval non-zero failure
* @see cx_reallocate()
*/
-cx_attr_nonnull
-cx_attr_nodiscard
-cx_attr_export
-int cx_reallocatearray_(
- void **mem,
- size_t nmemb,
- size_t size
-);
+cx_attr_nonnull cx_attr_nodiscard
+CX_EXPORT int cx_reallocatearray_(void **mem, size_t nmemb, size_t size);
/**
* Reallocate a previously allocated block and changes the pointer in-place,
* @param mem a pointer to the block to free
*/
cx_attr_nonnull_arg(1)
-cx_attr_export
-void cxFree(
- const CxAllocator *allocator,
- void *mem
-);
+CX_EXPORT 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_attr_export
-void *cxMalloc(
- const CxAllocator *allocator,
- size_t n
-);
+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);
/**
* 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_attr_export
-void *cxRealloc(
- const CxAllocator *allocator,
- void *mem,
- size_t n
-);
+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);
/**
* Reallocate the previously allocated block in @p mem, making the new block
* @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_attr_export
-void *cxReallocArray(
- const CxAllocator *allocator,
- void *mem,
- size_t nmemb,
- size_t size
-);
+cx_attr_nodiscard cx_attr_nonnull_arg(1)
+cx_attr_dealloc_ucx cx_attr_allocsize(3, 4)
+CX_EXPORT void *cxReallocArray(const CxAllocator *allocator,
+ void *mem, size_t nmemb, size_t size);
/**
* Reallocate a previously allocated block and changes the pointer in-place,
* @retval zero success
* @retval non-zero failure
*/
-cx_attr_nodiscard
-cx_attr_nonnull
-cx_attr_export
-int cxReallocate_(
- const CxAllocator *allocator,
- void **mem,
- size_t n
-);
+cx_attr_nodiscard cx_attr_nonnull
+CX_EXPORT 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_attr_export
-int cxReallocateArray_(
- const CxAllocator *allocator,
- void **mem,
- size_t nmemb,
- size_t size
-);
+cx_attr_nodiscard cx_attr_nonnull
+CX_EXPORT int cxReallocateArray_(const CxAllocator *allocator,
+ void **mem, size_t nmemb, size_t size);
/**
* Reallocate a previously allocated block and changes the pointer in-place,
* @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_attr_export
-void *cxCalloc(
- const CxAllocator *allocator,
- size_t nmemb,
- size_t size
-);
+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);
/**
* 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_attr_export
-void *cxZalloc(
- const CxAllocator *allocator,
- size_t n
-);
+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);
/**
* Convenience macro that invokes cxMalloc() with the cxDefaultAllocator.
* The maximum item size in an array list that fits into
* a stack buffer when swapped.
*/
-cx_attr_export
-extern const unsigned cx_array_swap_sbo_size;
+CX_EXPORT extern const unsigned cx_array_swap_sbo_size;
/**
* Declares variables for an array that can be used with the convenience macros.
* Reallocates space for the given array.
*
* Implementations are not required to free the original array.
- * This allows reallocation of static memory by allocating heap memory
- * and copying the array contents. The information in the custom fields of
- * the referenced allocator can be used to track the state of the memory
- * or to transport other additional data.
+ * This allows reallocation of static or stack memory by allocating heap memory
+ * and copying the array contents; namely when @c stack_ptr in this struct
+ * is not @c NULL and @p array equals @c stack_ptr.
*
* @param array the array to reallocate
* @param old_capacity the old number of elements
* @param alloc a reference to this allocator
* @return a pointer to the reallocated memory or @c NULL on failure
*/
- cx_attr_nodiscard
- cx_attr_nonnull_arg(5)
- cx_attr_allocsize(3, 4)
- void *(*realloc)(
- void *array,
- size_t old_capacity,
- size_t new_capacity,
- size_t elem_size,
- struct cx_array_reallocator_s *alloc
- );
+ void *(*realloc)( void *array, size_t old_capacity, size_t new_capacity,
+ size_t elem_size, struct cx_array_reallocator_s *alloc);
/**
- * Custom data pointer.
+ * The allocator that shall be used for the reallocations.
*/
- void *ptr1;
+ const CxAllocator *allocator;
/**
- * Custom data pointer.
+ * Optional pointer to stack memory
+ * if the array is originally located on the stack.
*/
- void *ptr2;
- /**
- * Custom data integer.
- */
- size_t int1;
- /**
- * Custom data integer.
- */
- size_t int2;
+ const void *stack_ptr;
};
/**
/**
* A default array reallocator that is based on the cxDefaultAllocator.
*/
-cx_attr_export
-extern CxArrayReallocator *cx_array_default_reallocator;
+CX_EXPORT extern CxArrayReallocator *cx_array_default_reallocator;
/**
* Creates a new array reallocator.
*
* When @p allocator is @c NULL, the cxDefaultAllocator will be used.
*
- * When @p stackmem is not @c NULL, the reallocator is supposed to be used
- * @em only for the specific array initially located at @p stackmem.
+ * When @p stack_ptr is not @c NULL, the reallocator is supposed to be used
+ * @em only for the specific array initially located at @p stack_ptr.
* When reallocation is needed, the reallocator checks if the array is
- * still located at @p stackmem and copies the contents to the heap.
+ * still located at @p stack_ptr and copies the contents to the heap.
*
* @note Invoking this function with both arguments being @c NULL will return a
* reallocator that behaves like #cx_array_default_reallocator.
*
* @param allocator the allocator this reallocator shall be based on
- * @param stackmem the address of the array when the array is initially located
+ * @param stack_ptr the address of the array when the array is initially located
* on the stack or shall not reallocate in place
* @return an array reallocator
*/
-cx_attr_export
-CxArrayReallocator cx_array_reallocator(
- const struct cx_allocator_s *allocator,
- const void *stackmem
-);
+CX_EXPORT CxArrayReallocator cx_array_reallocator(
+ const struct cx_allocator_s *allocator, const void *stack_ptr);
/**
* Reserves memory for additional elements.
* Supported are 0, 1, 2, and 4, as well as 8 if running on a 64-bit
* architecture. If set to zero, the native word width is used.
*
+ * @note This function will reserve the minimum required capacity to hold
+ * the additional elements and does not perform an overallocation.
+ *
* @param array a pointer to the target array
* @param size a pointer to the size of the array
* @param capacity a pointer to the capacity of the array
* @see cx_array_reallocator()
*/
cx_attr_nonnull_arg(1, 2, 3)
-cx_attr_export
-int cx_array_reserve(
- void **array,
- void *size,
- void *capacity,
- unsigned width,
- size_t elem_size,
- size_t elem_count,
- CxArrayReallocator *reallocator
-);
+CX_EXPORT int cx_array_reserve(void **array, void *size, void *capacity,
+ unsigned width, size_t elem_size, size_t elem_count,
+ CxArrayReallocator *reallocator);
/**
* Copies elements from one array to another.
* Supported are 0, 1, 2, and 4, as well as 8 if running on a 64-bit
* architecture. If set to zero, the native word width is used.
*
+ * @note When this function does reallocate the array, it may allocate more
+ * space than required to avoid further allocations in the near future.
+ *
* @param target a pointer to the target array
* @param size a pointer to the size of the target array
* @param capacity a pointer to the capacity of the target array
* @retval zero success
* @retval non-zero failure
* @see cx_array_reallocator()
+ * @see cx_array_reserve()
*/
cx_attr_nonnull_arg(1, 2, 3, 6)
-cx_attr_export
-int cx_array_copy(
- void **target,
- void *size,
- void *capacity,
- unsigned width,
- size_t index,
- const void *src,
- size_t elem_size,
- size_t elem_count,
- CxArrayReallocator *reallocator
-);
+CX_EXPORT int cx_array_copy(void **target, void *size, void *capacity, unsigned width,
+ size_t index, const void *src, size_t elem_size, size_t elem_count,
+ CxArrayReallocator *reallocator);
/**
* Convenience macro that uses cx_array_copy() with a default layout and
* @retval non-zero failure
*/
cx_attr_nonnull_arg(1, 2, 3, 5)
-cx_attr_export
-int cx_array_insert_sorted(
- void **target,
- size_t *size,
- size_t *capacity,
- cx_compare_func cmp_func,
- const void *src,
- size_t elem_size,
- size_t elem_count,
- CxArrayReallocator *reallocator
-);
+CX_EXPORT int cx_array_insert_sorted(void **target, size_t *size, size_t *capacity,
+ cx_compare_func cmp_func, const void *src, size_t elem_size, size_t elem_count,
+ CxArrayReallocator *reallocator);
/**
* Inserts an element into a sorted array.
* If the target array is not already sorted with respect
* to the specified @p cmp_func, the behavior is undefined.
*
- * If the capacity is insufficient to hold the new data, a reallocation
+ * If the capacity is not enough to hold the new data, a reallocation
* attempt is made.
*
* The \@ SIZE_TYPE is flexible and can be any unsigned integer type.
* @retval non-zero failure
*/
cx_attr_nonnull_arg(1, 2, 3, 5)
-cx_attr_export
-int cx_array_insert_unique(
- void **target,
- size_t *size,
- size_t *capacity,
- cx_compare_func cmp_func,
- const void *src,
- size_t elem_size,
- size_t elem_count,
- CxArrayReallocator *reallocator
-);
+CX_EXPORT int cx_array_insert_unique(void **target, size_t *size, size_t *capacity,
+ cx_compare_func cmp_func, const void *src, size_t elem_size, size_t elem_count,
+ CxArrayReallocator *reallocator);
/**
* Inserts an element into a sorted array if it does not exist.
* in @p arr that is less or equal to @p elem with respect to @p cmp_func.
* When no such element exists, @p size is returned.
*
+ * When such an element exists more than once, the largest index of all those
+ * elements is returned.
+ *
* If @p elem is contained in the array, this is identical to
* #cx_array_binary_search().
*
* @see cx_array_binary_search()
*/
cx_attr_nonnull
-cx_attr_export
-size_t cx_array_binary_search_inf(
- const void *arr,
- size_t size,
- size_t elem_size,
- const void *elem,
- cx_compare_func cmp_func
-);
+CX_EXPORT size_t cx_array_binary_search_inf(const void *arr, size_t size,
+ size_t elem_size, const void *elem, cx_compare_func cmp_func);
/**
* Searches an item in a sorted array.
*
+ * When such an element exists more than once, the largest index of all those
+ * elements is returned.
+ *
* If the array is not sorted with respect to the @p cmp_func, the behavior
* is undefined.
*
* @see cx_array_binary_search_sup()
*/
cx_attr_nonnull
-cx_attr_export
-size_t cx_array_binary_search(
- const void *arr,
- size_t size,
- size_t elem_size,
- const void *elem,
- cx_compare_func cmp_func
-);
+CX_EXPORT size_t cx_array_binary_search(const void *arr, size_t size,
+ size_t elem_size, const void *elem, cx_compare_func cmp_func);
/**
* Searches the smallest upper bound in a sorted array.
* in @p arr that is greater or equal to @p elem with respect to @p cmp_func.
* When no such element exists, @p size is returned.
*
+ * When such an element exists more than once, the smallest index of all those
+ * elements is returned.
+ *
* If @p elem is contained in the array, this is identical to
* #cx_array_binary_search().
*
* @see cx_array_binary_search()
*/
cx_attr_nonnull
-cx_attr_export
-size_t cx_array_binary_search_sup(
- const void *arr,
- size_t size,
- size_t elem_size,
- const void *elem,
- cx_compare_func cmp_func
-);
+CX_EXPORT size_t cx_array_binary_search_sup(const void *arr, size_t size,
+ size_t elem_size, const void *elem, cx_compare_func cmp_func);
/**
* Swaps two array elements.
* @param idx2 index of the second element
*/
cx_attr_nonnull
-cx_attr_export
-void cx_array_swap(
- void *arr,
- size_t elem_size,
- size_t idx1,
- size_t idx2
-);
+CX_EXPORT void cx_array_swap(void *arr, size_t elem_size, size_t idx1, size_t idx2);
/**
* Allocates an array list for storing elements with @p elem_size bytes each.
cx_attr_nodiscard
cx_attr_malloc
cx_attr_dealloc(cxListFree, 1)
-cx_attr_export
-CxList *cxArrayListCreate(
- const CxAllocator *allocator,
- cx_compare_func comparator,
- size_t elem_size,
- size_t initial_capacity
-);
+CX_EXPORT CxList *cxArrayListCreate(const CxAllocator *allocator,
+ cx_compare_func comparator, size_t elem_size, size_t initial_capacity);
/**
* Allocates an array list for storing elements with @p elem_size bytes each.
/**
* The maximum number of blocks to flush in one cycle.
*
- * @attention while it is guaranteed that cxBufferFlush() will not flush
+ * @attention While it is guaranteed that cxBufferFlush() will not flush
* more blocks, this is not necessarily the case for cxBufferWrite().
* After performing a flush cycle, cxBufferWrite() will retry the write
* operation and potentially trigger another flush cycle, until the
* @return zero on success, non-zero if a required allocation failed
*/
cx_attr_nonnull_arg(1)
-cx_attr_export
-int cxBufferInit(
- CxBuffer *buffer,
- void *space,
- size_t capacity,
- const CxAllocator *allocator,
- int flags
-);
+CX_EXPORT int cxBufferInit(CxBuffer *buffer, void *space, size_t capacity,
+ const CxAllocator *allocator, int flags);
/**
* Configures the buffer for flushing.
* @see cxBufferWrite()
*/
cx_attr_nonnull
-cx_attr_export
-int cxBufferEnableFlushing(
- CxBuffer *buffer,
- CxBufferFlushConfig config
-);
+CX_EXPORT int cxBufferEnableFlushing(CxBuffer *buffer, CxBufferFlushConfig config);
/**
* Destroys the buffer contents.
* @see cxBufferInit()
*/
cx_attr_nonnull
-cx_attr_export
-void cxBufferDestroy(CxBuffer *buffer);
+CX_EXPORT void cxBufferDestroy(CxBuffer *buffer);
/**
* Deallocates the buffer.
* @param buffer the buffer to deallocate
* @see cxBufferCreate()
*/
-cx_attr_export
-void cxBufferFree(CxBuffer *buffer);
+CX_EXPORT 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_attr_export
-CxBuffer *cxBufferCreate(
- void *space,
- size_t capacity,
- const CxAllocator *allocator,
- int flags
-);
+cx_attr_malloc cx_attr_dealloc(cxBufferFree, 1) cx_attr_nodiscard
+CX_EXPORT CxBuffer *cxBufferCreate(void *space, size_t capacity,
+ const CxAllocator *allocator, int flags);
/**
* Shifts the contents of the buffer by the given offset.
* @see cxBufferShiftRight()
*/
cx_attr_nonnull
-cx_attr_export
-int cxBufferShift(
- CxBuffer *buffer,
- off_t shift
-);
+CX_EXPORT int cxBufferShift(CxBuffer *buffer, off_t shift);
/**
* Shifts the buffer to the right.
* @see cxBufferShift()
*/
cx_attr_nonnull
-cx_attr_export
-int cxBufferShiftRight(
- CxBuffer *buffer,
- size_t shift
-);
+CX_EXPORT int cxBufferShiftRight(CxBuffer *buffer, size_t shift);
/**
* Shifts the buffer to the left.
* @see cxBufferShift()
*/
cx_attr_nonnull
-cx_attr_export
-int cxBufferShiftLeft(
- CxBuffer *buffer,
- size_t shift
-);
+CX_EXPORT int cxBufferShiftLeft(CxBuffer *buffer, size_t shift);
/**
*
*/
cx_attr_nonnull
-cx_attr_export
-int cxBufferSeek(
- CxBuffer *buffer,
- off_t offset,
- int whence
-);
+CX_EXPORT int cxBufferSeek(CxBuffer *buffer, off_t offset, int whence);
+
+/**
+ * Discards items from the end of the buffer.
+ *
+ * When the current position points to a byte that gets discarded,
+ * the position is set to the buffer size.
+ *
+ * @param buffer the buffer
+ * @param size the size of one item
+ * @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);
/**
* Clears the buffer by resetting the position and deleting the data.
* @see cxBufferReset()
*/
cx_attr_nonnull
-cx_attr_export
-void cxBufferClear(CxBuffer *buffer);
+CX_EXPORT void cxBufferClear(CxBuffer *buffer);
/**
* Resets the buffer by resetting the position and size to zero.
* @see cxBufferClear()
*/
cx_attr_nonnull
-cx_attr_export
-void cxBufferReset(CxBuffer *buffer);
+CX_EXPORT 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_attr_export
-bool cxBufferEof(const CxBuffer *buffer);
+cx_attr_nonnull cx_attr_nodiscard
+CX_EXPORT bool cxBufferEof(const CxBuffer *buffer);
+/**
+ * Ensures that the buffer has the required capacity.
+ *
+ * If the current capacity is not sufficient, the buffer will be extended.
+ *
+ * This function will reserve no more bytes than requested, in contrast to
+ * cxBufferMinimumCapacity(), which may reserve more bytes to improve the
+ * number of future necessary reallocations.
+ *
+ * @param buffer the buffer
+ * @param capacity the required capacity for this buffer
+ * @retval zero the capacity was already sufficient or successfully increased
+ * @retval non-zero on allocation failure
+ * @see cxBufferShrink()
+ * @see cxBufferMinimumCapacity()
+ */
+cx_attr_nonnull
+CX_EXPORT int cxBufferReserve(CxBuffer *buffer, size_t capacity);
/**
* Ensures that the buffer has a minimum capacity.
*
- * If the current capacity is not sufficient, the buffer will be extended.
+ * If the current capacity is not sufficient, the buffer will be generously
+ * extended.
*
* The new capacity will be a power of two until the system's page size is reached.
* Then, the new capacity will be a multiple of the page size.
* @param capacity the minimum required capacity for this buffer
* @retval zero the capacity was already sufficient or successfully increased
* @retval non-zero on allocation failure
+ * @see cxBufferReserve()
* @see cxBufferShrink()
*/
cx_attr_nonnull
-cx_attr_export
-int cxBufferMinimumCapacity(
- CxBuffer *buffer,
- size_t capacity
-);
+CX_EXPORT int cxBufferMinimumCapacity(CxBuffer *buffer, size_t capacity);
/**
* Shrinks the capacity of the buffer to fit its current size.
*
* @param buffer the buffer
* @param reserve the number of bytes that shall remain reserved
+ * @see cxBufferReserve()
* @see cxBufferMinimumCapacity()
*/
cx_attr_nonnull
-cx_attr_export
-void cxBufferShrink(
- CxBuffer *buffer,
- size_t reserve
-);
+CX_EXPORT void cxBufferShrink(CxBuffer *buffer, size_t reserve);
/**
* Writes data to a CxBuffer.
* @see cxBufferRead()
*/
cx_attr_nonnull
-cx_attr_export
-size_t cxBufferWrite(
- const void *ptr,
- size_t size,
- size_t nitems,
- CxBuffer *buffer
-);
+CX_EXPORT size_t cxBufferWrite(const void *ptr, size_t size,
+ size_t nitems, CxBuffer *buffer);
/**
* Appends data to a CxBuffer.
* @see cxBufferRead()
*/
cx_attr_nonnull
-cx_attr_export
-size_t cxBufferAppend(
- const void *ptr,
- size_t size,
- size_t nitems,
- CxBuffer *buffer
-);
+CX_EXPORT size_t cxBufferAppend(const void *ptr, size_t size,
+ size_t nitems, CxBuffer *buffer);
/**
* Performs a single flush-run on the specified buffer.
* @see cxBufferEnableFlushing()
*/
cx_attr_nonnull
-cx_attr_export
-size_t cxBufferFlush(CxBuffer *buffer);
+CX_EXPORT size_t cxBufferFlush(CxBuffer *buffer);
/**
* Reads data from a CxBuffer.
* @see cxBufferAppend()
*/
cx_attr_nonnull
-cx_attr_export
-size_t cxBufferRead(
- void *ptr,
- size_t size,
- size_t nitems,
- CxBuffer *buffer
-);
+CX_EXPORT size_t cxBufferRead(void *ptr, size_t size,
+ size_t nitems, CxBuffer *buffer);
/**
* Writes a character to a buffer.
* @see cxBufferTerminate()
*/
cx_attr_nonnull
-cx_attr_export
-int cxBufferPut(
- CxBuffer *buffer,
- int c
-);
+CX_EXPORT 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
*/
cx_attr_nonnull
-cx_attr_export
-int cxBufferTerminate(CxBuffer *buffer);
+CX_EXPORT int cxBufferTerminate(CxBuffer *buffer);
/**
* Writes a string to a buffer.
* @param str the zero-terminated string
* @return the number of bytes written
*/
-cx_attr_nonnull
-cx_attr_cstr_arg(2)
-cx_attr_export
-size_t cxBufferPutString(
- CxBuffer *buffer,
- const char *str
-);
+cx_attr_nonnull cx_attr_cstr_arg(2)
+CX_EXPORT size_t cxBufferPutString(CxBuffer *buffer, const char *str);
/**
* Gets a character from a buffer.
* @return the character or @c EOF, if the end of the buffer is reached
*/
cx_attr_nonnull
-cx_attr_export
-int cxBufferGet(CxBuffer *buffer);
+CX_EXPORT int cxBufferGet(CxBuffer *buffer);
#ifdef __cplusplus
}
* @retval true if the elements are currently sorted wrt. the collection's compare function
* @retval false if the order of elements is unknown
*/
-#define cxCollectionSorted(c) ((c)->collection.sorted)
+#define cxCollectionSorted(c) ((c)->collection.sorted || (c)->collection.size == 0)
+
+/**
+ * Sets the compare function for a collection.
+ *
+ * @param c a pointer to a struct that contains #CX_COLLECTION_BASE
+ * @param func (@c cx_compare_func) the compare function that shall be used by @c c
+ */
+#define cxCollectionCompareFunc(c, func) (c)->collection.cmpfunc = (func)
/**
* Sets a simple destructor function for this collection.
#define _Thread_local __declspec(thread)
#endif // _MSC_VER
+// ---------------------------------------------------------------------------
+// Exported and inlined functions
+// ---------------------------------------------------------------------------
+
#if defined(CX_WINDLL_EXPORT)
-#define cx_attr_export __declspec(dllexport)
+#define CX_EXPORT __declspec(dllexport)
#elif defined(CX_WINDLL)
-#define cx_attr_export __declspec(dllimport)
+#define CX_EXPORT __declspec(dllimport)
#else
/** Only used for building Windows DLLs. */
-#define cx_attr_export
+#define CX_EXPORT
#endif // CX_WINDLL / CX_WINDLL_EXPORT
+#ifdef __GNUC__
+/**
+ * Declares a function to be inlined.
+ */
+#define CX_INLINE __attribute__((always_inline)) static inline
+#else
+/**
+ * Declares a function to be inlined.
+ */
+#define CX_INLINE static inline
+#endif
+/**
+ * Declares a compatibility function for C++ builds.
+ */
+#define CX_CPPDECL static inline
+
// ---------------------------------------------------------------------------
// Useful function pointers
// ---------------------------------------------------------------------------
/**
* Function pointer compatible with fwrite-like functions.
*/
-typedef size_t (*cx_write_func)(
- const void *,
- size_t,
- size_t,
- void *
-);
+typedef size_t (*cx_write_func)(const void*, size_t, size_t, void*);
/**
* Function pointer compatible with fread-like functions.
*/
-typedef size_t (*cx_read_func)(
- void *,
- size_t,
- size_t,
- void *
-);
+typedef size_t (*cx_read_func)(void*, size_t, size_t, void*);
// ---------------------------------------------------------------------------
// Utility macros
#if __cplusplus
extern "C"
#endif
-cx_attr_export int cx_szmul_impl(size_t a, size_t b, size_t *result);
+CX_EXPORT int cx_szmul_impl(size_t a, size_t b, size_t *result);
#endif // cx_szmul
-
-
#endif // UCX_COMMON_H
+++ /dev/null
-/*
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
- *
- * Copyright 2021 Mike Becker, Olaf Wintermann All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- */
-
-/**
- * \file common.h
- *
- * \brief Common definitions and feature checks.
- *
- * \author Mike Becker
- * \author Olaf Wintermann
- * \version 3.0
- * \copyright 2-Clause BSD License
- *
- * \mainpage UAP Common Extensions
- * Library with common and useful functions, macros and data structures.
- * <p>
- * Latest available source:<br>
- * <a href="https://sourceforge.net/projects/ucx/files/">https://sourceforge.net/projects/ucx/files/</a>
- * </p>
- *
- * <p>
- * Repositories:<br>
- * <a href="https://sourceforge.net/p/ucx/code">https://sourceforge.net/p/ucx/code</a>
- * - or -
- * <a href="https://develop.uap-core.de/hg/ucx">https://develop.uap-core.de/hg/ucx</a>
- * </p>
- *
- * <h2>LICENCE</h2>
- *
- * Copyright 2021 Mike Becker, Olaf Wintermann All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef UCX_COMMON_H
-#define UCX_COMMON_H
-
-/** Major UCX version as integer constant. */
-#define UCX_VERSION_MAJOR 3
-
-/** Minor UCX version as integer constant. */
-#define UCX_VERSION_MINOR 0
-
-/** Version constant which ensures to increase monotonically. */
-#define UCX_VERSION (((UCX_VERSION_MAJOR)<<16)|UCX_VERSION_MINOR)
-
-#define __attribute__(...)
-
-#include <stdlib.h>
-#include <stddef.h>
-#include <stdbool.h>
-#include <stdint.h>
-
-/**
- * Function pointer compatible with fwrite-like functions.
- */
-typedef size_t (*cx_write_func)(
- void const *,
- size_t,
- size_t,
- void *
-);
-
-/**
- * Function pointer compatible with fread-like functions.
- */
-typedef size_t (*cx_read_func)(
- void *,
- size_t,
- size_t,
- void *
-);
-
-#ifdef _WIN32
-
-#ifdef __MINGW32__
-#include <sys/types.h>
-#endif // __MINGW32__
-
-#else // !_WIN32
-
-#include <sys/types.h>
-
-#endif // _WIN32
-
-#ifndef __GNUC__
-/**
- * Removes GNU C attributes where they are not supported.
- */
-#define __attribute__(x)
-#endif
-
-#endif // UCX_COMMON_H
* can be used, but they are NOT compatible with this function
* pointer.
*/
-cx_attr_nonnull
-cx_attr_nodiscard
-cx_attr_export
-typedef int (*cx_compare_func)(
- const void *left,
- const void *right
-);
+typedef int (*cx_compare_func)(const void *left, const void *right);
/**
* 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_attr_export
-int cx_cmp_int(const void *i1, const void *i2);
+cx_attr_nonnull cx_attr_nodiscard
+CX_EXPORT int cx_cmp_int(const void *i1, const void *i2);
/**
* Compares two integers of type int.
* @retval 1 if the left argument is greater than the right argument
*/
cx_attr_nodiscard
-cx_attr_export
-int cx_vcmp_int(int i1, int i2);
+CX_EXPORT 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_attr_export
-int cx_cmp_longint(const void *i1, const void *i2);
+cx_attr_nonnull cx_attr_nodiscard
+CX_EXPORT int cx_cmp_longint(const void *i1, const void *i2);
/**
* Compares two integers of type long int.
* @retval 1 if the left argument is greater than the right argument
*/
cx_attr_nodiscard
-cx_attr_export
-int cx_vcmp_longint(long int i1, long int i2);
+CX_EXPORT 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_attr_export
-int cx_cmp_longlong(const void *i1, const void *i2);
+cx_attr_nonnull cx_attr_nodiscard
+CX_EXPORT int cx_cmp_longlong(const void *i1, const void *i2);
/**
* Compares two integers of type long long.
* @retval 1 if the left argument is greater than the right argument
*/
cx_attr_nodiscard
-cx_attr_export
-int cx_vcmp_longlong(long long int i1, long long int i2);
+CX_EXPORT 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_attr_export
-int cx_cmp_int16(const void *i1, const void *i2);
+cx_attr_nonnull cx_attr_nodiscard
+CX_EXPORT int cx_cmp_int16(const void *i1, const void *i2);
/**
* Compares two integers of type int16_t.
* @retval 1 if the left argument is greater than the right argument
*/
cx_attr_nodiscard
-cx_attr_export
-int cx_vcmp_int16(int16_t i1, int16_t i2);
+CX_EXPORT 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_attr_export
-int cx_cmp_int32(const void *i1, const void *i2);
+cx_attr_nonnull cx_attr_nodiscard
+CX_EXPORT int cx_cmp_int32(const void *i1, const void *i2);
/**
* Compares two integers of type int32_t.
* @retval 1 if the left argument is greater than the right argument
*/
cx_attr_nodiscard
-cx_attr_export
-int cx_vcmp_int32(int32_t i1, int32_t i2);
+CX_EXPORT 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_attr_export
-int cx_cmp_int64(const void *i1, const void *i2);
+cx_attr_nonnull cx_attr_nodiscard
+CX_EXPORT int cx_cmp_int64(const void *i1, const void *i2);
/**
* Compares two integers of type int64_t.
* @retval 1 if the left argument is greater than the right argument
*/
cx_attr_nodiscard
-cx_attr_export
-int cx_vcmp_int64(int64_t i1, int64_t i2);
+CX_EXPORT 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_attr_export
-int cx_cmp_uint(const void *i1, const void *i2);
+cx_attr_nonnull cx_attr_nodiscard
+CX_EXPORT int cx_cmp_uint(const void *i1, const void *i2);
/**
* Compares two integers of type unsigned int.
* @retval 1 if the left argument is greater than the right argument
*/
cx_attr_nodiscard
-cx_attr_export
-int cx_vcmp_uint(unsigned int i1, unsigned int i2);
+CX_EXPORT 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_attr_export
-int cx_cmp_ulongint(const void *i1, const void *i2);
+cx_attr_nonnull cx_attr_nodiscard
+CX_EXPORT int cx_cmp_ulongint(const void *i1, const void *i2);
/**
* Compares two integers of type unsigned long int.
* @retval 1 if the left argument is greater than the right argument
*/
cx_attr_nodiscard
-cx_attr_export
-int cx_vcmp_ulongint(unsigned long int i1, unsigned long int i2);
+CX_EXPORT 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_attr_export
-int cx_cmp_ulonglong(const void *i1, const void *i2);
+cx_attr_nonnull cx_attr_nodiscard
+CX_EXPORT int cx_cmp_ulonglong(const void *i1, const void *i2);
/**
* Compares two integers of type unsigned long long.
* @retval 1 if the left argument is greater than the right argument
*/
cx_attr_nodiscard
-cx_attr_export
-int cx_vcmp_ulonglong(unsigned long long int i1, unsigned long long int i2);
+CX_EXPORT 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_attr_export
-int cx_cmp_uint16(const void *i1, const void *i2);
+cx_attr_nonnull cx_attr_nodiscard
+CX_EXPORT int cx_cmp_uint16(const void *i1, const void *i2);
/**
* Compares two integers of type uint16_t.
* @retval 1 if the left argument is greater than the right argument
*/
cx_attr_nodiscard
-cx_attr_export
-int cx_vcmp_uint16(uint16_t i1, uint16_t i2);
+CX_EXPORT 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_attr_export
-int cx_cmp_uint32(const void *i1, const void *i2);
+cx_attr_nonnull cx_attr_nodiscard
+CX_EXPORT int cx_cmp_uint32(const void *i1, const void *i2);
/**
* Compares two integers of type uint32_t.
* @retval 1 if the left argument is greater than the right argument
*/
cx_attr_nodiscard
-cx_attr_export
-int cx_vcmp_uint32(uint32_t i1, uint32_t i2);
+CX_EXPORT 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_attr_export
-int cx_cmp_uint64(const void *i1, const void *i2);
+cx_attr_nonnull cx_attr_nodiscard
+CX_EXPORT int cx_cmp_uint64(const void *i1, const void *i2);
/**
* Compares two integers of type uint64_t.
* @retval 1 if the left argument is greater than the right argument
*/
cx_attr_nodiscard
-cx_attr_export
-int cx_vcmp_uint64(uint64_t i1, uint64_t i2);
+CX_EXPORT 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_attr_export
-int cx_cmp_size(const void *i1, const void *i2);
+cx_attr_nonnull cx_attr_nodiscard
+CX_EXPORT int cx_cmp_size(const void *i1, const void *i2);
/**
* Compares two integers of type size_t.
* @retval 1 if the left argument is greater than the right argument
*/
cx_attr_nodiscard
-cx_attr_export
-int cx_vcmp_size(size_t i1, size_t i2);
+CX_EXPORT 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_attr_export
-int cx_cmp_float(const void *f1, const void *f2);
+cx_attr_nonnull cx_attr_nodiscard
+CX_EXPORT int cx_cmp_float(const void *f1, const void *f2);
/**
* Compares two real numbers of type float with precision 1e-6f.
* @retval 1 if the left argument is greater than the right argument
*/
cx_attr_nodiscard
-cx_attr_export
-int cx_vcmp_float(float f1, float f2);
+CX_EXPORT 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_attr_export
-int cx_cmp_double(const void *d1, const void *d2);
+cx_attr_nonnull cx_attr_nodiscard
+CX_EXPORT int cx_cmp_double(const void *d1, const void *d2);
/**
* Compares two real numbers of type double with precision 1e-14.
* @retval 1 if the left argument is greater than the right argument
*/
cx_attr_nodiscard
-cx_attr_export
-int cx_vcmp_double(double d1, double d2);
+CX_EXPORT 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_attr_export
-int cx_cmp_intptr(const void *ptr1, const void *ptr2);
+cx_attr_nonnull cx_attr_nodiscard
+CX_EXPORT int cx_cmp_intptr(const void *ptr1, const void *ptr2);
/**
* Compares the integer representation of two pointers.
* @retval 1 if the left argument is greater than the right argument
*/
cx_attr_nodiscard
-cx_attr_export
-int cx_vcmp_intptr(intptr_t ptr1, intptr_t ptr2);
+CX_EXPORT 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_attr_export
-int cx_cmp_uintptr(const void *ptr1, const void *ptr2);
+cx_attr_nonnull cx_attr_nodiscard
+CX_EXPORT int cx_cmp_uintptr(const void *ptr1, const void *ptr2);
/**
* Compares the unsigned integer representation of two pointers.
* @retval 1 if the left argument is greater than the right argument
*/
cx_attr_nodiscard
-cx_attr_export
-int cx_vcmp_uintptr(uintptr_t ptr1, uintptr_t ptr2);
+CX_EXPORT 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_attr_export
-int cx_cmp_ptr(const void *ptr1, const void *ptr2);
+cx_attr_nonnull cx_attr_nodiscard
+CX_EXPORT int cx_cmp_ptr(const void *ptr1, const void *ptr2);
#ifdef __cplusplus
} // extern "C"
* @see cx_hash_key()
*/
cx_attr_nonnull
-cx_attr_export
-void cx_hash_murmur(CxHashKey *key);
+CX_EXPORT 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_attr_export
-uint32_t cx_hash_u32(uint32_t x);
+CX_EXPORT uint32_t cx_hash_u32(uint32_t x);
/**
* Mixes up a 64-bit integer to be used as a hash.
* @param x the integer
* @return the hash
*/
-cx_attr_export
-uint64_t cx_hash_u64(uint64_t x);
+CX_EXPORT uint64_t cx_hash_u64(uint64_t x);
/**
* Computes a hash key from a 32-bit integer.
* @return the hash key
*/
cx_attr_nodiscard
-cx_attr_export
-CxHashKey cx_hash_key_u32(uint32_t x);
+CX_EXPORT CxHashKey cx_hash_key_u32(uint32_t x);
/**
* Computes a hash key from a 64-bit integer.
* @return the hash key
*/
cx_attr_nodiscard
-cx_attr_export
-CxHashKey cx_hash_key_u64(uint64_t x);
+CX_EXPORT CxHashKey cx_hash_key_u64(uint64_t x);
/**
* Computes a hash key from a string.
* @param str the string
* @return the hash key
*/
-cx_attr_nodiscard
-cx_attr_cstr_arg(1)
-cx_attr_export
-CxHashKey cx_hash_key_str(const char *str);
+cx_attr_nodiscard cx_attr_cstr_arg(1)
+CX_EXPORT CxHashKey cx_hash_key_str(const char *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_attr_export
-static inline CxHashKey cx_hash_key_ustr(const unsigned char *str) {
- return cx_hash_key_str((const char*)str);
-}
+cx_attr_nodiscard cx_attr_cstr_arg(1)
+CX_EXPORT CxHashKey cx_hash_key_ustr(const unsigned 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_attr_export
-CxHashKey cx_hash_key_bytes(
- const unsigned char *bytes,
- size_t len
-);
+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.
*/
cx_attr_nodiscard
cx_attr_access_r(1, 2)
-cx_attr_export
-CxHashKey cx_hash_key(
- const void *obj,
- size_t len
-);
+CX_EXPORT CxHashKey cx_hash_key(const void *obj, size_t len);
/**
* Computes a hash key from a UCX string.
* @return the hash key
*/
cx_attr_nodiscard
-static inline CxHashKey cx_hash_key_cxstr(cxstring str) {
- return cx_hash_key(str.ptr, str.length);
-}
+CX_EXPORT CxHashKey cx_hash_key_cxstr(cxstring str);
/**
* Computes a hash key from a UCX string.
* @return the hash key
*/
cx_attr_nodiscard
-static inline CxHashKey cx_hash_key_mutstr(cxmutstr str) {
- return cx_hash_key(str.ptr, str.length);
-}
+CX_EXPORT CxHashKey cx_hash_key_mutstr(cxmutstr str);
/**
* The identity function for the CX_HASH_KEY() macro.
* @return a copy of the key
*/
cx_attr_nodiscard
-static inline CxHashKey cx_hash_key_identity(CxHashKey key) {
+CX_INLINE CxHashKey cx_hash_key_identity(CxHashKey key) {
return key;
}
(key)
#endif // __cplusplus
-/**
- * Computes a hash key from a UCX string.
- * Convenience macro that accepts both cxstring and cxmutstr.
- * @deprecated use the CX_HASH_KEY() macro instead
- * @param str (@c cxstring or @c cxmutstr) the string
- * @return (@c CxHashKey) the hash key
- */
-#define cx_hash_key_cxstr(str) cx_hash_key_cxstr(cx_strcast(str))
-
/**
* Compare function for hash keys.
*
- * @param left the first key
- * @param right the second key
+ * The pointers are untyped to be compatible with the cx_compare_func signature.
+ *
+ * @param left (@c CxHashKey*) the first key
+ * @param right (@c CxHashKey*) the second key
* @return zero when the keys equal, non-zero when they differ
*/
-cx_attr_nodiscard
-cx_attr_nonnull
-cx_attr_export
-int cx_hash_key_cmp(const CxHashKey *left, const CxHashKey *right);
+cx_attr_nodiscard cx_attr_nonnull
+CX_EXPORT int cx_hash_key_cmp(const void *left, const void *right);
#ifdef __cplusplus
} // extern "C"
// Overloads of CX_HASH_KEY (the C++ version of a _Generic)
// ----------------------------------------------------------
-static inline CxHashKey CX_HASH_KEY(CxHashKey key) {
+CX_CPPDECL CxHashKey CX_HASH_KEY(CxHashKey key) {
return key;
}
-static inline CxHashKey CX_HASH_KEY(cxstring str) {
+CX_CPPDECL CxHashKey CX_HASH_KEY(cxstring str) {
return cx_hash_key_cxstr(str);
}
-static inline CxHashKey CX_HASH_KEY(cxmutstr str) {
+CX_CPPDECL CxHashKey CX_HASH_KEY(cxmutstr str) {
return cx_hash_key_mutstr(str);
}
-static inline CxHashKey CX_HASH_KEY(const char *str) {
+CX_CPPDECL CxHashKey CX_HASH_KEY(const char *str) {
return cx_hash_key_str(str);
}
-static inline CxHashKey CX_HASH_KEY(const unsigned char *str) {
+CX_CPPDECL CxHashKey CX_HASH_KEY(const unsigned char *str) {
return cx_hash_key_ustr(str);
}
-static inline CxHashKey CX_HASH_KEY(uint32_t key) {
+CX_CPPDECL CxHashKey CX_HASH_KEY(uint32_t key) {
return cx_hash_key_u32(key);
}
-static inline CxHashKey CX_HASH_KEY(uint64_t key) {
+CX_CPPDECL CxHashKey CX_HASH_KEY(uint64_t key) {
return cx_hash_key_u64(key);
}
#endif
* @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_attr_export
-CxMap *cxHashMapCreate(
- const CxAllocator *allocator,
- size_t itemsize,
- size_t buckets
-);
+cx_attr_nodiscard cx_attr_malloc cx_attr_dealloc(cxMapFree, 1)
+CX_EXPORT CxMap *cxHashMapCreate(const CxAllocator *allocator,
+ size_t itemsize, size_t buckets);
/**
* Creates a new hash map with a default number of buckets.
* @retval non-zero if a memory allocation error occurred
*/
cx_attr_nonnull
-cx_attr_export
-int cxMapRehash(CxMap *map);
+CX_EXPORT int cxMapRehash(CxMap *map);
#ifdef __cplusplus
* True if the iterator points to valid data.
*/
bool (*valid)(const void *);
-
+ /**
+ * Original implementation in case the function needs to be wrapped.
+ */
+ bool (*valid_impl)(const void *);
/**
* Returns a pointer to the current element.
*
* Original implementation in case the function needs to be wrapped.
*/
void *(*current_impl)(const void *);
-
/**
* Advances the iterator.
*
/**
* Indicates whether this iterator may remove elements.
*/
- bool mutating;
+ bool allow_remove;
/**
* Internal flag for removing the current element when advancing.
*/
/**
* Handle for the source collection, if any.
*/
- union {
- /**
- * Access for mutating iterators.
- */
- void *m;
- /**
- * Access for normal iterators.
- */
- const void *c;
- } src_handle;
+ void *src_handle;
/**
* If the iterator is position-aware, contains the index of the element in the underlying collection.
* to be "position-aware", which means that they keep track of the current index within the collection.
*
* @note Objects that are pointed to by an iterator are always mutable through that iterator. However,
- * any concurrent mutation of the collection other than by this iterator makes this iterator invalid,
+ * any concurrent mutation of the collection other than by this iterator makes this iterator obsolete,
* and it must not be used anymore.
*/
typedef struct cx_iterator_s CxIterator;
#define cxIteratorNext(iter) (iter).base.next(&iter)
/**
- * Flags the current element for removal if this iterator is mutating.
- *
- * Does nothing for non-mutating iterators.
+ * Flags the current element for removal if the iterator allows it.
*
* @param iter the iterator
+ * @return @c true if removal is allowed, @c false otherwise
*/
-#define cxIteratorFlagRemoval(iter) (iter).base.remove |= (iter).base.mutating
+#define cxIteratorFlagRemoval(iter) ((iter).base.remove = (iter).base.allow_remove)
/**
* Obtains a reference to an arbitrary iterator.
* use cxIteratorPtr() to create an iterator which directly
* yields the stored pointers.
*
- * @param array a pointer to the array (can be @c NULL)
- * @param elem_size the size of one array element
- * @param elem_count the number of elements in the array
- * @return an iterator for the specified array
- * @see cxIteratorPtr()
- */
-cx_attr_nodiscard
-cx_attr_export
-CxIterator cxIterator(
- const void *array,
- size_t elem_size,
- size_t elem_count
-);
-
-/**
- * Creates a mutating iterator for the specified plain array.
- *
* While the iterator is in use, the array may only be altered by removing
* elements through #cxIteratorFlagRemoval(). Every other change to the array
* will bring this iterator to an undefined state.
* moving all subsequent elements by one. Usually, when the order of elements is
* not important, this parameter should be set to @c false.
*
- * The @p array can be @c NULL, in which case the iterator will be immediately
- * initialized such that #cxIteratorValid() returns @c false.
- *
- *
* @param array a pointer to the array (can be @c NULL)
* @param elem_size the size of one array element
* @param elem_count the number of elements in the array
* @param remove_keeps_order @c true if the order of elements must be preserved
* when removing an element
* @return an iterator for the specified array
+ * @see cxIteratorPtr()
*/
cx_attr_nodiscard
-cx_attr_export
-CxIterator cxMutIterator(
- void *array,
- size_t elem_size,
- size_t elem_count,
- bool remove_keeps_order
-);
+CX_EXPORT CxIterator cxIterator(const void *array,
+ size_t elem_size, size_t elem_count, bool remove_keeps_order);
/**
* Creates an iterator for the specified plain pointer array.
* hand, an iterator created with cxIterator() would return the
* addresses of those pointers within the array).
*
- * @param array a pointer to the array (can be @c NULL)
- * @param elem_count the number of elements in the array
- * @return an iterator for the specified array
- * @see cxIterator()
- */
-cx_attr_nodiscard
-cx_attr_export
-CxIterator cxIteratorPtr(
- const void *array,
- size_t elem_count
-);
-
-/**
- * Creates a mutating iterator for the specified plain pointer array.
+ * While the iterator is in use, the array may only be altered by removing
+ * elements through #cxIteratorFlagRemoval(). Every other change to the array
+ * will bring this iterator to an undefined state.
*
- * This is the mutating variant of cxIteratorPtr(). See also
- * cxMutIterator().
+ * When @p remove_keeps_order is set to @c false, removing an element will only
+ * move the last element to the position of the removed element, instead of
+ * moving all subsequent elements by one. Usually, when the order of elements is
+ * not important, this parameter should be set to @c false.
*
* @param array a pointer to the array (can be @c NULL)
* @param elem_count the number of elements in the array
* @param remove_keeps_order @c true if the order of elements must be preserved
* when removing an element
* @return an iterator for the specified array
- * @see cxMutIterator()
- * @see cxIteratorPtr()
+ * @see cxIterator()
*/
cx_attr_nodiscard
-cx_attr_export
-CxIterator cxMutIteratorPtr(
- void *array,
- size_t elem_count,
- bool remove_keeps_order
-);
+CX_EXPORT CxIterator cxIteratorPtr(const void *array, size_t elem_count,
+ bool remove_keeps_order);
#ifdef __cplusplus
} // extern "C"
* @return new JSON writer settings
*/
cx_attr_nodiscard
-cx_attr_export
-CxJsonWriter cxJsonWriterCompact(void);
+CX_EXPORT CxJsonWriter cxJsonWriterCompact(void);
/**
* Creates a default writer configuration for pretty output.
* @return new JSON writer settings
*/
cx_attr_nodiscard
-cx_attr_export
-CxJsonWriter cxJsonWriterPretty(bool use_spaces);
+CX_EXPORT CxJsonWriter cxJsonWriterPretty(bool use_spaces);
/**
* Writes a JSON value to a buffer or stream.
* @retval non-zero when no or not all data could be written
*/
cx_attr_nonnull_arg(1, 2, 3)
-cx_attr_export
-int cxJsonWrite(
- void* target,
- const CxJsonValue* value,
- cx_write_func wfunc,
- const CxJsonWriter* settings
-);
+CX_EXPORT int cxJsonWrite(void* target, const CxJsonValue* value,
+ cx_write_func wfunc, const CxJsonWriter* settings);
/**
* Initializes the JSON interface.
* @see cxJsonDestroy()
*/
cx_attr_nonnull_arg(1)
-cx_attr_export
-void cxJsonInit(CxJson *json, const CxAllocator *allocator);
+CX_EXPORT void cxJsonInit(CxJson *json, const CxAllocator *allocator);
/**
* Destroys the JSON interface.
* @see cxJsonInit()
*/
cx_attr_nonnull
-cx_attr_export
-void cxJsonDestroy(CxJson *json);
+CX_EXPORT void cxJsonDestroy(CxJson *json);
/**
* Destroys and re-initializes the JSON interface.
* @param json the JSON interface
*/
cx_attr_nonnull
-static inline void cxJsonReset(CxJson *json) {
- const CxAllocator *allocator = json->allocator;
- cxJsonDestroy(json);
- cxJsonInit(json, allocator);
-}
+CX_EXPORT void cxJsonReset(CxJson *json);
/**
* Fills the input buffer.
* @retval non-zero internal allocation error
* @see cxJsonFill()
*/
-cx_attr_nonnull
-cx_attr_access_r(2, 3)
-cx_attr_export
-int cxJsonFilln(CxJson *json, const char *buf, size_t len);
+cx_attr_nonnull_arg(1) cx_attr_access_r(2, 3)
+CX_EXPORT int cxJsonFilln(CxJson *json, const char *buf, size_t len);
/**
* @retval non-zero internal allocation error
*/
cx_attr_nonnull
-static inline int cx_json_fill(CxJson *json, cxstring str) {
+CX_INLINE int cx_json_fill(CxJson *json, cxstring str) {
return cxJsonFilln(json, str.ptr, str.length);
}
* @see cxJsonArrAddValues()
*/
cx_attr_nodiscard
-cx_attr_export
-CxJsonValue* cxJsonCreateObj(const CxAllocator* allocator);
+CX_EXPORT CxJsonValue* cxJsonCreateObj(const CxAllocator* allocator);
/**
* Creates a new (empty) JSON array.
* @see cxJsonArrAddValues()
*/
cx_attr_nodiscard
-cx_attr_export
-CxJsonValue* cxJsonCreateArr(const CxAllocator* allocator);
+CX_EXPORT CxJsonValue* cxJsonCreateArr(const CxAllocator* allocator);
/**
* Creates a new JSON number value.
* @see cxJsonArrAddNumbers()
*/
cx_attr_nodiscard
-cx_attr_export
-CxJsonValue* cxJsonCreateNumber(const CxAllocator* allocator, double num);
+CX_EXPORT CxJsonValue* cxJsonCreateNumber(const CxAllocator* allocator, double num);
/**
* Creates a new JSON number value based on an integer.
* @see cxJsonArrAddIntegers()
*/
cx_attr_nodiscard
-cx_attr_export
-CxJsonValue* cxJsonCreateInteger(const CxAllocator* allocator, int64_t num);
+CX_EXPORT CxJsonValue* cxJsonCreateInteger(const CxAllocator* allocator, int64_t num);
/**
* Creates a new JSON string.
*
+ * Internal function - use cxJsonCreateString() instead.
+ *
* @param allocator the allocator to use
* @param str the string data
* @return the new JSON value or @c NULL if allocation fails
- * @see cxJsonCreateString()
* @see cxJsonObjPutString()
- * @see cxJsonArrAddStrings()
+ * @see cxJsonArrAddCxStrings()
*/
cx_attr_nodiscard
-cx_attr_nonnull_arg(2)
-cx_attr_cstr_arg(2)
-cx_attr_export
-CxJsonValue* cxJsonCreateString(const CxAllocator* allocator, const char *str);
+CX_EXPORT CxJsonValue* cx_json_create_string(const CxAllocator* allocator, cxstring str);
/**
* Creates a new JSON string.
*
- * @param allocator the allocator to use
- * @param str the string data
- * @return the new JSON value or @c NULL if allocation fails
- * @see cxJsonCreateCxString()
- * @see cxJsonObjPutCxString()
+ * @param allocator (@c CxAllocator*) the allocator to use
+ * @param str the string
+ * @return (@c CxJsonValue*) the new JSON value or @c NULL if allocation fails
+ * @see cxJsonObjPutString()
* @see cxJsonArrAddCxStrings()
*/
-cx_attr_nodiscard
-cx_attr_export
-CxJsonValue* cxJsonCreateCxString(const CxAllocator* allocator, cxstring str);
+#define cxJsonCreateString(allocator, str) cx_json_create_string(allocator, cx_strcast(str))
/**
* Creates a new JSON literal.
* @see cxJsonArrAddLiterals()
*/
cx_attr_nodiscard
-cx_attr_export
-CxJsonValue* cxJsonCreateLiteral(const CxAllocator* allocator, CxJsonLiteral lit);
+CX_EXPORT 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_attr_export
-int cxJsonArrAddNumbers(CxJsonValue* arr, const double* num, size_t count);
+cx_attr_nonnull cx_attr_access_r(2, 3)
+CX_EXPORT 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_attr_export
-int cxJsonArrAddIntegers(CxJsonValue* arr, const int64_t* num, size_t count);
+cx_attr_nonnull cx_attr_access_r(2, 3)
+CX_EXPORT 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_attr_export
-int cxJsonArrAddStrings(CxJsonValue* arr, const char* const* str, size_t count);
+cx_attr_nonnull cx_attr_access_r(2, 3)
+CX_EXPORT 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_attr_export
-int cxJsonArrAddCxStrings(CxJsonValue* arr, const cxstring* str, size_t count);
+cx_attr_nonnull cx_attr_access_r(2, 3)
+CX_EXPORT 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_attr_export
-int cxJsonArrAddLiterals(CxJsonValue* arr, const CxJsonLiteral* lit, size_t count);
+cx_attr_nonnull cx_attr_access_r(2, 3)
+CX_EXPORT 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);
+
+/**
+ * Adds or replaces a value within a JSON object.
+ *
+ * Internal function - use cxJsonObjPut().
+ *
+ * @param obj the JSON object
+ * @param name the name of the value
+ * @param child the value
+ * @retval zero success
+ * @retval non-zero allocation failure
+ */
cx_attr_nonnull
-cx_attr_access_r(2, 3)
-cx_attr_export
-int cxJsonArrAddValues(CxJsonValue* arr, CxJsonValue* const* val, size_t count);
+CX_EXPORT int cx_json_obj_put(CxJsonValue* obj, cxstring name, CxJsonValue* child);
/**
* Adds or replaces a value within a JSON object.
* @note If a value with the specified @p name already exists,
* it will be (recursively) freed with its own allocator.
*
- * @param obj the JSON object
- * @param name the name of the value
- * @param child the value
+ * @param obj (@c CxJsonValue*) the JSON object
+ * @param name (any string) the name of the value
+ * @param child (@c CxJsonValue*) the value
* @retval zero success
* @retval non-zero allocation failure
*/
-cx_attr_nonnull
-cx_attr_export
-int cxJsonObjPut(CxJsonValue* obj, cxstring name, CxJsonValue* child);
+#define cxJsonObjPut(obj, name, child) cx_json_obj_put(obj, cx_strcast(name), child)
/**
* Creates a new JSON object and adds it to an existing object.
*
+ * Internal function - use cxJsonObjPutObj().
+ *
* @param obj the target JSON object
* @param name the name of the new value
* @return the new value or @c NULL if allocation fails
* @see cxJsonCreateObj()
*/
cx_attr_nonnull
-cx_attr_export
-CxJsonValue* cxJsonObjPutObj(CxJsonValue* obj, cxstring name);
+CX_EXPORT CxJsonValue* cx_json_obj_put_obj(CxJsonValue* obj, cxstring name);
+
+/**
+ * Creates a new JSON object and adds it to an existing object.
+ *
+ * @param obj (@c CxJsonValue*) the target JSON object
+ * @param name (any string) the name of the new value
+ * @return (@c CxJsonValue*) the new value or @c NULL if allocation fails
+ * @see cxJsonObjPut()
+ * @see cxJsonCreateObj()
+ */
+#define cxJsonObjPutObj(obj, name) cx_json_obj_put_obj(obj, cx_strcast(name))
/**
* Creates a new JSON array and adds it to an object.
*
+ * Internal function - use cxJsonObjPutArr().
+ *
* @param obj the target JSON object
* @param name the name of the new value
* @return the new value or @c NULL if allocation fails
* @see cxJsonCreateArr()
*/
cx_attr_nonnull
-cx_attr_export
-CxJsonValue* cxJsonObjPutArr(CxJsonValue* obj, cxstring name);
+CX_EXPORT CxJsonValue* cx_json_obj_put_arr(CxJsonValue* obj, cxstring name);
+
+/**
+ * Creates a new JSON array and adds it to an object.
+ *
+ * @param obj (@c CxJsonValue*) the target JSON object
+ * @param name (any string) the name of the new value
+ * @return (@c CxJsonValue*) the new value or @c NULL if allocation fails
+ * @see cxJsonObjPut()
+ * @see cxJsonCreateArr()
+ */
+#define cxJsonObjPutArr(obj, name) cx_json_obj_put_arr(obj, cx_strcast(name))
/**
* Creates a new JSON number and adds it to an object.
*
+ * Internal function - use cxJsonObjPutNumber().
+ *
* @param obj the target JSON object
* @param name the name of the new value
* @param num the numeric value
* @see cxJsonCreateNumber()
*/
cx_attr_nonnull
-cx_attr_export
-CxJsonValue* cxJsonObjPutNumber(CxJsonValue* obj, cxstring name, double num);
+CX_EXPORT CxJsonValue* cx_json_obj_put_number(CxJsonValue* obj, cxstring name, double num);
+
+/**
+ * Creates a new JSON number and adds it to an object.
+ *
+ * @param obj (@c CxJsonValue*) the target JSON object
+ * @param name (any string) the name of the new value
+ * @param num (@c double) the numeric value
+ * @return (@c CxJsonValue*) the new value or @c NULL if allocation fails
+ * @see cxJsonObjPut()
+ * @see cxJsonCreateNumber()
+ */
+#define cxJsonObjPutNumber(obj, name, num) cx_json_obj_put_number(obj, cx_strcast(name), num)
/**
* Creates a new JSON number, based on an integer, and adds it to an object.
*
+ * Internal function - use cxJsonObjPutInteger().
+ *
* @param obj the target JSON object
* @param name the name of the new value
* @param num the numeric value
* @see cxJsonCreateInteger()
*/
cx_attr_nonnull
-cx_attr_export
-CxJsonValue* cxJsonObjPutInteger(CxJsonValue* obj, cxstring name, int64_t num);
+CX_EXPORT 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.
+ *
+ * @param obj (@c CxJsonValue*) the target JSON object
+ * @param name (any string) the name of the new value
+ * @param num (@c int64_t) the numeric value
+ * @return (@c CxJsonValue*) the new value or @c NULL if allocation fails
+ * @see cxJsonObjPut()
+ * @see cxJsonCreateInteger()
+ */
+#define cxJsonObjPutInteger(obj, name, num) cx_json_obj_put_integer(obj, cx_strcast(name), num)
/**
* Creates a new JSON string and adds it to an object.
*
- * The string data is copied.
+ * Internal function - use cxJsonObjPutString()
*
* @param obj the target JSON object
* @param name the name of the new value
* @see cxJsonCreateString()
*/
cx_attr_nonnull
-cx_attr_cstr_arg(3)
-cx_attr_export
-CxJsonValue* cxJsonObjPutString(CxJsonValue* obj, cxstring name, const char* str);
+CX_EXPORT CxJsonValue* cx_json_obj_put_string(CxJsonValue* obj, cxstring name, cxstring str);
/**
* Creates a new JSON string and adds it to an object.
*
* The string data is copied.
*
- * @param obj the target JSON object
- * @param name the name of the new value
- * @param str the string data
- * @return the new value or @c NULL if allocation fails
+ * @param obj (@c CxJsonValue*) the target JSON object
+ * @param name (any string) the name of the new value
+ * @param str (any string) the string data
+ * @return (@c CxJsonValue*) the new value or @c NULL if allocation fails
* @see cxJsonObjPut()
- * @see cxJsonCreateCxString()
+ * @see cxJsonCreateString()
*/
-cx_attr_nonnull
-cx_attr_export
-CxJsonValue* cxJsonObjPutCxString(CxJsonValue* obj, cxstring name, cxstring str);
+#define cxJsonObjPutString(obj, name, str) cx_json_obj_put_string(obj, cx_strcast(name), cx_strcast(str))
/**
* Creates a new JSON literal and adds it to an object.
*
+ * Internal function - use cxJsonObjPutLiteral().
+ *
* @param obj the target JSON object
* @param name the name of the new value
* @param lit the type of literal
* @see cxJsonCreateLiteral()
*/
cx_attr_nonnull
-cx_attr_export
-CxJsonValue* cxJsonObjPutLiteral(CxJsonValue* obj, cxstring name, CxJsonLiteral lit);
+CX_EXPORT CxJsonValue* cx_json_obj_put_literal(CxJsonValue* obj, cxstring name, CxJsonLiteral lit);
+
+/**
+ * Creates a new JSON literal and adds it to an object.
+ *
+ * @param obj (@c CxJsonValue*) the target JSON object
+ * @param name (any string) the name of the new value
+ * @param lit (@c CxJsonLiteral) the type of literal
+ * @return (@c CxJsonValue*) the new value or @c NULL if allocation fails
+ * @see cxJsonObjPut()
+ * @see cxJsonCreateLiteral()
+ */
+#define cxJsonObjPutLiteral(obj, name, lit) cx_json_obj_put_literal(obj, cx_strcast(name), lit)
/**
* Recursively deallocates the memory of a JSON value.
*
* @param value the value
*/
-cx_attr_export
-void cxJsonValueFree(CxJsonValue *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_attr_export
-CxJsonStatus cxJsonNext(CxJson *json, CxJsonValue **value);
+cx_attr_nonnull cx_attr_access_w(2)
+CX_EXPORT CxJsonStatus cxJsonNext(CxJson *json, CxJsonValue **value);
/**
* Checks if the specified value is a JSON object.
* @retval false otherwise
*/
cx_attr_nonnull
-static inline bool cxJsonIsObject(const CxJsonValue *value) {
+CX_INLINE bool cxJsonIsObject(const CxJsonValue *value) {
return value->type == CX_JSON_OBJECT;
}
* @retval false otherwise
*/
cx_attr_nonnull
-static inline bool cxJsonIsArray(const CxJsonValue *value) {
+CX_INLINE bool cxJsonIsArray(const CxJsonValue *value) {
return value->type == CX_JSON_ARRAY;
}
* @retval false otherwise
*/
cx_attr_nonnull
-static inline bool cxJsonIsString(const CxJsonValue *value) {
+CX_INLINE bool cxJsonIsString(const CxJsonValue *value) {
return value->type == CX_JSON_STRING;
}
* @see cxJsonIsInteger()
*/
cx_attr_nonnull
-static inline bool cxJsonIsNumber(const CxJsonValue *value) {
+CX_INLINE bool cxJsonIsNumber(const CxJsonValue *value) {
return value->type == CX_JSON_NUMBER || value->type == CX_JSON_INTEGER;
}
* @see cxJsonIsNumber()
*/
cx_attr_nonnull
-static inline bool cxJsonIsInteger(const CxJsonValue *value) {
+CX_INLINE bool cxJsonIsInteger(const CxJsonValue *value) {
return value->type == CX_JSON_INTEGER;
}
* @see cxJsonIsNull()
*/
cx_attr_nonnull
-static inline bool cxJsonIsLiteral(const CxJsonValue *value) {
+CX_INLINE bool cxJsonIsLiteral(const CxJsonValue *value) {
return value->type == CX_JSON_LITERAL;
}
* @see cxJsonIsFalse()
*/
cx_attr_nonnull
-static inline bool cxJsonIsBool(const CxJsonValue *value) {
+CX_INLINE bool cxJsonIsBool(const CxJsonValue *value) {
return cxJsonIsLiteral(value) && value->value.literal != CX_JSON_NULL;
}
* @see cxJsonIsFalse()
*/
cx_attr_nonnull
-static inline bool cxJsonIsTrue(const CxJsonValue *value) {
+CX_INLINE bool cxJsonIsTrue(const CxJsonValue *value) {
return cxJsonIsLiteral(value) && value->value.literal == CX_JSON_TRUE;
}
* @see cxJsonIsTrue()
*/
cx_attr_nonnull
-static inline bool cxJsonIsFalse(const CxJsonValue *value) {
+CX_INLINE bool cxJsonIsFalse(const CxJsonValue *value) {
return cxJsonIsLiteral(value) && value->value.literal == CX_JSON_FALSE;
}
* @see cxJsonIsLiteral()
*/
cx_attr_nonnull
-static inline bool cxJsonIsNull(const CxJsonValue *value) {
+CX_INLINE bool cxJsonIsNull(const CxJsonValue *value) {
return cxJsonIsLiteral(value) && value->value.literal == CX_JSON_NULL;
}
* @return the value represented as C string
* @see cxJsonIsString()
*/
-cx_attr_nonnull
-cx_attr_returns_nonnull
-static inline char *cxJsonAsString(const CxJsonValue *value) {
- return value->value.string.ptr;
-}
+cx_attr_nonnull cx_attr_returns_nonnull
+CX_EXPORT char *cxJsonAsString(const CxJsonValue *value);
/**
* Obtains a UCX string from the given JSON value.
* @see cxJsonIsString()
*/
cx_attr_nonnull
-static inline cxstring cxJsonAsCxString(const CxJsonValue *value) {
- return cx_strcast(value->value.string);
-}
+CX_EXPORT cxstring cxJsonAsCxString(const CxJsonValue *value);
/**
* Obtains a mutable UCX string from the given JSON value.
* @see cxJsonIsString()
*/
cx_attr_nonnull
-static inline cxmutstr cxJsonAsCxMutStr(const CxJsonValue *value) {
- return value->value.string;
-}
+CX_EXPORT cxmutstr cxJsonAsCxMutStr(const CxJsonValue *value);
/**
* Obtains a double-precision floating-point value from the given JSON value.
* @see cxJsonIsNumber()
*/
cx_attr_nonnull
-static inline double cxJsonAsDouble(const CxJsonValue *value) {
- if (value->type == CX_JSON_INTEGER) {
- return (double) value->value.integer;
- } else {
- return value->value.number;
- }
-}
+CX_EXPORT double cxJsonAsDouble(const CxJsonValue *value);
/**
* Obtains a 64-bit signed integer from the given JSON value.
* @see cxJsonIsInteger()
*/
cx_attr_nonnull
-static inline int64_t cxJsonAsInteger(const CxJsonValue *value) {
- if (value->type == CX_JSON_INTEGER) {
- return value->value.integer;
- } else {
- return (int64_t) value->value.number;
- }
-}
+CX_EXPORT int64_t cxJsonAsInteger(const CxJsonValue *value);
/**
* Obtains a Boolean value from the given JSON value.
* @see cxJsonIsLiteral()
*/
cx_attr_nonnull
-static inline bool cxJsonAsBool(const CxJsonValue *value) {
+CX_INLINE bool cxJsonAsBool(const CxJsonValue *value) {
return value->value.literal == CX_JSON_TRUE;
}
* @see cxJsonIsArray()
*/
cx_attr_nonnull
-static inline size_t cxJsonArrSize(const CxJsonValue *value) {
+CX_INLINE size_t cxJsonArrSize(const CxJsonValue *value) {
return value->value.array.array_size;
}
* @return the value at the specified index
* @see cxJsonIsArray()
*/
-cx_attr_nonnull
-cx_attr_returns_nonnull
-cx_attr_export
-CxJsonValue *cxJsonArrGet(const CxJsonValue *value, size_t index);
+cx_attr_nonnull cx_attr_returns_nonnull
+CX_EXPORT CxJsonValue *cxJsonArrGet(const CxJsonValue *value, size_t index);
/**
* Removes an element from a JSON array.
* @see cxJsonIsArray()
*/
cx_attr_nonnull
-cx_attr_export
-CxJsonValue *cxJsonArrRemove(CxJsonValue *value, size_t index);
+CX_EXPORT 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);
+
+/**
+ * Returns the size of a JSON object.
+ *
+ * If the @p value is not a JSON object, the behavior is undefined.
+ *
+ * @param value the JSON value
+ * @return the size of the object, i.e., the number of key/value pairs
+ * @see cxJsonIsObject()
+ */
cx_attr_nonnull
-cx_attr_nodiscard
-cx_attr_export
-CxIterator cxJsonArrIter(const CxJsonValue *value);
+CX_INLINE size_t cxJsonObjSize(const CxJsonValue *value) {
+ return value->value.object.values_size;
+}
/**
* Returns an iterator over the JSON object members.
* @return an iterator over the object members
* @see cxJsonIsObject()
*/
-cx_attr_nonnull
-cx_attr_nodiscard
-cx_attr_export
-CxIterator cxJsonObjIter(const CxJsonValue *value);
+cx_attr_nonnull cx_attr_nodiscard
+CX_EXPORT CxIterator 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_attr_export
-CxJsonValue *cx_json_obj_get(const CxJsonValue *value, cxstring name);
+cx_attr_nonnull cx_attr_returns_nonnull
+CX_EXPORT CxJsonValue *cx_json_obj_get(const CxJsonValue *value, cxstring name);
/**
* Returns a value corresponding to a key in a JSON object.
* @return the value corresponding to the key or @c NULL when the key is not part of the object
*/
cx_attr_nonnull
-cx_attr_export
-CxJsonValue *cx_json_obj_remove(CxJsonValue *value, cxstring name);
+CX_EXPORT CxJsonValue *cx_json_obj_remove(CxJsonValue *value, cxstring name);
/**
* Removes and returns a value corresponding to a key in a JSON object.
* @see cxKvListAsMap()
* @see cxKvListAsList()
*/
-cx_attr_nodiscard
-cx_attr_malloc
-cx_attr_dealloc(cxListFree, 1)
-cx_attr_export
-CxList *cxKvListCreate(
- const CxAllocator *allocator,
- cx_compare_func comparator,
- size_t elem_size
-);
+cx_attr_nodiscard cx_attr_malloc cx_attr_dealloc(cxListFree, 1)
+CX_EXPORT CxList *cxKvListCreate(const CxAllocator *allocator,
+ cx_compare_func comparator, size_t elem_size);
/**
* 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(cxMapFree, 1)
-cx_attr_export
-CxMap *cxKvListCreateAsMap(
- const CxAllocator *allocator,
- cx_compare_func comparator,
- size_t elem_size
-);
+cx_attr_nodiscard cx_attr_malloc cx_attr_dealloc(cxMapFree, 1)
+CX_EXPORT CxMap *cxKvListCreateAsMap(const CxAllocator *allocator,
+ cx_compare_func comparator, size_t elem_size);
/**
* Allocates a linked list with a lookup-map for storing elements with @p elem_size bytes each.
* @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_attr_export
-CxList *cxKvListAsList(CxMap *map);
+cx_attr_nodiscard cx_attr_nonnull cx_attr_returns_nonnull
+CX_EXPORT 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() or cxKvListCreateSimple()
* @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_attr_export
-CxMap *cxKvListAsMap(CxList *list);
+cx_attr_nodiscard cx_attr_nonnull cx_attr_returns_nonnull
+CX_EXPORT CxMap *cxKvListAsMap(CxList *list);
/**
* Sets or updates the key of a list item.
* @see cxKvListSetKey()
*/
cx_attr_nonnull
-cx_attr_export
-int cx_kv_list_set_key(CxList *list, size_t index, CxHashKey key);
+CX_EXPORT 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.
* @see cxKvListInsert()
*/
cx_attr_nonnull
-cx_attr_export
-int cx_kv_list_insert(CxList *list, size_t index, CxHashKey key, void *value);
+CX_EXPORT int cx_kv_list_insert(CxList *list, size_t index, CxHashKey key, void *value);
/**
* Sets or updates the key of a list item.
* @retval non-zero the index is out of bounds
*/
cx_attr_nonnull
-cx_attr_export
-int cxKvListRemoveKey(CxList *list, size_t index);
+CX_EXPORT int cxKvListRemoveKey(CxList *list, size_t index);
/**
* Returns the key of a list item.
* @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_attr_export
-const CxHashKey *cxKvListGetKey(CxList *list, size_t index);
+CX_EXPORT const CxHashKey *cxKvListGetKey(CxList *list, size_t index);
/**
* Adds an item into the list and associates it with the specified key.
* Location of the payload (mandatory).
*/
off_t loc_data;
+ /**
+ * Location of extra data (optional).
+ * Negative when no extra data is requested.
+ * @see cx_linked_list_extra_data()
+ */
+ off_t loc_extra;
/**
* Additional bytes to allocate @em behind the payload (e.g. for metadata).
+ * @see cx_linked_list_extra_data()
*/
size_t extra_data_len;
/**
* @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_attr_export
-CxList *cxLinkedListCreate(
- const CxAllocator *allocator,
- cx_compare_func comparator,
- size_t elem_size
-);
+cx_attr_nodiscard cx_attr_malloc cx_attr_dealloc(cxListFree, 1)
+CX_EXPORT CxList *cxLinkedListCreate(const CxAllocator *allocator,
+ cx_compare_func comparator, size_t elem_size);
/**
* Allocates a linked list for storing elements with @p elem_size bytes each.
* @return (@c CxList*) the created list
*/
#define cxLinkedListCreateSimple(elem_size) \
- cxLinkedListCreate(NULL, NULL, elem_size)
+ cxLinkedListCreate(NULL, NULL, elem_size)
+
+/**
+ * Instructs the linked list to reserve extra data in each node.
+ *
+ * The extra data will be aligned and placed behind the element data.
+ * The exact location in the node is stored in the @c loc_extra field
+ * of the linked list.
+ *
+ * You should usually not use this function except when you are creating an
+ * own linked-list implementation that is based on the UCX linked list and
+ * needs to store extra data in each node.
+ *
+ * @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);
/**
* 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_attr_export
-void *cx_linked_list_at(
- const void *start,
- size_t start_index,
- ptrdiff_t loc_advance,
- size_t index
-);
+cx_attr_nonnull cx_attr_nodiscard
+CX_EXPORT void *cx_linked_list_at(const void *start,size_t start_index,
+ ptrdiff_t loc_advance, size_t index);
/**
* Finds the node containing an element within a linked list.
* @return a pointer to the found node or @c NULL if no matching node was found
*/
cx_attr_nonnull_arg(1, 4, 5)
-cx_attr_export
-void *cx_linked_list_find(
- const void *start,
- ptrdiff_t loc_advance,
- ptrdiff_t loc_data,
- cx_compare_func cmp_func,
- const void *elem,
- size_t *found_index
-);
+CX_EXPORT void *cx_linked_list_find(const void *start, ptrdiff_t loc_advance,
+ ptrdiff_t loc_data, cx_compare_func cmp_func, const void *elem,
+ size_t *found_index);
/**
* Finds the first node in a linked list.
* @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_attr_export
-void *cx_linked_list_first(
- const void *node,
- ptrdiff_t loc_prev
-);
+cx_attr_nonnull cx_attr_returns_nonnull
+CX_EXPORT 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_attr_export
-void *cx_linked_list_last(
- const void *node,
- ptrdiff_t loc_next
-);
+cx_attr_nonnull cx_attr_returns_nonnull
+CX_EXPORT void *cx_linked_list_last(const void *node, ptrdiff_t loc_next);
/**
* Finds the predecessor of a node in case it is not linked.
* @return the node or @c NULL if @p node has no predecessor
*/
cx_attr_nonnull
-cx_attr_export
-void *cx_linked_list_prev(
- const void *begin,
- ptrdiff_t loc_next,
- const void *node
-);
+CX_EXPORT void *cx_linked_list_prev(const void *begin, ptrdiff_t loc_next, const void *node);
/**
* Adds a new node to a linked list.
* @param new_node a pointer to the node that shall be appended
*/
cx_attr_nonnull_arg(5)
-cx_attr_export
-void cx_linked_list_add(
- void **begin,
- void **end,
- ptrdiff_t loc_prev,
- ptrdiff_t loc_next,
- void *new_node
-);
+CX_EXPORT 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 new_node a pointer to the node that shall be prepended
*/
cx_attr_nonnull_arg(5)
-cx_attr_export
-void cx_linked_list_prepend(
- void **begin,
- void **end,
- ptrdiff_t loc_prev,
- ptrdiff_t loc_next,
- void *new_node
-);
+CX_EXPORT 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_next the location of a @c next pointer within your node struct (required)
*/
cx_attr_nonnull
-cx_attr_export
-void cx_linked_list_link(
- void *left,
- void *right,
- ptrdiff_t loc_prev,
- ptrdiff_t loc_next
-);
+CX_EXPORT void cx_linked_list_link(void *left, void *right, ptrdiff_t loc_prev, ptrdiff_t loc_next);
/**
* Unlinks two nodes.
* @param loc_next the location of a @c next pointer within your node struct (required)
*/
cx_attr_nonnull
-cx_attr_export
-void cx_linked_list_unlink(
- void *left,
- void *right,
- ptrdiff_t loc_prev,
- ptrdiff_t loc_next
-);
+CX_EXPORT 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 new_node a pointer to the node that shall be inserted
*/
cx_attr_nonnull_arg(6)
-cx_attr_export
-void cx_linked_list_insert(
- void **begin,
- void **end,
- ptrdiff_t loc_prev,
- ptrdiff_t loc_next,
- void *node,
- void *new_node
-);
+CX_EXPORT void cx_linked_list_insert(void **begin, void **end,
+ ptrdiff_t loc_prev, ptrdiff_t loc_next, void *node, void *new_node);
/**
* Inserts a chain of nodes after a given node of a linked list.
* @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_attr_export
-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
-);
+CX_EXPORT 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);
/**
* Inserts a node into a sorted linked list.
* @param cmp_func a compare function that will receive the node pointers
*/
cx_attr_nonnull_arg(1, 5, 6)
-cx_attr_export
-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
-);
+CX_EXPORT 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);
/**
* Inserts a chain of nodes into a sorted linked list.
* @param cmp_func a compare function that will receive the node pointers
*/
cx_attr_nonnull_arg(1, 5, 6)
-cx_attr_export
-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
-);
+CX_EXPORT 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);
/**
* Inserts a node into a sorted linked list if no other node with the same value already exists.
* @retval non-zero when a node with the same value already exists
*/
cx_attr_nonnull_arg(1, 5, 6)
-cx_attr_export
-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
-);
+CX_EXPORT 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);
/**
* Inserts a chain of nodes into a sorted linked list, avoiding duplicates.
* @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_attr_export
-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
-);
+cx_attr_nonnull_arg(1, 5, 6) cx_attr_nodiscard
+CX_EXPORT 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);
/**
* Removes a chain of nodes from the linked list.
* @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_attr_export
-size_t cx_linked_list_remove_chain(
- void **begin,
- void **end,
- ptrdiff_t loc_prev,
- ptrdiff_t loc_next,
- void *node,
- size_t num
-);
+CX_EXPORT size_t cx_linked_list_remove_chain(void **begin, void **end,
+ ptrdiff_t loc_prev, ptrdiff_t loc_next, void *node, size_t num);
/**
* Removes a node from the linked list.
* @param node the node to remove
*/
cx_attr_nonnull_arg(5)
-static inline void cx_linked_list_remove(
- void **begin,
- void **end,
- ptrdiff_t loc_prev,
- ptrdiff_t loc_next,
- void *node
-) {
- cx_linked_list_remove_chain(begin, end, loc_prev, loc_next, node, 1);
-}
+CX_EXPORT void cx_linked_list_remove(void **begin, void **end,
+ ptrdiff_t loc_prev, ptrdiff_t loc_next, void *node);
/**
* Determines the size of a linked list starting with @p node.
* @return the size of the list or zero if @p node is @c NULL
*/
cx_attr_nodiscard
-cx_attr_export
-size_t cx_linked_list_size(
- const void *node,
- ptrdiff_t loc_next
-);
+CX_EXPORT size_t cx_linked_list_size(const void *node, ptrdiff_t loc_next);
/**
* Sorts a linked list based on a comparison function.
* @param cmp_func the compare function defining the sort order
*/
cx_attr_nonnull_arg(1, 6)
-cx_attr_export
-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
-);
+CX_EXPORT 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);
/**
* 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_attr_export
-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
-);
+CX_EXPORT 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);
/**
* Reverses the order of the nodes in a linked list.
* @param loc_next the location of a @c next pointer within your node struct (required)
*/
cx_attr_nonnull_arg(1)
-cx_attr_export
-void cx_linked_list_reverse(
- void **begin,
- void **end,
- ptrdiff_t loc_prev,
- ptrdiff_t loc_next
-);
+CX_EXPORT void cx_linked_list_reverse(void **begin, void **end, ptrdiff_t loc_prev, ptrdiff_t loc_next);
#ifdef __cplusplus
} // extern "C"
#include "common.h"
#include "collection.h"
-#include <assert.h>
-
#ifdef __cplusplus
extern "C" {
#endif
* The data pointer may be @c NULL, in which case the function shall only allocate memory.
* Returns a pointer to the allocated memory or @c NULL if allocation fails.
*/
- void *(*insert_element)(
- struct cx_list_s *list,
- size_t index,
- const void *data
- );
+ void *(*insert_element)(struct cx_list_s *list, size_t index, const void *data);
/**
* Member function for inserting multiple elements.
*
+ * The data pointer may be @c NULL, in which case the function shall only allocate memory.
+ * Returns the number of successfully inserted or allocated elements.
+ *
* @see cx_list_default_insert_array()
*/
- size_t (*insert_array)(
- struct cx_list_s *list,
- size_t index,
- const void *data,
- size_t n
- );
+ size_t (*insert_array)(struct cx_list_s *list, size_t index, const void *data, size_t n);
/**
* Member function for inserting sorted elements into a sorted list.
+ * Returns the number of successfully inserted elements.
*
* @see cx_list_default_insert_sorted()
*/
- size_t (*insert_sorted)(
- struct cx_list_s *list,
- const void *sorted_data,
- size_t n
- );
+ size_t (*insert_sorted)(struct cx_list_s *list, const void *sorted_data, size_t n);
/**
* Member function for inserting multiple elements if they do not exist.
- *
+ * Implementations shall return the number of successfully processed elements
+ * (including those which were not added because they are already contained).
* @see cx_list_default_insert_unique()
*/
- size_t (*insert_unique)(
- struct cx_list_s *list,
- const void *sorted_data,
- size_t n
- );
+ size_t (*insert_unique)(struct cx_list_s *list, const void *sorted_data, size_t n);
/**
* Member function for inserting an element relative to an iterator position.
*/
- int (*insert_iter)(
- struct cx_iterator_s *iter,
- const void *elem,
- int prepend
- );
+ int (*insert_iter)(struct cx_iterator_s *iter, const void *elem, int prepend);
/**
* Member function for removing elements.
* The function SHALL return the actual number of elements removed, which
* might be lower than @p num when going out of bounds.
*/
- size_t (*remove)(
- struct cx_list_s *list,
- size_t index,
- size_t num,
- void *targetbuf
- );
+ size_t (*remove)(struct cx_list_s *list, size_t index, size_t num, void *targetbuf);
/**
* Member function for removing all elements.
*
* @see cx_list_default_swap()
*/
- int (*swap)(
- struct cx_list_s *list,
- size_t i,
- size_t j
- );
+ int (*swap)(struct cx_list_s *list, size_t i, size_t j);
/**
* Member function for element lookup.
*/
- void *(*at)(
- const struct cx_list_s *list,
- size_t index
- );
+ void *(*at)(const struct cx_list_s *list, size_t index);
/**
* Member function for finding and optionally removing an element.
*/
- size_t (*find_remove)(
- struct cx_list_s *list,
- const void *elem,
- bool remove
- );
+ size_t (*find_remove)(struct cx_list_s *list, const void *elem, bool remove);
/**
* Member function for sorting the list.
* to another list of the same type.
* If set to @c NULL, the comparison won't be optimized.
*/
- int (*compare)(
- const struct cx_list_s *list,
- const struct cx_list_s *other
- );
+ int (*compare)(const struct cx_list_s *list, const struct cx_list_s *other);
/**
* Member function for reversing the order of the items.
*/
void (*reverse)(struct cx_list_s *list);
+ /**
+ * Optional member function for changing the capacity.
+ * If the list does not support overallocation, this can be set to @c NULL.
+ */
+ int (*change_capacity)(struct cx_list_s *list, size_t new_capacity);
+
/**
* Member function for returning an iterator pointing to the specified index.
*/
- struct cx_iterator_s (*iterator)(
- const struct cx_list_s *list,
- size_t index,
- bool backward
- );
+ struct cx_iterator_s (*iterator)(const struct cx_list_s *list, size_t index, bool backward);
};
/**
* You can use this as a placeholder for initializing CxList pointers
* for which you do not want to reserve memory right from the beginning.
*/
-cx_attr_export
-extern CxList *const cxEmptyList;
+CX_EXPORT extern CxList *const cxEmptyList;
/**
* Default implementation of an array insert.
* @return the number of elements actually inserted
*/
cx_attr_nonnull
-cx_attr_export
-size_t cx_list_default_insert_array(
- struct cx_list_s *list,
- size_t index,
- const void *data,
- size_t n
-);
+CX_EXPORT size_t cx_list_default_insert_array(struct cx_list_s *list,
+ size_t index, const void *data, size_t n);
/**
* Default implementation of a sorted insert.
* @return the number of elements actually inserted
*/
cx_attr_nonnull
-cx_attr_export
-size_t cx_list_default_insert_sorted(
- struct cx_list_s *list,
- const void *sorted_data,
- size_t n
-);
+CX_EXPORT size_t cx_list_default_insert_sorted(struct cx_list_s *list,
+ const void *sorted_data, size_t n);
/**
* Default implementation of an array insert where only elements are inserted when they don't exist in the list.
* @return the number of elements from the @p sorted_data that are definitely present in the list after this call
*/
cx_attr_nonnull
-cx_attr_export
-size_t cx_list_default_insert_unique(
- struct cx_list_s *list,
- const void *sorted_data,
- size_t n
-);
+CX_EXPORT size_t cx_list_default_insert_unique(struct cx_list_s *list,
+ const void *sorted_data, size_t n);
/**
* Default unoptimized sort implementation.
* @param list the list that shall be sorted
*/
cx_attr_nonnull
-cx_attr_export
-void cx_list_default_sort(struct cx_list_s *list);
+CX_EXPORT void cx_list_default_sort(struct cx_list_s *list);
/**
* Default unoptimized swap implementation.
* allocation for the temporary buffer fails
*/
cx_attr_nonnull
-cx_attr_export
-int cx_list_default_swap(struct cx_list_s *list, size_t i, size_t j);
+CX_EXPORT int cx_list_default_swap(struct cx_list_s *list, size_t i, size_t j);
/**
* Initializes a list struct.
* @param elem_size the size of one element
*/
cx_attr_nonnull_arg(1, 2, 3)
-cx_attr_export
-void cx_list_init(
- struct cx_list_s *list,
- struct cx_list_class_s *cl,
- const struct cx_allocator_s *allocator,
- cx_compare_func comparator,
- size_t elem_size
-);
+CX_EXPORT void cx_list_init(struct cx_list_s *list,
+ struct cx_list_class_s *cl, const struct cx_allocator_s *allocator,
+ cx_compare_func comparator, size_t elem_size);
/**
* Returns the number of elements currently stored in the list.
* @return the number of currently stored elements
*/
cx_attr_nonnull
-static inline size_t cxListSize(const CxList *list) {
- return list->collection.size;
-}
+CX_EXPORT size_t cxListSize(const CxList *list);
/**
* Adds an item to the end of the list.
* @see cxListEmplace()
*/
cx_attr_nonnull
-static inline int cxListAdd(
- CxList *list,
- const void *elem
-) {
- list->collection.sorted = false;
- return list->cl->insert_element(list, list->collection.size, elem) == NULL;
-}
+CX_EXPORT int cxListAdd(CxList *list, const void *elem);
/**
* Adds multiple items to the end of the list.
* @param array a pointer to the elements to add
* @param n the number of elements to add
* @return the number of added elements
+ * @see cxListEmplaceArray()
*/
cx_attr_nonnull
-static inline size_t cxListAddArray(
- CxList *list,
- const void *array,
- size_t n
-) {
- list->collection.sorted = false;
- return list->cl->insert_array(list, list->collection.size, array, n);
-}
+CX_EXPORT size_t cxListAddArray(CxList *list, const void *array, size_t n);
/**
* Inserts an item at the specified index.
* @see cxListEmplaceAt()
*/
cx_attr_nonnull
-static inline int cxListInsert(
- CxList *list,
- size_t index,
- const void *elem
-) {
- list->collection.sorted = false;
- return list->cl->insert_element(list, index, elem) == NULL;
-}
+CX_EXPORT 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.
* @param index the index where to emplace the element
* @return a pointer to the allocated memory; @c NULL when the operation fails, or the index is out-of-bounds
* @see cxListEmplace()
+ * @see cxListEmplaceArrayAt()
* @see cxListInsert()
*/
cx_attr_nonnull
-static inline void *cxListEmplaceAt(CxList *list, size_t index) {
- list->collection.sorted = false;
- return list->cl->insert_element(list, index, NULL);
-}
-
+CX_EXPORT 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 cxListAdd()
*/
cx_attr_nonnull
-static inline void *cxListEmplace(CxList *list) {
- list->collection.sorted = false;
- return list->cl->insert_element(list, list->collection.size, NULL);
-}
+CX_EXPORT void *cxListEmplace(CxList *list);
+
+/**
+ * Allocates memory for multiple elements and returns an iterator.
+ *
+ * The iterator will only iterate over the successfully allocated elements.
+ * The @c elem_count attribute is set to that number, and the @c index attribute
+ * will range from zero to @c elem_count minus one.
+ *
+ * @remark When the list is storing pointers, the iterator will iterate over
+ * the @c void** elements.
+ *
+ * @param list the list
+ * @param index the index where to insert the new data
+ * @param n the number of elements for which to allocate the memory
+ * @return an iterator, iterating over the new memory
+ * @see cxListEmplaceAt()
+ * @see cxListInsertArray()
+ */
+cx_attr_nonnull
+CX_EXPORT CxIterator cxListEmplaceArrayAt(CxList *list, size_t index, size_t n);
+
+/**
+ * Allocates memory for multiple elements and returns an iterator.
+ *
+ * The iterator will only iterate over the successfully allocated elements.
+ * The @c elem_count attribute is set to that number, and the @c index attribute
+ * will range from zero to @c elem_count minus one.
+ *
+ * @remark When the list is storing pointers, the iterator will iterate over
+ * the @c void** elements.
+ *
+ * @param list the list
+ * @param n the number of elements for which to allocate the memory
+ * @return an iterator, iterating over the new memory
+ * @see cxListEmplace()
+ * @see cxListAddArray()
+ */
+cx_attr_nonnull
+CX_EXPORT CxIterator cxListEmplaceArray(CxList *list, size_t n);
/**
* Inserts an item into a sorted list.
* @retval non-zero memory allocation failure
*/
cx_attr_nonnull
-static inline int cxListInsertSorted(
- CxList *list,
- const void *elem
-) {
- assert(list->collection.sorted || list->collection.size == 0);
- list->collection.sorted = true;
- const void *data = list->collection.store_pointer ? &elem : elem;
- return list->cl->insert_sorted(list, data, 1) == 0;
-}
+CX_EXPORT int cxListInsertSorted(CxList *list, const void *elem);
/**
- * Inserts an item into a sorted list if it does not exist.
+ * Inserts an item into a list if it does not exist.
*
- * If the list is not sorted already, the behavior is undefined.
+ * If the list is not sorted already, this function will check all elements
+ * and append the new element when it was not found.
+ * It is strongly recommended to use this function only on sorted lists, where
+ * the element, if it is not contained, is inserted at the correct position.
*
* @param list the list
* @param elem a pointer to the element to add
* @retval non-zero memory allocation failure
*/
cx_attr_nonnull
-static inline int cxListInsertUnique(
- CxList *list,
- const void *elem
-) {
- assert(list->collection.sorted || list->collection.size == 0);
- list->collection.sorted = true;
- const void *data = list->collection.store_pointer ? &elem : elem;
- return list->cl->insert_unique(list, data, 1) == 0;
-}
+CX_EXPORT int cxListInsertUnique(CxList *list, const void *elem);
/**
* Inserts multiple items to the list at the specified index.
* @param array a pointer to the elements to add
* @param n the number of elements to add
* @return the number of added elements
+ * @see cxListEmplaceArrayAt()
*/
cx_attr_nonnull
-static inline size_t cxListInsertArray(
- CxList *list,
- size_t index,
- const void *array,
- size_t n
-) {
- list->collection.sorted = false;
- return list->cl->insert_array(list, index, array, n);
-}
+CX_EXPORT size_t cxListInsertArray(CxList *list, size_t index, const void *array, size_t n);
/**
* Inserts a sorted array into a sorted list.
* @return the number of added elements
*/
cx_attr_nonnull
-static inline size_t cxListInsertSortedArray(
- CxList *list,
- const void *array,
- size_t n
-) {
- assert(list->collection.sorted || list->collection.size == 0);
- list->collection.sorted = true;
- return list->cl->insert_sorted(list, array, n);
-}
+CX_EXPORT size_t cxListInsertSortedArray(CxList *list, const void *array, size_t n);
/**
- * Inserts a sorted array into a sorted list, skipping duplicates.
+ * Inserts an array into a list, skipping duplicates.
+ *
+ * The @p list does not need to be sorted (in contrast to cxListInsertSortedArray()).
+ * But it is strongly recommended to use this function only on sorted lists,
+ * because otherwise it will fall back to an inefficient algorithm which inserts
+ * all elements one by one.
+ * If the @p list is not sorted, the @p array also does not need to be sorted.
+ * But when the @p list is sorted, the @p array must also be sorted.
*
* This method is usually more efficient than inserting each element separately
* because consecutive chunks of sorted data are inserted in one pass.
* If this list is storing pointers instead of objects @p array is expected to
* be an array of pointers.
*
- * If the list is not sorted already, the behavior is undefined.
- * This is also the case when the @p array is not sorted.
- *
* @param list the list
* @param array a pointer to the elements to add
* @param n the number of elements to add
* @return the number of elements from the @p sorted_data that are definitely present in the list after this call
*/
cx_attr_nonnull
-static inline size_t cxListInsertUniqueArray(
- CxList *list,
- const void *array,
- size_t n
-) {
- assert(list->collection.sorted || list->collection.size == 0);
- list->collection.sorted = true;
- return list->cl->insert_unique(list, array, n);
-}
+CX_EXPORT size_t cxListInsertUniqueArray(CxList *list, const void *array, size_t n);
/**
* Inserts an element after the current location of the specified iterator.
* @see cxListInsertBefore()
*/
cx_attr_nonnull
-static inline int cxListInsertAfter(
- CxIterator *iter,
- const void *elem
-) {
- CxList* list = (CxList*)iter->src_handle.m;
- list->collection.sorted = false;
- return list->cl->insert_iter(iter, elem, 0);
-}
+CX_EXPORT int cxListInsertAfter(CxIterator *iter, const void *elem);
/**
* Inserts an element before the current location of the specified iterator.
* @see cxListInsertAfter()
*/
cx_attr_nonnull
-static inline int cxListInsertBefore(
- CxIterator *iter,
- const void *elem
-) {
- CxList* list = (CxList*)iter->src_handle.m;
- list->collection.sorted = false;
- return list->cl->insert_iter(iter, elem, 1);
-}
+CX_EXPORT int cxListInsertBefore(CxIterator *iter, const void *elem);
/**
* Removes the element at the specified index.
* @retval non-zero index out of bounds
*/
cx_attr_nonnull
-static inline int cxListRemove(
- CxList *list,
- size_t index
-) {
- return list->cl->remove(list, index, 1, NULL) == 0;
-}
+CX_EXPORT 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)
-static inline int cxListRemoveAndGet(
- CxList *list,
- size_t index,
- void *targetbuf
-) {
- return list->cl->remove(list, index, 1, targetbuf) == 0;
-}
+cx_attr_nonnull cx_attr_access_w(3)
+CX_EXPORT 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)
-static inline int cxListRemoveAndGetFirst(
- CxList *list,
- void *targetbuf
-) {
- return list->cl->remove(list, 0, 1, targetbuf) == 0;
-}
+cx_attr_nonnull cx_attr_access_w(2)
+CX_EXPORT 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)
-static inline int cxListRemoveAndGetLast(
- CxList *list,
- void *targetbuf
-) {
- // note: index may wrap - member function will catch that
- return list->cl->remove(list, list->collection.size - 1, 1, targetbuf) == 0;
-}
+cx_attr_nonnull cx_attr_access_w(2)
+CX_EXPORT int cxListRemoveAndGetLast(CxList *list, void *targetbuf);
/**
* Removes and returns the last element of the list.
* @return the actual number of removed elements
*/
cx_attr_nonnull
-static inline size_t cxListRemoveArray(
- CxList *list,
- size_t index,
- size_t num
-) {
- return list->cl->remove(list, index, num, NULL);
-}
+CX_EXPORT 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)
-static inline size_t cxListRemoveArrayAndGet(
- CxList *list,
- size_t index,
- size_t num,
- void *targetbuf
-) {
- return list->cl->remove(list, index, num, targetbuf);
-}
+cx_attr_nonnull cx_attr_access_w(4)
+CX_EXPORT 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
-static inline void cxListClear(CxList *list) {
- list->cl->clear(list);
- list->collection.sorted = true; // empty lists are always sorted
-}
+CX_EXPORT void cxListClear(CxList *list);
/**
* Swaps two items in the list.
* or the swap needed extra memory, but allocation failed
*/
cx_attr_nonnull
-static inline int cxListSwap(
- CxList *list,
- size_t i,
- size_t j
-) {
- list->collection.sorted = false;
- return list->cl->swap(list, i, j);
-}
+CX_EXPORT int cxListSwap(CxList *list, size_t i, size_t j);
/**
* Returns a pointer to the element at the specified index.
* @return a pointer to the element or @c NULL if the index is out of bounds
*/
cx_attr_nonnull
-static inline void *cxListAt(
- const CxList *list,
- size_t index
-) {
- return list->cl->at(list, index);
-}
+CX_EXPORT void *cxListAt(const CxList *list, size_t index);
/**
* Returns a pointer to the first element.
* @return a pointer to the first element or @c NULL if the list is empty
*/
cx_attr_nonnull
-static inline void *cxListFirst(const CxList *list) {
- return list->cl->at(list, 0);
-}
+CX_EXPORT void *cxListFirst(const CxList *list);
/**
* Returns a pointer to the last element.
* @return a pointer to the last element or @c NULL if the list is empty
*/
cx_attr_nonnull
-static inline void *cxListLast(const CxList *list) {
- return list->cl->at(list, list->collection.size - 1);
-}
+CX_EXPORT void *cxListLast(const CxList *list);
/**
- * Sets the element at the specified index in the list
+ * Sets the element at the specified index in the list.
+ *
+ * This overwrites the element in-place without calling any destructor
+ * on the overwritten element.
*
* @param list the list to set the element in
* @param index the index to set the element at
* @retval non-zero when index is out of bounds
*/
cx_attr_nonnull
-cx_attr_export
-int cxListSet(
- CxList *list,
- size_t index,
- const void *elem
-);
+CX_EXPORT int cxListSet(CxList *list, size_t index, const void *elem);
/**
* Returns an iterator pointing to the item at the specified index.
* @return a new iterator
*/
cx_attr_nodiscard
-static inline CxIterator cxListIteratorAt(
- const CxList *list,
- size_t index
-) {
- if (list == NULL) list = cxEmptyList;
- return list->cl->iterator(list, index, false);
-}
+CX_EXPORT CxIterator cxListIteratorAt(const CxList *list, size_t index);
/**
* Returns a backwards iterator pointing to the item at the specified index.
* @return a new iterator
*/
cx_attr_nodiscard
-static inline CxIterator cxListBackwardsIteratorAt(
- const CxList *list,
- size_t index
-) {
- if (list == NULL) list = cxEmptyList;
- return list->cl->iterator(list, index, true);
-}
-
-/**
- * Returns a mutating iterator pointing to the item at the specified index.
- *
- * The returned iterator is position-aware.
- *
- * If the index is out of range or @p list is @c NULL, a past-the-end iterator will be returned.
- *
- * @param list the list
- * @param index the index where the iterator shall point at
- * @return a new iterator
- */
-cx_attr_nodiscard
-cx_attr_export
-CxIterator cxListMutIteratorAt(
- CxList *list,
- size_t index
-);
-
-/**
- * Returns a mutating backwards iterator pointing to the item at the
- * specified index.
- *
- * The returned iterator is position-aware.
- *
- * If the index is out of range or @p list is @c NULL, a past-the-end iterator will be returned.
- *
- * @param list the list
- * @param index the index where the iterator shall point at
- * @return a new iterator
- */
-cx_attr_nodiscard
-cx_attr_export
-CxIterator cxListMutBackwardsIteratorAt(
- CxList *list,
- size_t index
-);
+CX_EXPORT CxIterator cxListBackwardsIteratorAt(const CxList *list, size_t index);
/**
* Returns an iterator pointing to the first item of the list.
* @return a new iterator
*/
cx_attr_nodiscard
-static inline CxIterator cxListIterator(const CxList *list) {
- if (list == NULL) list = cxEmptyList;
- return list->cl->iterator(list, 0, false);
-}
-
-/**
- * Returns a mutating iterator pointing to the first item of the list.
- *
- * The returned iterator is position-aware.
- *
- * If the list is empty or @c NULL, a past-the-end iterator will be returned.
- *
- * @param list the list
- * @return a new iterator
- */
-cx_attr_nodiscard
-static inline CxIterator cxListMutIterator(CxList *list) {
- if (list == NULL) list = cxEmptyList;
- return cxListMutIteratorAt(list, 0);
-}
-
+CX_EXPORT CxIterator cxListIterator(const CxList *list);
/**
* Returns a backwards iterator pointing to the last item of the list.
* @return a new iterator
*/
cx_attr_nodiscard
-static inline CxIterator cxListBackwardsIterator(const CxList *list) {
- if (list == NULL) list = cxEmptyList;
- return list->cl->iterator(list, list->collection.size - 1, true);
-}
-
-/**
- * Returns a mutating backwards iterator pointing to the last item of the list.
- *
- * The returned iterator is position-aware.
- *
- * If the list is empty or @c NULL, a past-the-end iterator will be returned.
- *
- * @param list the list
- * @return a new iterator
- */
-cx_attr_nodiscard
-static inline CxIterator cxListMutBackwardsIterator(CxList *list) {
- if (list == NULL) list = cxEmptyList;
- return cxListMutBackwardsIteratorAt(list, list->collection.size - 1);
-}
+CX_EXPORT 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
-static inline size_t cxListFind(
- const CxList *list,
- const void *elem
-) {
- return list->cl->find_remove((CxList*)list, elem, false);
-}
+cx_attr_nonnull cx_attr_nodiscard
+CX_EXPORT 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
-static inline bool cxListContains(
- const CxList* list,
- const void* elem
-) {
- return list->cl->find_remove((CxList*)list, elem, false) < list->collection.size;
-}
+cx_attr_nonnull cx_attr_nodiscard
+CX_EXPORT 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
-static inline bool cxListIndexValid(const CxList *list, size_t index) {
- return index < list->collection.size;
-}
+cx_attr_nonnull cx_attr_nodiscard
+CX_EXPORT bool cxListIndexValid(const CxList *list, size_t index);
/**
* Removes and returns the index of the first element that equals @p elem.
* @see cxListIndexValid()
*/
cx_attr_nonnull
-static inline size_t cxListFindRemove(
- CxList *list,
- const void *elem
-) {
- return list->cl->find_remove(list, elem, true);
-}
+CX_EXPORT size_t cxListFindRemove(CxList *list, const void *elem);
/**
* Sorts the list.
* @param list the list
*/
cx_attr_nonnull
-static inline void cxListSort(CxList *list) {
- if (list->collection.sorted) return;
- list->cl->sort(list);
- list->collection.sorted = true;
-}
+CX_EXPORT void cxListSort(CxList *list);
/**
* Reverses the order of the items.
* @param list the list
*/
cx_attr_nonnull
-static inline void cxListReverse(CxList *list) {
- // still sorted, but not according to the cmp_func
- list->collection.sorted = false;
- list->cl->reverse(list);
-}
+CX_EXPORT void cxListReverse(CxList *list);
/**
* Compares a list to another list of the same type.
* @param list the list
* @param other the list to compare to
* @retval zero both lists are equal element wise
- * @retval negative the first list is smaller
+ * @retval negative the first list is smaller,
* or the first non-equal element in the first list is smaller
* @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_attr_export
-int cxListCompare(
- const CxList *list,
- const CxList *other
-);
+cx_attr_nonnull cx_attr_nodiscard
+CX_EXPORT 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_attr_export
-void cxListFree(CxList *list);
+CX_EXPORT void cxListFree(CxList *list);
+
+
+/**
+ * Performs a deep clone of one list into another.
+ *
+ * If the destination list already contains elements, the cloned elements
+ * are appended to that list.
+ *
+ * @attention If the cloned elements need to be destroyed by a destructor
+ * function, you must make sure that the destination list also uses this
+ * destructor function.
+ *
+ * @param dst the destination list
+ * @param src the source list
+ * @param clone_func the clone function for the elements
+ * @param clone_allocator the allocator that is passed to the clone function
+ * @param data optional additional data that is passed to the clone function
+ * @retval zero when all elements were successfully cloned
+ * @retval non-zero when an allocation error occurred
+ * @see cxListCloneSimple()
+ */
+cx_attr_nonnull_arg(1, 2, 3)
+CX_EXPORT int cxListClone(CxList *dst, const CxList *src,
+ cx_clone_func clone_func, const CxAllocator *clone_allocator, void *data);
+
+/**
+ * Clones elements from a list only if they are not present in another list.
+ *
+ * If the @p minuend does not contain duplicates, this is equivalent to adding
+ * the set difference to the destination list.
+ *
+ * This function is optimized for the case when both the @p minuend and the
+ * @p subtrahend are sorted.
+ *
+ * @param dst the destination list
+ * @param minuend the list to subtract elements from
+ * @param subtrahend the elements that shall be subtracted
+ * @param clone_func the clone function for the elements
+ * @param clone_allocator the allocator that is passed to the clone function
+ * @param data optional additional data that is passed to the clone function
+ * @retval zero when the elements were successfully cloned
+ * @retval non-zero when an allocation error occurred
+ * @see cxListDifferenceSimple()
+ */
+cx_attr_nonnull_arg(1, 2, 3, 4)
+CX_EXPORT int cxListDifference(CxList *dst,
+ const CxList *minuend, const CxList *subtrahend,
+ cx_clone_func clone_func, const CxAllocator *clone_allocator, void *data);
+
+/**
+ * Clones elements from a list only if they are also present in another list.
+ *
+ * This function is optimized for the case when both the @p src and the
+ * @p other list are sorted.
+ *
+ * If the destination list already contains elements, the intersection is appended
+ * to that list.
+ *
+ * @param dst the destination list
+ * @param src the list to clone the elements from
+ * @param other the list to check the elements for existence
+ * @param clone_func the clone function for the elements
+ * @param clone_allocator the allocator that is passed to the clone function
+ * @param data optional additional data that is passed to the clone function
+ * @retval zero when the elements were successfully cloned
+ * @retval non-zero when an allocation error occurred
+ * @see cxListIntersectionSimple()
+ */
+cx_attr_nonnull_arg(1, 2, 3, 4)
+CX_EXPORT int cxListIntersection(CxList *dst, const CxList *src, const CxList *other,
+ cx_clone_func clone_func, const CxAllocator *clone_allocator, void *data);
+
+/**
+ * Performs a deep clone of one list into another, skipping duplicates.
+ *
+ * This function is optimized for the case when both the @p src and the
+ * @p other list are sorted.
+ * In that case, the union will also be sorted.
+ *
+ * If the destination list already contains elements, the union is appended
+ * to that list. In that case the destination is not necessarily sorted.
+ *
+ * @param dst the destination list
+ * @param src the primary source list
+ * @param other the other list, where elements are only cloned from
+ * when they are not in @p src
+ * @param clone_func the clone function for the elements
+ * @param clone_allocator the allocator that is passed to the clone function
+ * @param data optional additional data that is passed to the clone function
+ * @retval zero when the elements were successfully cloned
+ * @retval non-zero when an allocation error occurred
+ * @see cxListUnionSimple()
+ */
+cx_attr_nonnull_arg(1, 2, 3, 4)
+CX_EXPORT int cxListUnion(CxList *dst, const CxList *src, const CxList *other,
+ cx_clone_func clone_func, const CxAllocator *clone_allocator, void *data);
+
+/**
+ * Performs a shallow clone of one list into another.
+ *
+ * This function uses the default allocator, if needed, and performs
+ * shallow clones with @c memcpy().
+ *
+ * If the destination list already contains elements, the cloned elements
+ * are appended to that list.
+ *
+ * @attention If the cloned elements need to be destroyed by a destructor
+ * function, you must make sure that the destination list also uses this
+ * destructor function.
+ *
+ * @param dst the destination list
+ * @param src the source list
+ * @retval zero when all elements were successfully cloned
+ * @retval non-zero when an allocation error occurred
+ * @see cxListClone()
+ */
+cx_attr_nonnull
+CX_EXPORT int cxListCloneSimple(CxList *dst, const CxList *src);
+
+/**
+ * Clones elements from a list only if they are not present in another list.
+ *
+ * This function uses the default allocator, if needed, and performs
+ * shallow clones with @c memcpy().
+ *
+ * If the @p minuend does not contain duplicates, this is equivalent to adding
+ * the set difference to the destination list.
+ *
+ * This function is optimized for the case when both the @p minuend and the
+ * @p subtrahend are sorted.
+ *
+ * @param dst the destination list
+ * @param minuend the list to subtract elements from
+ * @param subtrahend the elements that shall be subtracted
+ * @retval zero when the elements were successfully cloned
+ * @retval non-zero when an allocation error occurred
+ * @see cxListDifference()
+ */
+cx_attr_nonnull
+CX_EXPORT int cxListDifferenceSimple(CxList *dst,
+ const CxList *minuend, const CxList *subtrahend);
+
+/**
+ * Clones elements from a list only if they are also present in another list.
+ *
+ * This function uses the default allocator, if needed, and performs
+ * shallow clones with @c memcpy().
+ *
+ * This function is optimized for the case when both the @p src and the
+ * @p other list are sorted.
+ *
+ * If the destination list already contains elements, the intersection is appended
+ * to that list.
+ *
+ * @param dst the destination list
+ * @param src the list to clone the elements from
+ * @param other the list to check the elements for existence
+ * @retval zero when the elements were successfully cloned
+ * @retval non-zero when an allocation error occurred
+ * @see cxListIntersection()
+ */
+cx_attr_nonnull
+CX_EXPORT int cxListIntersectionSimple(CxList *dst, const CxList *src, const CxList *other);
+
+/**
+ * Performs a deep clone of one list into another, skipping duplicates.
+ *
+ * This function uses the default allocator, if needed, and performs
+ * shallow clones with @c memcpy().
+ *
+ * This function is optimized for the case when both the @p src and the
+ * @p other list are sorted.
+ * In that case, the union will also be sorted.
+ *
+ * If the destination list already contains elements, the union is appended
+ * to that list. In that case the destination is not necessarily sorted.
+ *
+ * @param dst the destination list
+ * @param src the primary source list
+ * @param other the other list, where elements are only cloned from
+ * when they are not in @p src
+ * @retval zero when the elements were successfully cloned
+ * @retval non-zero when an allocation error occurred
+ * @see cxListUnion()
+ */
+cx_attr_nonnull
+CX_EXPORT int cxListUnionSimple(CxList *dst, const CxList *src, const CxList *other);
+/**
+ * Asks the list to reserve enough memory for a given total number of elements.
+ *
+ * List implementations are free to choose if reserving memory upfront makes
+ * sense.
+ * For example, array-based implementations usually do support reserving memory
+ * for additional elements while linked lists usually don't.
+ *
+ * @note When the requested capacity is smaller than the current size,
+ * this function returns zero without performing any action.
+ *
+ * @param list the list
+ * @param capacity the expected total number of elements
+ * @retval zero on success or when overallocation is not supported
+ * @retval non-zero when an allocation error occurred
+ * @see cxListShrink()
+ */
+cx_attr_nonnull
+CX_EXPORT int cxListReserve(CxList *list, size_t capacity);
+
+/**
+ * Advises the list to free any overallocated memory.
+ *
+ * Lists that do not support overallocation simply return zero.
+ *
+ * This function usually returns zero, except for very special and custom
+ * list and/or allocator implementations where freeing memory can fail.
+ *
+ * @param list the list
+ * @return usually zero
+ */
+cx_attr_nonnull
+CX_EXPORT int cxListShrink(CxList *list);
#ifdef __cplusplus
} // extern "C"
#include "string.h"
#include "hash_key.h"
+#ifndef UCX_LIST_H
+// forward-declare CxList
+typedef struct cx_list_s CxList;
+#endif
+
#ifdef __cplusplus
extern "C" {
#endif
/**
* Handle for the source map.
*/
- union {
- /**
- * Access for mutating iterators.
- */
- CxMap *m;
- /**
- * Access for normal iterators.
- */
- const CxMap *c;
- } map;
+ CxMap *map;
/**
* Handle for the current element.
* shall only allocate memory instead of adding an existing value to the map.
* Returns a pointer to the allocated memory or @c NULL if allocation fails.
*/
- void *(*put)(
- CxMap *map,
- CxHashKey key,
- void *value
- );
+ void *(*put)(CxMap *map, CxHashKey key, void *value);
/**
* Returns an element.
*/
- void *(*get)(
- const CxMap *map,
- CxHashKey key
- );
+ void *(*get)(const CxMap *map, CxHashKey key);
/**
* Removes an element.
* The function SHALL return zero when the @p key was found and
* non-zero, otherwise.
*/
- int (*remove)(
- CxMap *map,
- CxHashKey key,
- void *targetbuf
- );
+ int (*remove)(CxMap *map, CxHashKey key, void *targetbuf);
/**
* Creates an iterator for this map.
* You can use this as a placeholder for initializing CxMap pointers
* for which you do not want to reserve memory right from the beginning.
*/
-cx_attr_export
-extern CxMap *const cxEmptyMap;
+CX_EXPORT extern CxMap *const cxEmptyMap;
/**
* Deallocates the memory of the specified map.
*
* @param map the map to be freed
*/
-cx_attr_export
-void cxMapFree(CxMap *map);
+CX_EXPORT void cxMapFree(CxMap *map);
/**
* @param map the map to be cleared
*/
cx_attr_nonnull
-static inline void cxMapClear(CxMap *map) {
- map->cl->clear(map);
-}
+CX_EXPORT void cxMapClear(CxMap *map);
/**
* Returns the number of elements in this map.
* @return the number of stored elements
*/
cx_attr_nonnull
-static inline size_t cxMapSize(const CxMap *map) {
- return map->collection.size;
-}
+CX_EXPORT size_t cxMapSize(const CxMap *map);
/**
* Creates a value iterator for a map.
* @return an iterator for the currently stored values
*/
cx_attr_nodiscard
-static inline CxMapIterator cxMapIteratorValues(const CxMap *map) {
- if (map == NULL) map = cxEmptyMap;
- return map->cl->iterator(map, CX_MAP_ITERATOR_VALUES);
-}
+CX_EXPORT CxMapIterator cxMapIteratorValues(const CxMap *map);
/**
* Creates a key iterator for a map.
* @return an iterator for the currently stored keys
*/
cx_attr_nodiscard
-static inline CxMapIterator cxMapIteratorKeys(const CxMap *map) {
- if (map == NULL) map = cxEmptyMap;
- return map->cl->iterator(map, CX_MAP_ITERATOR_KEYS);
-}
+CX_EXPORT CxMapIterator cxMapIteratorKeys(const CxMap *map);
/**
* Creates an iterator for a map.
* @see cxMapIteratorValues()
*/
cx_attr_nodiscard
-static inline CxMapIterator cxMapIterator(const CxMap *map) {
- if (map == NULL) map = cxEmptyMap;
- return map->cl->iterator(map, CX_MAP_ITERATOR_PAIRS);
-}
-
-
-/**
- * Creates a mutating iterator over the values of a map.
- *
- * When the map is storing pointers, those pointers are returned.
- * Otherwise, the iterator iterates over pointers to the memory within the map where the
- * respective elements are stored.
- *
- * @note An iterator iterates over all elements successively. Therefore, the order
- * highly depends on the map implementation and may change arbitrarily when the contents change.
- *
- * @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_attr_export
-CxMapIterator cxMapMutIteratorValues(CxMap *map);
-
-/**
- * Creates a mutating iterator over the keys of a map.
- *
- * The elements of the iterator are keys of type CxHashKey, and the pointer returned
- * during iterator shall be treated as @c const @c CxHashKey* .
- *
- * @note An iterator iterates over all elements successively. Therefore, the order
- * highly depends on the map implementation and may change arbitrarily when the contents change.
- *
- * @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_attr_export
-CxMapIterator cxMapMutIteratorKeys(CxMap *map);
-
-/**
- * Creates a mutating iterator for a map.
- *
- * The elements of the iterator are key/value pairs of type CxMapEntry, and the pointer returned
- * during iterator shall be treated as @c const @c CxMapEntry* .
- *
- * @note An iterator iterates over all elements successively. Therefore, the order
- * highly depends on the map implementation and may change arbitrarily when the contents change.
- *
- * @param map the map to create the iterator for (can be @c NULL)
- * @return an iterator for the currently stored entries
- * @see cxMapMutIteratorKeys()
- * @see cxMapMutIteratorValues()
- */
-cx_attr_nodiscard
-cx_attr_export
-CxMapIterator cxMapMutIterator(CxMap *map);
+CX_EXPORT CxMapIterator cxMapIterator(const CxMap *map);
/**
* Puts a key/value-pair into the map.
* @see cxMapPut()
*/
cx_attr_nonnull
-static inline int cx_map_put(
- CxMap *map,
- CxHashKey key,
- void *value
-) {
- return map->cl->put(map, key, value) == NULL;
-}
+CX_EXPORT int cx_map_put(CxMap *map, CxHashKey key, void *value);
/**
* Puts a key/value-pair into the map.
* @see cxMapEmplace()
*/
cx_attr_nonnull
-static inline void *cx_map_emplace(
- CxMap *map,
- CxHashKey key
-) {
- return map->cl->put(map, key, NULL);
-}
+CX_EXPORT 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
-static inline void *cx_map_get(
- const CxMap *map,
- CxHashKey key
-) {
- return map->cl->get(map, key);
-}
+cx_attr_nonnull cx_attr_nodiscard
+CX_EXPORT void *cx_map_get(const CxMap *map, CxHashKey key);
/**
* Retrieves a value by using a key.
*
* @param map (@c CxMap*) the map
* @param key (any supported key type) the key
- * @return (@c void*) the value
+ * @return (@c void*) the value or @c NULL when no value with that @p key exists
* @see CX_HASH_KEY()
*/
#define cxMapGet(map, key) cx_map_get(map, CX_HASH_KEY(key))
+/**
+ * Checks if a map contains a specific key.
+ *
+ * @param map (@c CxMap*) the map
+ * @param key (any supported key type) the key
+ * @retval true if the key exists in the map
+ * @retval false if the key does not exist in the map
+ * @see CX_HASH_KEY()
+ */
+#define cxMapContains(map, key) (cxMapGet(map, key) != NULL)
+
/**
* Removes a key/value-pair from the map by using the key.
*
* @see cxMapRemoveAndGet()
*/
cx_attr_nonnull_arg(1)
-static inline int cx_map_remove(
- CxMap *map,
- CxHashKey key,
- void *targetbuf
-) {
- return map->cl->remove(map, key, targetbuf);
-}
+CX_EXPORT 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.
+ *
+ * If the destination map already contains entries, the cloned entries
+ * are added to that map, possibly overwriting existing elements when
+ * the keys already exist.
+ *
+ * When elements in the destination map need to be replaced, any destructor
+ * function is called on the replaced elements before replacing them.
+ *
+ * @attention If the cloned elements need to be destroyed by a destructor
+ * function, you must make sure that the destination map also uses this
+ * destructor function.
+ *
+ * @param dst the destination map
+ * @param src the source map
+ * @param clone_func the clone function for the values
+ * @param clone_allocator the allocator that is passed to the clone function
+ * @param data optional additional data that is passed to the clone function
+ * @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_clone_func clone_func, const CxAllocator *clone_allocator, void *data);
+
+
+/**
+ * Clones entries of a map if their key is not present in another map.
+ *
+ * @param dst the destination map
+ * @param minuend the map to subtract the entries from
+ * @param subtrahend the map containing the elements to be subtracted
+ * @param clone_func the clone function for the values
+ * @param clone_allocator the allocator that is passed to the clone function
+ * @param data optional additional data that is passed to the clone function
+ * @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_clone_func clone_func, const CxAllocator *clone_allocator, void *data);
+
+/**
+ * Clones entries of a map if their key is not present in a list.
+ *
+ * Note that the list must contain keys of type @c CxKey
+ * (or pointers to such keys) and must use @c cx_hash_key_cmp
+ * as the compare function.
+ * Generic key types cannot be processed in this case.
+ *
+ * @param dst the destination map
+ * @param src the source map
+ * @param keys the list of @c CxKey items
+ * @param clone_func the clone function for the values
+ * @param clone_allocator the allocator that is passed to the clone function
+ * @param data optional additional data that is passed to the clone function
+ * @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_clone_func clone_func, const CxAllocator *clone_allocator, void *data);
+
+
+/**
+ * Clones entries of a map only if their key is present in another map.
+ *
+ * @param dst the destination map
+ * @param src the map to clone the entries from
+ * @param other the map to check for existence of the keys
+ * @param clone_func the clone function for the values
+ * @param clone_allocator the allocator that is passed to the clone function
+ * @param data optional additional data that is passed to the clone function
+ * @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_clone_func clone_func, const CxAllocator *clone_allocator, void *data);
+
+/**
+ * Clones entries of a map only if their key is present in a list.
+ *
+ * Note that the list must contain keys of type @c CxKey
+ * (or pointers to such keys) and must use @c cx_hash_key_cmp
+ * as the compare function.
+ * Generic key types cannot be processed in this case.
+ *
+ * @param dst the destination map
+ * @param src the source map
+ * @param keys the list of @c CxKey items
+ * @param clone_func the clone function for the values
+ * @param clone_allocator the allocator that is passed to the clone function
+ * @param data optional additional data that is passed to the clone function
+ * @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_clone_func clone_func, const CxAllocator *clone_allocator, void *data);
+
+/**
+ * Clones entries into a map if their key does not exist yet.
+ *
+ * If you want to calculate the union of two maps into a fresh new map,
+ * you can proceed as follows:
+ * 1. Clone the first map into a fresh, empty map.
+ * 2. Use this function to clone the second map into the result from step 1.
+ *
+ * @param dst the destination map
+ * @param src the map to clone the entries from
+ * @param clone_func the clone function for the values
+ * @param clone_allocator the allocator that is passed to the clone function
+ * @param data optional additional data that is passed to the clone function
+ * @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_clone_func clone_func, const CxAllocator *clone_allocator, void *data);
+
+/**
+ * Performs a shallow clone of one map into another.
+ *
+ * This function uses the default allocator, if needed, and performs
+ * shallow clones with @c memcpy().
+ *
+ * If the destination map already contains entries, the cloned entries
+ * are added to that map, possibly overwriting existing elements when
+ * the keys already exist.
+ *
+ * When elements in the destination map need to be replaced, any destructor
+ * function is called on the replaced elements before replacing them.
+ *
+ * @attention If the cloned elements need to be destroyed by a destructor
+ * function, you must make sure that the destination map also uses this
+ * destructor function.
+ *
+ * @param dst the destination map
+ * @param src the source map
+ * @retval zero when all elements were successfully cloned
+ * @retval non-zero when an allocation error occurred
+ * @see cxMapClone()
+ */
+cx_attr_nonnull
+CX_EXPORT int cxMapCloneSimple(CxMap *dst, const CxMap *src);
+
+/**
+ * Clones entries of a map if their key is not present in another map.
+ *
+ * This function uses the default allocator, if needed, and performs
+ * shallow clones with @c memcpy().
+ *
+ * @param dst the destination map
+ * @param minuend the map to subtract the entries from
+ * @param subtrahend the map containing the elements to be subtracted
+ * @retval zero when the elements were successfully cloned
+ * @retval non-zero when an allocation error occurred
+ */
+cx_attr_nonnull
+CX_EXPORT int cxMapDifferenceSimple(CxMap *dst, const CxMap *minuend, const CxMap *subtrahend);
+
+/**
+ * Clones entries of a map if their key is not present in a list.
+ *
+ * This function uses the default allocator, if needed, and performs
+ * shallow clones with @c memcpy().
+ *
+ * Note that the list must contain keys of type @c CxKey
+ * (or pointers to such keys) and must use @c cx_hash_key_cmp
+ * as the compare function.
+ * Generic key types cannot be processed in this case.
+ *
+ * @param dst the destination map
+ * @param src the source map
+ * @param keys the list of @c CxKey items
+ * @retval zero when the elements were successfully cloned
+ * @retval non-zero when an allocation error occurred
+ * @see cxMapListDifference()
+ */
+cx_attr_nonnull
+CX_EXPORT int cxMapListDifferenceSimple(CxMap *dst, const CxMap *src, const CxList *keys);
+
+
+/**
+ * Clones entries of a map only if their key is present in another map.
+ *
+ * This function uses the default allocator, if needed, and performs
+ * shallow clones with @c memcpy().
+ *
+ * @param dst the destination map
+ * @param src the map to clone the entries from
+ * @param other the map to check for existence of the keys
+ * @retval zero when the elements were successfully cloned
+ * @retval non-zero when an allocation error occurred
+ */
+cx_attr_nonnull
+CX_EXPORT int cxMapIntersectionSimple(CxMap *dst, const CxMap *src, const CxMap *other);
+
+/**
+ * Clones entries of a map only if their key is present in a list.
+ *
+ * This function uses the default allocator, if needed, and performs
+ * shallow clones with @c memcpy().
+ *
+ * Note that the list must contain keys of type @c CxKey
+ * (or pointers to such keys) and must use @c cx_hash_key_cmp
+ * as the compare function.
+ * Generic key types cannot be processed in this case.
+ *
+ * @param dst the destination map
+ * @param src the source map
+ * @param keys the list of @c CxKey items
+ * @retval zero when the elements were successfully cloned
+ * @retval non-zero when an allocation error occurred
+ */
+cx_attr_nonnull
+CX_EXPORT int cxMapListIntersectionSimple(CxMap *dst, const CxMap *src, const CxList *keys);
+
+/**
+ * Clones entries into a map if their key does not exist yet.
+ *
+ * This function uses the default allocator, if needed, and performs
+ * shallow clones with @c memcpy().
+ *
+ * If you want to calculate the union of two maps into a fresh new map,
+ * you can proceed as follows:
+ * 1. Clone the first map into a fresh, empty map.
+ * 2. Use this function to clone the second map into the result from step 1.
+ *
+ * @param dst the destination map
+ * @param src the map to clone the entries from
+ * @retval zero when the elements were successfully cloned
+ * @retval non-zero when an allocation error occurred
+ */
+cx_attr_nonnull
+CX_EXPORT int cxMapUnionSimple(CxMap *dst, const CxMap *src);
+
#ifdef __cplusplus
} // extern "C"
#endif
*
* @param pool the memory pool to free
*/
-cx_attr_export
-void cxMempoolFree(CxMempool *pool);
+CX_EXPORT 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_attr_export
-CxMempool *cxMempoolCreate(size_t capacity, enum cx_mempool_type type);
+cx_attr_nodiscard cx_attr_malloc cx_attr_dealloc(cxMempoolFree, 1)
+CX_EXPORT CxMempool *cxMempoolCreate(size_t capacity, enum cx_mempool_type type);
/**
* Creates a basic array-based memory pool.
* @param fnc the destructor that shall be applied to all memory blocks
*/
cx_attr_nonnull_arg(1)
-cx_attr_export
-void cxMempoolGlobalDestructor(CxMempool *pool, cx_destructor_func fnc);
+CX_EXPORT void cxMempoolGlobalDestructor(CxMempool *pool, cx_destructor_func fnc);
/**
* Sets the global destructor for all memory blocks within the specified pool.
* @param data additional data for the destructor function
*/
cx_attr_nonnull_arg(1)
-cx_attr_export
-void cxMempoolGlobalDestructor2(CxMempool *pool, cx_destructor_func2 fnc, void *data);
+CX_EXPORT void cxMempoolGlobalDestructor2(CxMempool *pool, cx_destructor_func2 fnc, void *data);
/**
* Sets the destructor function for a specific allocated memory object.
* @param fnc the destructor function
*/
cx_attr_nonnull
-cx_attr_export
-void cxMempoolSetDestructor(
- void *memory,
- cx_destructor_func fnc
-);
+CX_EXPORT void cxMempoolSetDestructor(void *memory, cx_destructor_func fnc);
/**
* Sets the destructor function for a specific allocated memory object.
* @param data additional data for the destructor function
*/
cx_attr_nonnull
-cx_attr_export
-void cxMempoolSetDestructor2(
- void *memory,
- cx_destructor_func2 fnc,
- void *data
-);
+CX_EXPORT 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_attr_export
-void cxMempoolRemoveDestructor(void *memory);
+CX_EXPORT 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_attr_export
-void cxMempoolRemoveDestructor2(void *memory);
+CX_EXPORT void cxMempoolRemoveDestructor2(void *memory);
/**
* Registers foreign memory with this pool.
* @retval non-zero failure
*/
cx_attr_nonnull
-cx_attr_export
-int cxMempoolRegister(
- CxMempool *pool,
- void *memory,
- cx_destructor_func destr
-);
+CX_EXPORT int cxMempoolRegister(CxMempool *pool, void *memory, cx_destructor_func destr);
/**
* @retval non-zero failure
*/
cx_attr_nonnull
-cx_attr_export
-int cxMempoolRegister2(
- CxMempool *pool,
- void *memory,
- cx_destructor_func2 destr,
- void *data
-);
+CX_EXPORT int cxMempoolRegister2(CxMempool *pool, void *memory, cx_destructor_func2 destr, void *data);
/**
* Transfers all the memory managed by one pool to another.
* @retval non-zero allocation failure or incompatible pools
*/
cx_attr_nonnull
-cx_attr_export
-int cxMempoolTransfer(
- CxMempool *source,
- CxMempool *dest
-);
+CX_EXPORT int cxMempoolTransfer(CxMempool *source, CxMempool *dest);
/**
* Transfers an object from one pool to another.
* @retval non-zero failure, or the object was not found in the source pool, or the pools are incompatible
*/
cx_attr_nonnull
-cx_attr_export
-int cxMempoolTransferObject(
- CxMempool *source,
- CxMempool *dest,
- const void *obj
-);
+CX_EXPORT int cxMempoolTransferObject(CxMempool *source, CxMempool *dest, const void *obj);
#ifdef __cplusplus
} // extern "C"
/**
* The maximum string length that fits into stack memory.
*/
-cx_attr_export
-extern const unsigned cx_printf_sbo_size;
+CX_EXPORT extern const unsigned cx_printf_sbo_size;
/**
* A @c fprintf like function which writes the output to a stream by
* @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_attr_export
-int cx_fprintf(
- void *stream,
- cx_write_func wfc,
- const char *fmt,
- ...
-);
+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, ...);
/**
* 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_attr_export
-int cx_vfprintf(
- void *stream,
- cx_write_func wfc,
- const char *fmt,
- va_list ap
-);
+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);
/**
* 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_attr_export
-cxmutstr cx_asprintf_a(
- const CxAllocator *allocator,
- const char *fmt,
- ...
-);
+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, ...);
/**
* An @c asprintf like function which allocates space for a string
* @return (@c cxmutstr) the formatted string
* @see cx_strfree()
*/
-#define cx_asprintf(fmt, ...) \
- cx_asprintf_a(cxDefaultAllocator, fmt, __VA_ARGS__)
+#define cx_asprintf(fmt, ...) cx_asprintf_a(cxDefaultAllocator, fmt, __VA_ARGS__)
/**
* A @c vasprintf 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_attr_export
-cxmutstr cx_vasprintf_a(
- const CxAllocator *allocator,
- const char *fmt,
- va_list ap
-);
+cx_attr_nonnull cx_attr_cstr_arg(2)
+CX_EXPORT cxmutstr cx_vasprintf_a(const CxAllocator *allocator, const char *fmt, va_list ap);
/**
* A @c vasprintf like function which allocates space for a string
* @see cx_fprintf()
* @see cxBufferWrite()
*/
-#define cx_bprintf(buffer, fmt, ...) cx_fprintf((void*)buffer, \
- cxBufferWriteFunc, fmt, __VA_ARGS__)
+#define cx_bprintf(buffer, fmt, ...) cx_fprintf((void*)buffer, cxBufferWriteFunc, fmt, __VA_ARGS__)
/**
* @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_attr_export
-int cx_sprintf_a(
- const CxAllocator *alloc,
- char **str,
- size_t *len,
- const char *fmt,
- ...
-);
+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, ...);
/**
* @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_attr_export
-int cx_vsprintf_a(
- const CxAllocator *alloc,
- char **str,
- size_t *len,
- const char *fmt,
- va_list ap
-);
+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);
/**
* @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_attr_export
-int cx_sprintf_sa(
- const CxAllocator *alloc,
- char *buf,
- size_t *len,
- char **str,
- const char *fmt,
- ...
-);
+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, ...);
/**
* 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_attr_export
-int cx_vsprintf_sa(
- const CxAllocator *alloc,
- char *buf,
- size_t *len,
- char **str,
- const char *fmt,
- va_list ap
-);
+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
/**
* Default properties configuration.
*/
-cx_attr_export
-extern const CxPropertiesConfig cx_properties_config_default;
+CX_EXPORT extern const CxPropertiesConfig cx_properties_config_default;
/**
* Status codes for the properties interface.
* @retval zero success
* @retval non-zero sinking the k/v-pair failed
*/
-cx_attr_nonnull
typedef int(*cx_properties_sink_func)(
CxProperties *prop,
CxPropertiesSink *sink,
* @retval zero success
* @retval non-zero reading the data failed
*/
-cx_attr_nonnull
typedef int(*cx_properties_read_func)(
CxProperties *prop,
CxPropertiesSource *src,
* @retval zero initialization was successful
* @retval non-zero otherwise
*/
-cx_attr_nonnull
typedef int(*cx_properties_read_init_func)(
CxProperties *prop,
CxPropertiesSource *src
* @param prop the properties interface that wants to read from the source
* @param src the source
*/
-cx_attr_nonnull
typedef void(*cx_properties_read_clean_func)(
CxProperties *prop,
CxPropertiesSource *src
* @see cxPropertiesInitDefault()
*/
cx_attr_nonnull
-cx_attr_export
-void cxPropertiesInit(CxProperties *prop, CxPropertiesConfig config);
+CX_EXPORT void cxPropertiesInit(CxProperties *prop, CxPropertiesConfig config);
/**
* Destroys the properties interface.
* @param prop the properties interface
*/
cx_attr_nonnull
-cx_attr_export
-void cxPropertiesDestroy(CxProperties *prop);
+CX_EXPORT void cxPropertiesDestroy(CxProperties *prop);
/**
* Destroys and re-initializes the properties interface.
* @param prop the properties interface
*/
cx_attr_nonnull
-static inline void cxPropertiesReset(CxProperties *prop) {
- CxPropertiesConfig config = prop->config;
- cxPropertiesDestroy(prop);
- cxPropertiesInit(prop, config);
-}
+CX_EXPORT void cxPropertiesReset(CxProperties *prop);
/**
* Initialize a properties parser with the default configuration.
* @see cxPropertiesInit()
*/
#define cxPropertiesInitDefault(prop) \
- cxPropertiesInit(prop, cx_properties_config_default)
+ cxPropertiesInit(prop, cx_properties_config_default)
/**
* Fills the input buffer with data.
* @retval non-zero a memory allocation was necessary but failed
* @see cxPropertiesFill()
*/
-cx_attr_nonnull
-cx_attr_access_r(2, 3)
-cx_attr_export
-int cxPropertiesFilln(
- CxProperties *prop,
- const char *buf,
- size_t len
-);
+cx_attr_nonnull cx_attr_access_r(2, 3)
+CX_EXPORT int cxPropertiesFilln(CxProperties *prop, const char *buf, size_t len);
/**
* Internal function, do not use.
* @retval non-zero a memory allocation was necessary but failed
*/
cx_attr_nonnull
-static inline int cx_properties_fill(
- CxProperties *prop,
- cxstring str
-) {
+CX_INLINE int cx_properties_fill(CxProperties *prop, cxstring str) {
return cxPropertiesFilln(prop, str.ptr, str.length);
}
* @param capacity the capacity of the stack memory
*/
cx_attr_nonnull
-cx_attr_export
-void cxPropertiesUseStack(
- CxProperties *prop,
- char *buf,
- size_t capacity
-);
+CX_EXPORT 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_attr_export
-CxPropertiesStatus cxPropertiesNext(
- CxProperties *prop,
- cxstring *key,
- cxstring *value
-);
+cx_attr_nonnull cx_attr_nodiscard
+CX_EXPORT CxPropertiesStatus cxPropertiesNext(CxProperties *prop, cxstring *key, cxstring *value);
/**
* Creates a properties sink for an UCX map.
* @return the sink
* @see cxPropertiesLoad()
*/
-cx_attr_nonnull
-cx_attr_nodiscard
-cx_attr_export
-CxPropertiesSink cxPropertiesMapSink(CxMap *map);
+cx_attr_nonnull cx_attr_nodiscard
+CX_EXPORT CxPropertiesSink cxPropertiesMapSink(CxMap *map);
/**
* Creates a properties source based on an UCX string.
* @see cxPropertiesLoad()
*/
cx_attr_nodiscard
-cx_attr_export
-CxPropertiesSource cxPropertiesStringSource(cxstring str);
+CX_EXPORT CxPropertiesSource cxPropertiesStringSource(cxstring str);
/**
* Creates a properties source based on C string with the specified length.
* @return the properties source
* @see cxPropertiesLoad()
*/
-cx_attr_nonnull
-cx_attr_nodiscard
-cx_attr_access_r(1, 2)
-cx_attr_export
-CxPropertiesSource cxPropertiesCstrnSource(const char *str, size_t len);
+cx_attr_nonnull cx_attr_nodiscard cx_attr_access_r(1, 2)
+CX_EXPORT CxPropertiesSource cxPropertiesCstrnSource(const char *str, size_t len);
/**
* Creates a properties source based on a C string.
* @return the properties source
* @see cxPropertiesLoad()
*/
-cx_attr_nonnull
-cx_attr_nodiscard
-cx_attr_cstr_arg(1)
-cx_attr_export
-CxPropertiesSource cxPropertiesCstrSource(const char *str);
+cx_attr_nonnull cx_attr_nodiscard cx_attr_cstr_arg(1)
+CX_EXPORT CxPropertiesSource cxPropertiesCstrSource(const char *str);
/**
* Creates a properties source based on an FILE.
* @return the properties source
* @see cxPropertiesLoad()
*/
-cx_attr_nonnull
-cx_attr_nodiscard
-cx_attr_access_r(1)
-cx_attr_export
-CxPropertiesSource cxPropertiesFileSource(FILE *file, size_t chunk_size);
+cx_attr_nonnull cx_attr_nodiscard cx_attr_access_r(1)
+CX_EXPORT CxPropertiesSource cxPropertiesFileSource(FILE *file, size_t chunk_size);
/**
* @retval CX_PROPERTIES_BUFFER_ALLOC_FAILED an internal allocation was necessary but failed
*/
cx_attr_nonnull
-cx_attr_export
-CxPropertiesStatus cxPropertiesLoad(
- CxProperties *prop,
- CxPropertiesSink sink,
- CxPropertiesSource source
-);
+CX_EXPORT CxPropertiesStatus cxPropertiesLoad(CxProperties *prop,
+ CxPropertiesSink sink, CxPropertiesSource source);
#ifdef __cplusplus
} // extern "C"
* @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_attr_export
-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
-);
+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_read_func rfnc, cx_write_func wfnc,
+ char *buf, size_t bufsize, size_t n);
/**
* Reads data from a stream and writes it to another stream.
* @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_attr_export
-size_t cx_stream_ncopy(
- void *src,
- void *dest,
- cx_read_func rfnc,
- cx_write_func wfnc,
- size_t n
-);
+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_read_func rfnc, cx_write_func wfnc, size_t n);
/**
* Reads data from a stream and writes it to another stream.
/**
* The maximum length of the "needle" in cx_strstr() that can use SBO.
*/
-cx_attr_export
-extern const unsigned cx_strstr_sbo_size;
+CX_EXPORT extern const unsigned cx_strstr_sbo_size;
/**
* The UCX string structure.
*
* @see cx_mutstrn()
*/
-cx_attr_nodiscard
-cx_attr_cstr_arg(1)
-cx_attr_export
-cxmutstr cx_mutstr(char *cstring);
+cx_attr_nodiscard cx_attr_cstr_arg(1)
+CX_EXPORT cxmutstr cx_mutstr(char *cstring);
/**
* Wraps a string that does not need to be zero-terminated.
*
* @see cx_mutstr()
*/
-cx_attr_nodiscard
-cx_attr_access_rw(1, 2)
-cx_attr_export
-cxmutstr cx_mutstrn(
- char *cstring,
- size_t length
-);
+cx_attr_nodiscard cx_attr_access_rw(1, 2)
+CX_EXPORT cxmutstr cx_mutstrn(char *cstring, size_t length);
/**
* Wraps a string that must be zero-terminated.
*
* @see cx_strn()
*/
-cx_attr_nodiscard
-cx_attr_cstr_arg(1)
-cx_attr_export
-cxstring cx_str(const char *cstring);
+cx_attr_nodiscard cx_attr_cstr_arg(1)
+CX_EXPORT cxstring cx_str(const char *cstring);
/**
*
* @see cx_str()
*/
-cx_attr_nodiscard
-cx_attr_access_r(1, 2)
-cx_attr_export
-cxstring cx_strn(
- const char *cstring,
- size_t length
-);
+cx_attr_nodiscard cx_attr_access_r(1, 2)
+CX_EXPORT cxstring cx_strn(const char *cstring, size_t length);
#ifdef __cplusplus
} // extern "C"
cx_attr_nodiscard
-static inline cxstring cx_strcast(cxmutstr str) {
+CX_CPPDECL cxstring cx_strcast(cxmutstr str) {
return cx_strn(str.ptr, str.length);
}
cx_attr_nodiscard
-static inline cxstring cx_strcast(cxstring str) {
+CX_CPPDECL cxstring cx_strcast(cxstring str) {
return str;
}
cx_attr_nodiscard
-static inline cxstring cx_strcast(const char *str) {
+CX_CPPDECL cxstring cx_strcast(const char *str) {
return cx_str(str);
}
+cx_attr_nodiscard
+CX_CPPDECL cxstring cx_strcast(const unsigned char *str) {
+ return cx_str(reinterpret_cast<const char*>(str));
+}
extern "C" {
#else
/**
* @see cx_strcast()
*/
cx_attr_nodiscard
-static inline cxstring cx_strcast_m(cxmutstr str) {
+CX_INLINE cxstring cx_strcast_m(cxmutstr str) {
return (cxstring) {str.ptr, str.length};
}
/**
* @see cx_strcast()
*/
cx_attr_nodiscard
-static inline cxstring cx_strcast_c(cxstring str) {
+CX_INLINE cxstring cx_strcast_c(cxstring str) {
return str;
}
* @see cx_strcast()
*/
cx_attr_nodiscard
-static inline cxstring cx_strcast_z(const char *str) {
+CX_INLINE cxstring cx_strcast_u(const unsigned char *str) {
+ return cx_str((const char*)str);
+}
+
+/**
+ * Internal function, do not use.
+ * @param str
+ * @return
+ * @see cx_strcast()
+ */
+cx_attr_nodiscard
+CX_INLINE cxstring cx_strcast_z(const char *str) {
return cx_str(str);
}
#define cx_strcast(str) _Generic((str), \
cxmutstr: cx_strcast_m, \
cxstring: cx_strcast_c, \
- const unsigned char*: cx_strcast_z, \
- unsigned char *: cx_strcast_z, \
+ const unsigned char*: cx_strcast_u, \
+ unsigned char *: cx_strcast_u, \
const char*: cx_strcast_z, \
char *: cx_strcast_z) (str)
#endif
*
* @param str the string to free
*/
-cx_attr_export
-void cx_strfree(cxmutstr *str);
+CX_EXPORT void cx_strfree(cxmutstr *str);
/**
* Passes the pointer in this string to the allocator's free function.
* @param str the string to free
*/
cx_attr_nonnull_arg(1)
-cx_attr_export
-void cx_strfree_a(
- const CxAllocator *alloc,
- cxmutstr *str
-);
+CX_EXPORT void cx_strfree_a(const CxAllocator *alloc, cxmutstr *str);
/**
* Copies a string.
* @retval non-zero if re-allocation failed
*/
cx_attr_nonnull_arg(1)
-cx_attr_export
-int cx_strcpy_a(
- const CxAllocator *alloc,
- cxmutstr *dest,
- cxstring src
-);
+CX_EXPORT int cx_strcpy_a(const CxAllocator *alloc, cxmutstr *dest, cxstring src);
/**
* @return the accumulated length of all strings
*/
cx_attr_nodiscard
-cx_attr_export
-size_t cx_strlen(
- size_t count,
- ...
-);
+CX_EXPORT size_t cx_strlen(size_t count, ...);
/**
* Concatenates strings.
* @param ... all other UCX strings
* @return the concatenated string
*/
-cx_attr_nodiscard
-cx_attr_nonnull
-cx_attr_export
-cxmutstr cx_strcat_ma(
- const CxAllocator *alloc,
- cxmutstr str,
- size_t count,
- ...
-);
+cx_attr_nodiscard cx_attr_nonnull
+CX_EXPORT cxmutstr cx_strcat_ma(const CxAllocator *alloc,
+ cxmutstr str, size_t count, ...);
/**
* Concatenates strings and returns a new string.
* @return (@c cxmutstr) the concatenated string
*/
#define cx_strcat_a(alloc, count, ...) \
-cx_strcat_ma(alloc, cx_mutstrn(NULL, 0), count, __VA_ARGS__)
+ cx_strcat_ma(alloc, cx_mutstrn(NULL, 0), count, __VA_ARGS__)
/**
* Concatenates strings and returns a new string.
* @return (@c cxmutstr) the concatenated string
*/
#define cx_strcat(count, ...) \
-cx_strcat_ma(cxDefaultAllocator, cx_mutstrn(NULL, 0), count, __VA_ARGS__)
+ cx_strcat_ma(cxDefaultAllocator, cx_mutstrn(NULL, 0), count, __VA_ARGS__)
/**
* Concatenates strings.
* @return (@c cxmutstr) the concatenated string
*/
#define cx_strcat_m(str, count, ...) \
-cx_strcat_ma(cxDefaultAllocator, str, count, __VA_ARGS__)
+ cx_strcat_ma(cxDefaultAllocator, str, count, __VA_ARGS__)
/**
* Returns a substring starting at the specified location.
* @see cx_strsubsl_m()
*/
cx_attr_nodiscard
-cx_attr_export
-cxstring cx_strsubs(
- cxstring string,
- size_t start
-);
+CX_EXPORT cxstring cx_strsubs(cxstring string, size_t start);
/**
* Returns a substring starting at the specified location.
* @see cx_strsubsl_m()
*/
cx_attr_nodiscard
-cx_attr_export
-cxstring cx_strsubsl(
- cxstring string,
- size_t start,
- size_t length
-);
+CX_EXPORT cxstring cx_strsubsl(cxstring string, size_t start, size_t length);
/**
* Returns a substring starting at the specified location.
* @see cx_strsubsl()
*/
cx_attr_nodiscard
-cx_attr_export
-cxmutstr cx_strsubs_m(
- cxmutstr string,
- size_t start
-);
+CX_EXPORT cxmutstr cx_strsubs_m(cxmutstr string, size_t start);
/**
* Returns a substring starting at the specified location.
* @see cx_strsubsl()
*/
cx_attr_nodiscard
-cx_attr_export
-cxmutstr cx_strsubsl_m(
- cxmutstr string,
- size_t start,
- size_t length
-);
+CX_EXPORT cxmutstr cx_strsubsl_m(cxmutstr string, size_t start, size_t length);
/**
* Returns a substring starting at the location of the first occurrence of the
* @see cx_strchr_m()
*/
cx_attr_nodiscard
-cx_attr_export
-cxstring cx_strchr(
- cxstring string,
- int chr
-);
+CX_EXPORT cxstring cx_strchr(cxstring string, int chr);
/**
* Returns a substring starting at the location of the first occurrence of the
* @see cx_strchr()
*/
cx_attr_nodiscard
-cx_attr_export
-cxmutstr cx_strchr_m(
- cxmutstr string,
- int chr
-);
+CX_EXPORT cxmutstr cx_strchr_m(cxmutstr string, int chr);
/**
* Returns a substring starting at the location of the last occurrence of the
* @see cx_strrchr_m()
*/
cx_attr_nodiscard
-cx_attr_export
-cxstring cx_strrchr(
- cxstring string,
- int chr
-);
+CX_EXPORT cxstring cx_strrchr(cxstring string, int chr);
/**
* Returns a substring starting at the location of the last occurrence of the
* @see cx_strrchr()
*/
cx_attr_nodiscard
-cx_attr_export
-cxmutstr cx_strrchr_m(
- cxmutstr string,
- int chr
-);
+CX_EXPORT cxmutstr cx_strrchr_m(cxmutstr string, int chr);
/**
* Returns a substring starting at the location of the first occurrence of the
* @see cx_strstr_m()
*/
cx_attr_nodiscard
-cx_attr_export
-cxstring cx_strstr(
- cxstring haystack,
- cxstring needle
-);
+CX_EXPORT cxstring cx_strstr(cxstring haystack, cxstring needle);
/**
* Returns a substring starting at the location of the first occurrence of the
* @see cx_strstr()
*/
cx_attr_nodiscard
-cx_attr_export
-cxmutstr cx_strstr_m(
- cxmutstr haystack,
- cxstring needle
-);
+CX_EXPORT cxmutstr cx_strstr_m(cxmutstr haystack, cxstring needle);
/**
* Splits a given string using a delimiter string.
* @param output a preallocated array of at least @p limit length
* @return the actual number of split items
*/
-cx_attr_nodiscard
-cx_attr_nonnull
-cx_attr_access_w(4, 3)
-cx_attr_export
-size_t cx_strsplit(
- cxstring string,
- cxstring delim,
- size_t limit,
- cxstring *output
-);
+cx_attr_nodiscard cx_attr_nonnull cx_attr_access_w(4, 3)
+CX_EXPORT size_t cx_strsplit(cxstring string, cxstring delim,
+ size_t limit, cxstring *output);
/**
* Splits a given string using a delimiter string.
* written to
* @return the actual number of split items
*/
-cx_attr_nodiscard
-cx_attr_nonnull
-cx_attr_access_w(5)
-cx_attr_export
-size_t cx_strsplit_a(
- const CxAllocator *allocator,
- cxstring string,
- cxstring delim,
- size_t limit,
- cxstring **output
-);
+cx_attr_nodiscard cx_attr_nonnull cx_attr_access_w(5)
+CX_EXPORT size_t cx_strsplit_a(const CxAllocator *allocator,
+ cxstring string, cxstring delim,
+ size_t limit, cxstring **output);
/**
* @param output a preallocated array of at least @p limit length
* @return the actual number of split items
*/
-cx_attr_nodiscard
-cx_attr_nonnull
-cx_attr_access_w(4, 3)
-cx_attr_export
-size_t cx_strsplit_m(
- cxmutstr string,
- cxstring delim,
- size_t limit,
- cxmutstr *output
-);
+cx_attr_nodiscard cx_attr_nonnull cx_attr_access_w(4, 3)
+CX_EXPORT size_t cx_strsplit_m(cxmutstr string, cxstring delim,
+ size_t limit, cxmutstr *output);
/**
* Splits a given string using a delimiter string.
* written to
* @return the actual number of split items
*/
-cx_attr_nodiscard
-cx_attr_nonnull
-cx_attr_access_w(5)
-cx_attr_export
-size_t cx_strsplit_ma(
- const CxAllocator *allocator,
- cxmutstr string,
- cxstring delim,
- size_t limit,
- cxmutstr **output
-);
+cx_attr_nodiscard cx_attr_nonnull cx_attr_access_w(5)
+CX_EXPORT size_t cx_strsplit_ma(const CxAllocator *allocator,
+ cxmutstr string, cxstring delim, size_t limit,
+ cxmutstr **output);
/**
* Compares two strings.
* than @p s2, zero if both strings equal
*/
cx_attr_nodiscard
-cx_attr_export
-int cx_strcmp(
- cxstring s1,
- cxstring s2
-);
+CX_EXPORT int cx_strcmp_(cxstring s1, cxstring s2);
+
+/**
+ * Compares two strings.
+ *
+ * @param s1 the first string
+ * @param s2 the second string
+ * @return negative if @p s1 is smaller than @p s2, positive if @p s1 is larger
+ * than @p s2, zero if both strings equal
+ */
+#define cx_strcmp(s1, s2) cx_strcmp_(cx_strcast(s1), cx_strcast(s2))
/**
* Compares two strings ignoring case.
* than @p s2, zero if both strings equal ignoring case
*/
cx_attr_nodiscard
-cx_attr_export
-int cx_strcasecmp(
- cxstring s1,
- cxstring s2
-);
+CX_EXPORT int cx_strcasecmp_(cxstring s1, cxstring s2);
+
+/**
+ * Compares two strings ignoring case.
+ *
+ * @param s1 the first string
+ * @param s2 the second string
+ * @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
+ */
+#define cx_strcasecmp(s1, s2) cx_strcasecmp_(cx_strcast(s1), cx_strcast(s2))
/**
* Compares two strings.
*
* This function has a compatible signature for the use as a cx_compare_func.
*
+ * @attention This function can @em only compare UCX strings. It is unsafe to
+ * pass normal C-strings to this function.
+ *
* @param s1 the first string
* @param s2 the second string
* @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_attr_export
-int cx_strcmp_p(
- const void *s1,
- const void *s2
-);
+cx_attr_nodiscard cx_attr_nonnull
+CX_EXPORT 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_attr_export
-int cx_strcasecmp_p(
- const void *s1,
- const void *s2
-);
+cx_attr_nodiscard cx_attr_nonnull
+CX_EXPORT int cx_strcasecmp_p(const void *s1, const void *s2);
/**
* @return a duplicate of the string
* @see cx_strdup()
*/
-cx_attr_nodiscard
-cx_attr_nonnull
-cx_attr_export
-cxmutstr cx_strdup_a_(
- const CxAllocator *allocator,
- cxstring string
-);
+cx_attr_nodiscard cx_attr_nonnull
+CX_EXPORT cxmutstr cx_strdup_a_(const CxAllocator *allocator, cxstring string);
/**
* Creates a duplicate of the specified string.
* @see cx_strdup()
* @see cx_strfree_a()
*/
-#define cx_strdup_a(allocator, string) \
- cx_strdup_a_((allocator), cx_strcast(string))
+#define cx_strdup_a(allocator, string) cx_strdup_a_((allocator), cx_strcast(string))
/**
* Creates a duplicate of the specified string.
* @return the trimmed string
*/
cx_attr_nodiscard
-cx_attr_export
-cxstring cx_strtrim(cxstring string);
+CX_EXPORT cxstring cx_strtrim(cxstring string);
/**
* Omits leading and trailing spaces.
* @return the trimmed string
*/
cx_attr_nodiscard
-cx_attr_export
-cxmutstr cx_strtrim_m(cxmutstr string);
+CX_EXPORT cxmutstr cx_strtrim_m(cxmutstr string);
/**
* Checks if a string has a specific prefix.
* @c false otherwise
*/
cx_attr_nodiscard
-cx_attr_export
-bool cx_strprefix(
- cxstring string,
- cxstring prefix
-);
+CX_EXPORT bool cx_strprefix_(cxstring string, cxstring prefix);
+
+/**
+ * Checks if a string has a specific prefix.
+ *
+ * @param string the string to check
+ * @param prefix the prefix the string should have
+ * @return @c true, if and only if the string has the specified prefix,
+ * @c false otherwise
+ */
+#define cx_strprefix(string, prefix) cx_strprefix_(cx_strcast(string), cx_strcast(prefix))
/**
* Checks if a string has a specific suffix.
* @c false otherwise
*/
cx_attr_nodiscard
-cx_attr_export
-bool cx_strsuffix(
- cxstring string,
- cxstring suffix
-);
+CX_EXPORT bool cx_strsuffix_(cxstring string, cxstring suffix);
+
+/**
+ * Checks if a string has a specific suffix.
+ *
+ * @param string the string to check
+ * @param suffix the suffix the string should have
+ * @return @c true, if and only if the string has the specified suffix,
+ * @c false otherwise
+ */
+#define cx_strsuffix(string, suffix) cx_strsuffix_(cx_strcast(string), cx_strcast(suffix))
/**
* Checks if a string has a specific prefix, ignoring the case.
* @c false otherwise
*/
cx_attr_nodiscard
-cx_attr_export
-bool cx_strcaseprefix(
- cxstring string,
- cxstring prefix
-);
+CX_EXPORT bool cx_strcaseprefix_(cxstring string, cxstring prefix);
+
+/**
+ * Checks if a string has a specific prefix, ignoring the case.
+ *
+ * @param string the string to check
+ * @param prefix the prefix the string should have
+ * @return @c true, if and only if the string has the specified prefix,
+ * @c false otherwise
+ */
+#define cx_strcaseprefix(string, prefix) cx_strcaseprefix_(cx_strcast(string), cx_strcast(prefix))
/**
* Checks, if a string has a specific suffix, ignoring the case.
* @c false otherwise
*/
cx_attr_nodiscard
-cx_attr_export
-bool cx_strcasesuffix(
- cxstring string,
- cxstring suffix
-);
+CX_EXPORT bool cx_strcasesuffix_(cxstring string, cxstring suffix);
+
+/**
+ * Checks, if a string has a specific suffix, ignoring the case.
+ *
+ * @param string the string to check
+ * @param suffix the suffix the string should have
+ * @return @c true, if and only if the string has the specified suffix,
+ * @c false otherwise
+ */
+#define cx_strcasesuffix(string, suffix) cx_strcasesuffix_(cx_strcast(string), cx_strcast(suffix))
/**
* Replaces a string with another string.
* @param replmax maximum number of replacements
* @return the resulting string after applying the replacements
*/
-cx_attr_nodiscard
-cx_attr_nonnull
-cx_attr_export
-cxmutstr cx_strreplacen_a(
- const CxAllocator *allocator,
- cxstring str,
- cxstring search,
- cxstring replacement,
- size_t replmax
-);
+cx_attr_nodiscard cx_attr_nonnull
+CX_EXPORT cxmutstr cx_strreplacen_a(const CxAllocator *allocator,
+ cxstring str, cxstring search, cxstring replacement, size_t replmax);
/**
* Replaces a string with another string.
* @return (@c cxmutstr) the resulting string after applying the replacements
*/
#define cx_strreplacen(str, search, replacement, replmax) \
-cx_strreplacen_a(cxDefaultAllocator, str, search, replacement, replmax)
+ cx_strreplacen_a(cxDefaultAllocator, str, search, replacement, replmax)
/**
* Replaces a string with another string.
* @return (@c cxmutstr) the resulting string after applying the replacements
*/
#define cx_strreplace_a(allocator, str, search, replacement) \
-cx_strreplacen_a(allocator, str, search, replacement, SIZE_MAX)
+ cx_strreplacen_a(allocator, str, search, replacement, SIZE_MAX)
/**
* Replaces a string with another string.
* @return (@c cxmutstr) the resulting string after applying the replacements
*/
#define cx_strreplace(str, search, replacement) \
-cx_strreplacen_a(cxDefaultAllocator, str, search, replacement, SIZE_MAX)
+ cx_strreplacen_a(cxDefaultAllocator, str, search, replacement, SIZE_MAX)
/**
* Creates a string tokenization context.
* @return a new string tokenization context
*/
cx_attr_nodiscard
-cx_attr_export
-CxStrtokCtx cx_strtok_(
- cxstring str,
- cxstring delim,
- size_t limit
-);
+CX_EXPORT CxStrtokCtx cx_strtok_(cxstring str, cxstring delim, size_t limit);
/**
* Creates a string tokenization context.
* @return (@c CxStrtokCtx) a new string tokenization context
*/
#define cx_strtok(str, delim, limit) \
- cx_strtok_(cx_strcast(str), cx_strcast(delim), (limit))
+ cx_strtok_(cx_strcast(str), cx_strcast(delim), (limit))
/**
* Returns the next token.
* @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_attr_export
-bool cx_strtok_next(
- CxStrtokCtx *ctx,
- cxstring *token
-);
+cx_attr_nonnull cx_attr_nodiscard cx_attr_access_w(2)
+CX_EXPORT bool cx_strtok_next(CxStrtokCtx *ctx, cxstring *token);
/**
* Returns the next token of a mutable string.
* @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_attr_export
-bool cx_strtok_next_m(
- CxStrtokCtx *ctx,
- cxmutstr *token
-);
+cx_attr_nonnull cx_attr_nodiscard cx_attr_access_w(2)
+CX_EXPORT bool cx_strtok_next_m(CxStrtokCtx *ctx, cxmutstr *token);
/**
* 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_attr_export
-void cx_strtok_delim(
- CxStrtokCtx *ctx,
- const cxstring *delim,
- size_t count
-);
+cx_attr_nonnull cx_attr_access_r(2, 3)
+CX_EXPORT 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_attr_export
-int cx_strtos_lc_(cxstring str, short *output, int base, const char *groupsep);
+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);
/**
* 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_attr_export
-int cx_strtoi_lc_(cxstring str, int *output, int base, const char *groupsep);
+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);
/**
* 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_attr_export
-int cx_strtol_lc_(cxstring str, long *output, int base, const char *groupsep);
+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);
/**
* 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_attr_export
-int cx_strtoll_lc_(cxstring str, long long *output, int base, const char *groupsep);
+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);
/**
* 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_attr_export
-int cx_strtoi8_lc_(cxstring str, int8_t *output, int base, const char *groupsep);
+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);
/**
* 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_attr_export
-int cx_strtoi16_lc_(cxstring str, int16_t *output, int base, const char *groupsep);
+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);
/**
* 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_attr_export
-int cx_strtoi32_lc_(cxstring str, int32_t *output, int base, const char *groupsep);
+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);
/**
* 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_attr_export
-int cx_strtoi64_lc_(cxstring str, int64_t *output, int base, const char *groupsep);
+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);
/**
* 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_attr_export
-int cx_strtous_lc_(cxstring str, unsigned short *output, int base, const char *groupsep);
+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);
/**
* 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_attr_export
-int cx_strtou_lc_(cxstring str, unsigned int *output, int base, const char *groupsep);
+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);
/**
* 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_attr_export
-int cx_strtoul_lc_(cxstring str, unsigned long *output, int base, const char *groupsep);
+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);
/**
* 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_attr_export
-int cx_strtoull_lc_(cxstring str, unsigned long long *output, int base, const char *groupsep);
+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);
/**
* 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_attr_export
-int cx_strtou8_lc_(cxstring str, uint8_t *output, int base, const char *groupsep);
+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);
/**
* 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_attr_export
-int cx_strtou16_lc_(cxstring str, uint16_t *output, int base, const char *groupsep);
+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);
/**
* 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_attr_export
-int cx_strtou32_lc_(cxstring str, uint32_t *output, int base, const char *groupsep);
+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);
/**
* 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_attr_export
-int cx_strtou64_lc_(cxstring str, uint64_t *output, int base, const char *groupsep);
+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);
/**
* 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_attr_export
-int cx_strtoz_lc_(cxstring str, size_t *output, int base, const char *groupsep);
+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);
/**
* 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_attr_export
-int cx_strtof_lc_(cxstring str, float *output, char decsep, const char *groupsep);
+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);
/**
* 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_attr_export
-int cx_strtod_lc_(cxstring str, double *output, char decsep, const char *groupsep);
+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);
/**
* Converts a string to a number.
* @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_attr_nonnull cx_attr_nodiscard cx_attr_cstr_arg(1) cx_attr_malloc
static inline CxTestSuite* cx_test_suite_new(const char *name) {
CxTestSuite* suite = (CxTestSuite*) malloc(sizeof(CxTestSuite));
if (suite != NULL) {
*
* @param suite the test suite to free
*/
-static inline void cx_test_suite_free(CxTestSuite* suite) {
+CX_INLINE void cx_test_suite_free(CxTestSuite* suite) {
if (suite == NULL) return;
CxTestSet *l = suite->tests;
while (l != NULL) {
* @retval non-zero failure
*/
cx_attr_nonnull
-static inline int cx_test_register(CxTestSuite* suite, CxTest test) {
+CX_INLINE int cx_test_register(CxTestSuite* suite, CxTest test) {
CxTestSet *t = (CxTestSet*) malloc(sizeof(CxTestSet));
if (t) {
t->test = test;
* @param out_writer the write function writing to @p out_target
*/
cx_attr_nonnull
-static inline void cx_test_run(CxTestSuite *suite,
- void *out_target, cx_write_func out_writer) {
+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);
} else {
ptrdiff_t loc_next;
/**
* The total number of distinct nodes that have been passed so far.
+ * This includes the current node.
*/
size_t counter;
/**
ptrdiff_t loc_next;
/**
* The total number of distinct nodes that have been passed so far.
+ * This includes the currently visited node.
*/
size_t counter;
/**
* @param iter the iterator
*/
cx_attr_nonnull
-static inline void cxTreeIteratorDispose(CxTreeIterator *iter) {
- cxFreeDefault(iter->stack);
- iter->stack = NULL;
-}
+CX_EXPORT void cxTreeIteratorDispose(CxTreeIterator *iter);
/**
* Releases internal memory of the given tree visitor.
* @param visitor the visitor
*/
cx_attr_nonnull
-static inline 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;
- }
-}
+CX_EXPORT void cxTreeVisitorDispose(CxTreeVisitor *visitor);
/**
* Advises the iterator to skip the subtree below the current node and
* @see cx_tree_unlink()
*/
cx_attr_nonnull
-cx_attr_export
-void cx_tree_link(
- void *parent,
- void *node,
- ptrdiff_t loc_parent,
- ptrdiff_t loc_children,
- ptrdiff_t loc_last_child,
- ptrdiff_t loc_prev,
- ptrdiff_t loc_next
-);
+CX_EXPORT void cx_tree_link(void *parent, void *node,
+ ptrdiff_t loc_parent, ptrdiff_t loc_children, ptrdiff_t loc_last_child,
+ ptrdiff_t loc_prev, ptrdiff_t loc_next);
/**
* Unlinks a node from its parent.
* @see cx_tree_link()
*/
cx_attr_nonnull
-cx_attr_export
-void cx_tree_unlink(
- void *node,
- ptrdiff_t loc_parent,
- ptrdiff_t loc_children,
- ptrdiff_t loc_last_child,
- ptrdiff_t loc_prev,
- ptrdiff_t loc_next
-);
+CX_EXPORT void cx_tree_unlink(void *node,
+ ptrdiff_t loc_parent, ptrdiff_t loc_children, ptrdiff_t loc_last_child,
+ ptrdiff_t loc_prev, ptrdiff_t loc_next);
/**
* Macro that can be used instead of the magic value for infinite search depth.
* positive if one of the children might contain the data,
* negative if neither the node nor the children contains the data
*/
-cx_attr_nonnull
typedef int (*cx_tree_search_data_func)(const void *node, const void *data);
* positive if one of the children might contain the data,
* negative if neither the node nor the children contains the data
*/
-cx_attr_nonnull
typedef int (*cx_tree_search_func)(const void *node, const void *new_node);
/**
* could contain the node (but doesn't right now), negative if the tree does not
* contain any node that might be related to the searched data
*/
-cx_attr_nonnull
-cx_attr_access_w(5)
-cx_attr_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
-);
+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.
* 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_attr_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_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);
/**
* Creates a depth-first iterator for a tree with the specified root node.
* @see cxTreeIteratorDispose()
*/
cx_attr_nodiscard
-cx_attr_export
-CxTreeIterator cx_tree_iterator(
- void *root,
- bool visit_on_exit,
- ptrdiff_t loc_children,
- ptrdiff_t loc_next
-);
+CX_EXPORT CxTreeIterator cx_tree_iterator(void *root, bool visit_on_exit,
+ ptrdiff_t loc_children, ptrdiff_t loc_next);
/**
* Creates a breadth-first iterator for a tree with the specified root node.
* @see cxTreeVisitorDispose()
*/
cx_attr_nodiscard
-cx_attr_export
-CxTreeVisitor cx_tree_visitor(
- void *root,
- ptrdiff_t loc_children,
- ptrdiff_t loc_next
-);
+CX_EXPORT CxTreeVisitor 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.
* @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.
*/
-cx_attr_nonnull_arg(1)
typedef void *(*cx_tree_node_create_func)(const void *, void *);
/**
* 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_attr_export
-extern unsigned int cx_tree_add_look_around_depth;
+CX_EXPORT extern unsigned int cx_tree_add_look_around_depth;
/**
* Adds multiple elements efficiently to a tree.
* @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_attr_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
-);
+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.
* @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_attr_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
-);
+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.
* @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_attr_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
-);
+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);
/**
* 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
- );
+ 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
- );
+ 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
- );
+ void *(*find)(struct cx_tree_s *tree, const void *subtree, const void *data, size_t depth);
};
/**
* @see cxTreeFree()
*/
cx_attr_nonnull
-cx_attr_export
-void cxTreeDestroySubtree(CxTree *tree, void *node);
+CX_EXPORT void cxTreeDestroySubtree(CxTree *tree, void *node);
/**
*
* @param tree the tree to free
*/
-cx_attr_export
-void cxTreeFree(CxTree *tree);
+CX_EXPORT void cxTreeFree(CxTree *tree);
/**
* Creates a new tree structure based on the specified layout.
* @see cxTreeCreateSimple()
* @see cxTreeCreateWrapped()
*/
-cx_attr_nonnull_arg(2, 3, 4)
-cx_attr_nodiscard
-cx_attr_malloc
-cx_attr_dealloc(cxTreeFree, 1)
-cx_attr_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
-);
+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.
* @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)
+#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.
* @return the new tree
* @see cxTreeCreate()
*/
-cx_attr_nonnull_arg(2)
-cx_attr_nodiscard
-cx_attr_malloc
-cx_attr_dealloc(cxTreeFree, 1)
-cx_attr_export
-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
-);
+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,
+ 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.
* @retval non-zero failure
*/
cx_attr_nonnull
-static inline int cxTreeInsert(
- CxTree *tree,
- const void *data
-) {
- return tree->cl->insert_element(tree, data);
-}
+CX_EXPORT int cxTreeInsert(CxTree *tree, const void *data);
/**
* Inserts elements provided by an iterator efficiently into the tree.
* @return the number of elements that could be successfully inserted
*/
cx_attr_nonnull
-static inline size_t cxTreeInsertIter(
- CxTree *tree,
- CxIteratorBase *iter,
- size_t n
-) {
- return tree->cl->insert_many(tree, iter, n);
-}
+CX_EXPORT size_t cxTreeInsertIter(CxTree *tree, CxIteratorBase *iter, size_t n);
/**
* Inserts an array of data efficiently into the tree.
* @return the number of elements that could be successfully inserted
*/
cx_attr_nonnull
-static inline 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);
-}
+CX_EXPORT size_t cxTreeInsertArray(CxTree *tree, const void *data, size_t elem_size, size_t n);
/**
* Searches the data in the specified tree.
* @param data the data to search for
* @return the first matching node, or @c NULL when the data cannot be found
*/
-cx_attr_nonnull
-cx_attr_nodiscard
-static inline void *cxTreeFind(
- CxTree *tree,
- const void *data
-) {
- return tree->cl->find(tree, tree->root, data, 0);
-}
+cx_attr_nonnull cx_attr_nodiscard
+CX_EXPORT void *cxTreeFind(CxTree *tree, const void *data);
/**
* Searches the data in the specified subtree.
* @param max_depth the maximum search depth
* @return the first matching node, or @c NULL when the data cannot be found
*/
-cx_attr_nonnull
-cx_attr_nodiscard
-static inline void *cxTreeFindInSubtree(
- CxTree *tree,
- const void *data,
- void *subtree_root,
- size_t max_depth
-) {
- return tree->cl->find(tree, subtree_root, data, max_depth);
-}
+cx_attr_nonnull cx_attr_nodiscard
+CX_EXPORT void *cxTreeFindInSubtree(CxTree *tree, const void *data, void *subtree_root, size_t max_depth);
/**
* 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_attr_export
-size_t cxTreeSubtreeSize(CxTree *tree, void *subtree_root);
+cx_attr_nonnull cx_attr_nodiscard
+CX_EXPORT 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_attr_export
-size_t cxTreeSubtreeDepth(CxTree *tree, void *subtree_root);
+cx_attr_nonnull cx_attr_nodiscard
+CX_EXPORT 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
-static inline size_t cxTreeSize(CxTree *tree) {
- return tree->size;
-}
+cx_attr_nonnull cx_attr_nodiscard
+CX_EXPORT 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_attr_export
-size_t cxTreeDepth(CxTree *tree);
+cx_attr_nonnull cx_attr_nodiscard
+CX_EXPORT 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
-static inline CxTreeIterator cxTreeIterateSubtree(
- CxTree *tree,
- void *node,
- bool visit_on_exit
-) {
- return cx_tree_iterator(
- node, visit_on_exit,
- tree->loc_children, tree->loc_next
- );
-}
+cx_attr_nonnull cx_attr_nodiscard
+CX_EXPORT 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
-static inline CxTreeVisitor cxTreeVisitSubtree(CxTree *tree, void *node) {
- return cx_tree_visitor(
- node, tree->loc_children, tree->loc_next
- );
-}
+cx_attr_nonnull cx_attr_nodiscard
+CX_EXPORT CxTreeVisitor 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
-static inline CxTreeIterator cxTreeIterate(
- CxTree *tree,
- bool visit_on_exit
-) {
- return cxTreeIterateSubtree(tree, tree->root, visit_on_exit);
-}
+cx_attr_nonnull cx_attr_nodiscard
+CX_EXPORT 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
-static inline CxTreeVisitor cxTreeVisit(CxTree *tree) {
- return cxTreeVisitSubtree(tree, tree->root);
-}
+cx_attr_nonnull cx_attr_nodiscard
+CX_EXPORT CxTreeVisitor cxTreeVisit(CxTree *tree);
/**
* Sets the (new) parent of the specified child.
* @see cxTreeAddChildNode()
*/
cx_attr_nonnull
-cx_attr_export
-void cxTreeSetParent(
- CxTree *tree,
- void *parent,
- void *child
-);
+CX_EXPORT void cxTreeSetParent(CxTree *tree, void *parent, void *child);
/**
* Adds a new node to the tree.
* @see cxTreeSetParent()
*/
cx_attr_nonnull
-cx_attr_export
-void cxTreeAddChildNode(
- CxTree *tree,
- void *parent,
- void *child
-);
+CX_EXPORT void cxTreeAddChildNode(CxTree *tree, void *parent, void *child);
/**
* Creates a new node and adds it to the tree.
* @see cxTreeInsert()
*/
cx_attr_nonnull
-cx_attr_export
-int cxTreeAddChild(
- CxTree *tree,
- void *parent,
- const void *data
-);
+CX_EXPORT int cxTreeAddChild(CxTree *tree, void *parent, const void *data);
/**
* A function that is invoked when a node needs to be re-linked to a new parent.
* @param old_parent the old parent of the node
* @param new_parent the new parent of the node
*/
-cx_attr_nonnull
typedef void (*cx_tree_relink_func)(
void *node,
const void *old_parent,
* @return zero on success, non-zero if @p node is the root node of the tree
*/
cx_attr_nonnull_arg(1, 2)
-cx_attr_export
-int cxTreeRemoveNode(
- CxTree *tree,
- void *node,
- cx_tree_relink_func relink_func
-);
+CX_EXPORT int cxTreeRemoveNode(CxTree *tree, void *node, cx_tree_relink_func relink_func);
/**
* Removes a node and its subtree from the tree.
* @param node the node to remove
*/
cx_attr_nonnull
-cx_attr_export
-void cxTreeRemoveSubtree(CxTree *tree, void *node);
+CX_EXPORT void cxTreeRemoveSubtree(CxTree *tree, void *node);
/**
* Destroys a node and re-links its children to its former parent.
* @return zero on success, non-zero if @p node is the root node of the tree
*/
cx_attr_nonnull_arg(1, 2)
-cx_attr_export
-int cxTreeDestroyNode(
- CxTree *tree,
- void *node,
- cx_tree_relink_func relink_func
-);
+CX_EXPORT int cxTreeDestroyNode(CxTree *tree, void *node, cx_tree_relink_func relink_func);
#ifdef __cplusplus
} // extern "C"
+++ /dev/null
-/*
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
- *
- * Copyright 2021 Mike Becker, Olaf Wintermann All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- */
-
-/**
- * \file utils.h
- *
- * \brief General purpose utility functions.
- *
- * \author Mike Becker
- * \author Olaf Wintermann
- * \copyright 2-Clause BSD License
- */
-
-#ifndef UCX_UTILS_H
-#define UCX_UTILS_H
-
-#include "common.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/**
- * Convenience macro for a for loop that counts from zero to n-1.
- */
-#define cx_for_n(varname, n) for (size_t varname = 0 ; (varname) < (n) ; (varname)++)
-
-/**
- * Convenience macro for swapping two pointers.
- */
-#ifdef __cplusplus
-#define cx_swap_ptr(left, right) do {auto cx_tmp_swap_var = left; left = right; right = cx_tmp_swap_var;} while(0)
-#else
-#define cx_swap_ptr(left, right) do {void *cx_tmp_swap_var = left; left = right; right = cx_tmp_swap_var;} while(0)
-#endif
-
-// cx_szmul() definition
-
-#if (__GNUC__ >= 5 || defined(__clang__)) && !defined(CX_NO_SZMUL_BUILTIN)
-#define CX_SZMUL_BUILTIN
-
-/**
- * Alias for \c __builtin_mul_overflow.
- *
- * Performs a multiplication of size_t values and checks for overflow.
- *
- * @param a first operand
- * @param b second operand
- * @param result a pointer to a size_t, where the result should
- * be stored
- * @return zero, if no overflow occurred and the result is correct, non-zero
- * otherwise
- */
-#define cx_szmul(a, b, result) __builtin_mul_overflow(a, b, result)
-
-#else // no GNUC or clang bultin
-
-/**
- * Performs a multiplication of size_t values and checks for overflow.
- *
- * @param a first operand
- * @param b second operand
- * @param result a pointer to a size_t, where the result should
- * be stored
- * @return zero, if no overflow occurred and the result is correct, non-zero
- * otherwise
- */
-#define cx_szmul(a, b, result) cx_szmul_impl(a, b, result)
-
-/**
- * Performs a multiplication of size_t values and checks for overflow.
- *
- * This is a custom implementation in case there is no compiler builtin
- * available.
- *
- * @param a first operand
- * @param b second operand
- * @param result a pointer to a size_t where the result should be stored
- * @return zero, if no overflow occurred and the result is correct, non-zero
- * otherwise
- */
-int cx_szmul_impl(size_t a, size_t b, size_t *result);
-
-#endif // cx_szmul
-
-
-/**
- * Reads data from a stream and writes it to another stream.
- *
- * @param src the source stream
- * @param dest the destination stream
- * @param rfnc the read function
- * @param wfnc the write function
- * @param buf a pointer to the copy buffer or \c NULL if a buffer
- * shall be implicitly created on the heap
- * @param bufsize the size of the copy buffer - if \p buf is \c NULL you can
- * set this to zero to let the implementation decide
- * @param n the maximum number of bytes that shall be copied.
- * If this is larger than \p bufsize, the content is copied over multiple
- * iterations.
- * @return the total number of bytes copied
- */
-__attribute__((__nonnull__(1, 2, 3, 4)))
-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
-);
-
-/**
- * Reads data from a stream and writes it to another stream.
- *
- * @param src the source stream
- * @param dest the destination stream
- * @param rfnc the read function
- * @param wfnc the write function
- * @param buf a pointer to the copy buffer or \c NULL if a buffer
- * shall be implicitly created on the heap
- * @param bufsize the size of the copy buffer - if \p buf is \c NULL you can
- * set this to zero to let the implementation decide
- * @return total number of bytes copied
- */
-#define cx_stream_bcopy(src, dest, rfnc, wfnc, buf, bufsize) \
- cx_stream_bncopy(src, dest, rfnc, wfnc, buf, bufsize, SIZE_MAX)
-
-/**
- * Reads data from a stream and writes it to another stream.
- *
- * The data is temporarily stored in a stack allocated buffer.
- *
- * @param src the source stream
- * @param dest the destination stream
- * @param rfnc the read function
- * @param wfnc the write function
- * @param n the maximum number of bytes that shall be copied.
- * @return total number of bytes copied
- */
-__attribute__((__nonnull__))
-size_t cx_stream_ncopy(
- void *src,
- void *dest,
- cx_read_func rfnc,
- cx_write_func wfnc,
- size_t n
-);
-
-/**
- * Reads data from a stream and writes it to another stream.
- *
- * The data is temporarily stored in a stack allocated buffer.
- *
- * @param src the source stream
- * @param dest the destination stream
- * @param rfnc the read function
- * @param wfnc the write function
- * @return total number of bytes copied
- */
-#define cx_stream_copy(src, dest, rfnc, wfnc) \
- cx_stream_ncopy(src, dest, rfnc, wfnc, SIZE_MAX)
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif // UCX_UTILS_H
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
return key;
}
-int cx_hash_key_cmp(const CxHashKey *left, const CxHashKey *right) {
+int cx_hash_key_cmp(const void *l, const void *r) {
+ const CxHashKey *left = l;
+ const CxHashKey *right = r;
int d;
d = cx_vcmp_uint64(left->hash, right->hash);
if (d != 0) return d;
allocator,
sizeof(struct cx_hash_map_element_s) + map->collection.elem_size
);
- if (e == NULL) return NULL;
+ if (e == NULL) return NULL; // LCOV_EXCL_LINE
// write the value
if (value == NULL) {
// copy the key
void *kd = cxMalloc(allocator, key.len);
- if (kd == NULL) {
+ if (kd == NULL) { // LCOV_EXCL_START
cxFree(allocator, e);
return NULL;
- }
+ } // LCOV_EXCL_STOP
memcpy(kd, key.data, key.len);
e->key.data = kd;
e->key.len = key.len;
static void cx_hash_map_iter_next(void *it) {
CxMapIterator *iter = it;
- CxMap *map = iter->map.m;
+ CxMap *map = iter->map;
struct cx_hash_map_s *hmap = (struct cx_hash_map_s *) map;
struct cx_hash_map_element_s *elm = iter->elem;
// must not modify the iterator (the parameter is const)
if (elm != NULL) {
iter->entry.key = &elm->key;
- if (iter->map.c->collection.store_pointer) {
+ if (map->collection.store_pointer) {
iter->entry.value = *(void **) elm->data;
} else {
iter->entry.value = elm->data;
) {
CxMapIterator iter;
- iter.map.c = map;
+ iter.map = (CxMap*) map;
iter.elem_count = map->collection.size;
switch (type) {
iter.base.valid = cx_hash_map_iter_valid;
iter.base.next = cx_hash_map_iter_next;
iter.base.remove = false;
- iter.base.mutating = false;
+ iter.base.allow_remove = true;
iter.slot = 0;
iter.index = 0;
size_t new_bucket_count = (map->collection.size * 5) >> 1;
if (new_bucket_count < hash_map->bucket_count) {
+ // LCOV_EXCL_START
errno = EOVERFLOW;
return 1;
- }
+ } // LCOV_EXCL_STOP
struct cx_hash_map_element_s **new_buckets = cxCalloc(
map->collection.allocator,
new_bucket_count, sizeof(struct cx_hash_map_element_s *)
);
- if (new_buckets == NULL) return 1;
+ if (new_buckets == NULL) return 1; // LCOV_EXCL_LINE
// iterate through the elements and assign them to their new slots
for (size_t slot = 0; slot < hash_map->bucket_count; slot++) {
// only move the last element when we are not currently aiming
// at the last element already
if (iter->index < iter->elem_count) {
- void *last = ((char *) iter->src_handle.m)
+ void *last = ((char *) iter->src_handle)
+ iter->elem_count * iter->elem_size;
memcpy(iter->elem_handle, last, iter->elem_size);
}
}
}
-CxIterator cxMutIterator(
- void *array,
+CxIterator cxIterator(
+ const void *array,
size_t elem_size,
size_t elem_count,
bool remove_keeps_order
CxIterator iter;
iter.index = 0;
- iter.src_handle.m = array;
- iter.elem_handle = array;
+ iter.src_handle = (void*) array;
+ iter.elem_handle = (void*) array;
iter.elem_size = elem_size;
iter.elem_count = array == NULL ? 0 : elem_count;
iter.base.valid = cx_iter_valid;
iter.base.current = cx_iter_current;
iter.base.next = remove_keeps_order ? cx_iter_next_slow : cx_iter_next_fast;
iter.base.remove = false;
- iter.base.mutating = true;
+ iter.base.allow_remove = true;
return iter;
}
-CxIterator cxIterator(
+CxIterator cxIteratorPtr(
const void *array,
- size_t elem_size,
- size_t elem_count
-) {
- CxIterator iter = cxMutIterator((void*)array, elem_size, elem_count, false);
- iter.base.mutating = false;
- return iter;
-}
-
-CxIterator cxMutIteratorPtr(
- void *array,
size_t elem_count,
bool remove_keeps_order
) {
- CxIterator iter = cxMutIterator(array, sizeof(void*), elem_count, remove_keeps_order);
+ CxIterator iter = cxIterator(array, sizeof(void*), elem_count, remove_keeps_order);
iter.base.current = cx_iter_current_ptr;
return iter;
}
-
-CxIterator cxIteratorPtr(
- const void *array,
- size_t elem_count
-) {
- CxIterator iter = cxMutIteratorPtr((void*) array, elem_count, false);
- iter.base.mutating = false;
- return iter;
-}
size_t newcap = obj->values_capacity;
if (newcap > oldcap) {
if (cxReallocateArray(al, &obj->indices, newcap, sizeof(size_t))) {
- return 1;
+ return 1; // LCOV_EXCL_LINE
}
}
} else if (c == 'u') {
char utf8buf[4];
unsigned utf8len = unescape_unicode_string(
- cx_strn(str.ptr + i - 1, str.length + 1 - i),
+ cx_strn(str.ptr + i - 1, str.length - i),
utf8buf
);
if(utf8len > 0) {
} else {
// TODO: discuss the behavior for unrecognized escape sequences
// most parsers throw an error here - we just ignore it
- result.ptr[result.length++] = '\\';
+ result.ptr[result.length++] = '\\'; // LCOV_EXCL_LINE
}
result.ptr[result.length++] = c;
}
}
+void cxJsonReset(CxJson *json) {
+ const CxAllocator *allocator = json->allocator;
+ cxJsonDestroy(json);
+ cxJsonInit(json, allocator);
+}
+
int cxJsonFilln(CxJson *json, const char *buf, size_t size) {
if (cxBufferEof(&json->buffer)) {
// reinitialize the buffer
cxBufferDestroy(&json->buffer);
+ if (buf == NULL) buf = ""; // buffer must not be initialized with NULL
cxBufferInit(&json->buffer, (char*) buf, size,
NULL, CX_BUFFER_AUTO_EXTEND | CX_BUFFER_COPY_ON_WRITE);
json->buffer.size = size;
}
} else {
if (cx_strtod(token.content, &vbuf->value.number)) {
- return_rec(CX_JSON_FORMAT_ERROR_NUMBER);
+ // TODO: at the moment this is unreachable, because the tokenizer is already stricter than cx_strtod()
+ return_rec(CX_JSON_FORMAT_ERROR_NUMBER); // LCOV_EXCL_LINE
}
}
return_rec(CX_JSON_NO_ERROR);
} else {
// should be unreachable
assert(false);
- return_rec(-1);
+ return_rec(-1); // LCOV_EXCL_LINE
}
}
CxJsonStatus cxJsonNext(CxJson *json, CxJsonValue **value) {
- // check if buffer has been filled
+ // initialize output value
+ *value = &cx_json_value_nothing;
+
+ // check if the buffer has been filled
if (json->buffer.space == NULL) {
return CX_JSON_NULL_DATA;
}
- // initialize output value
- *value = &cx_json_value_nothing;
-
// parse data
CxJsonStatus result;
do {
return v;
}
-CxJsonValue* cxJsonCreateString(const CxAllocator* allocator, const char* str) {
- return cxJsonCreateCxString(allocator, cx_str(str));
-}
-
-CxJsonValue* cxJsonCreateCxString(const CxAllocator* allocator, cxstring str) {
+CxJsonValue* cx_json_create_string(const CxAllocator* allocator, cxstring str) {
if (allocator == NULL) allocator = cxDefaultAllocator;
CxJsonValue* v = cxMalloc(allocator, sizeof(CxJsonValue));
if (v == NULL) return NULL;
CxJsonValue** values = cxCallocDefault(count, sizeof(CxJsonValue*));
if (values == NULL) return -1;
for (size_t i = 0; i < count; i++) {
- values[i] = cxJsonCreateCxString(arr->allocator, str[i]);
+ values[i] = cxJsonCreateString(arr->allocator, str[i]);
if (values[i] == NULL) { json_arr_free_temp(values, count); return -1; }
}
int ret = cxJsonArrAddValues(arr, values, count);
);
}
-int cxJsonObjPut(CxJsonValue* obj, cxstring name, CxJsonValue* child) {
+int cx_json_obj_put(CxJsonValue* obj, cxstring name, CxJsonValue* child) {
cxmutstr k = cx_strdup_a(obj->allocator, name);
if (k.ptr == NULL) return -1;
CxJsonObjValue kv = {k, child};
if (json_add_objvalue(obj, kv)) {
+ // LCOV_EXCL_START
cx_strfree_a(obj->allocator, &k);
return 1;
+ // LCOV_EXCL_STOP
} else {
return 0;
}
}
-CxJsonValue* cxJsonObjPutObj(CxJsonValue* obj, cxstring name) {
+CxJsonValue* cx_json_obj_put_obj(CxJsonValue* obj, cxstring name) {
CxJsonValue* v = cxJsonCreateObj(obj->allocator);
if (v == NULL) return NULL;
if (cxJsonObjPut(obj, name, v)) { cxJsonValueFree(v); return NULL; }
return v;
}
-CxJsonValue* cxJsonObjPutArr(CxJsonValue* obj, cxstring name) {
+CxJsonValue* cx_json_obj_put_arr(CxJsonValue* obj, cxstring name) {
CxJsonValue* v = cxJsonCreateArr(obj->allocator);
if (v == NULL) return NULL;
if (cxJsonObjPut(obj, name, v)) { cxJsonValueFree(v); return NULL; }
return v;
}
-CxJsonValue* cxJsonObjPutNumber(CxJsonValue* obj, cxstring name, double num) {
+CxJsonValue* cx_json_obj_put_number(CxJsonValue* obj, cxstring name, double num) {
CxJsonValue* v = cxJsonCreateNumber(obj->allocator, num);
if (v == NULL) return NULL;
if (cxJsonObjPut(obj, name, v)) { cxJsonValueFree(v); return NULL; }
return v;
}
-CxJsonValue* cxJsonObjPutInteger(CxJsonValue* obj, cxstring name, int64_t num) {
+CxJsonValue* cx_json_obj_put_integer(CxJsonValue* obj, cxstring name, int64_t num) {
CxJsonValue* v = cxJsonCreateInteger(obj->allocator, num);
if (v == NULL) return NULL;
if (cxJsonObjPut(obj, name, v)) { cxJsonValueFree(v); return NULL; }
return v;
}
-CxJsonValue* cxJsonObjPutString(CxJsonValue* obj, cxstring name, const char* str) {
+CxJsonValue* cx_json_obj_put_string(CxJsonValue* obj, cxstring name, cxstring str) {
CxJsonValue* v = cxJsonCreateString(obj->allocator, str);
if (v == NULL) return NULL;
if (cxJsonObjPut(obj, name, v)) { cxJsonValueFree(v); return NULL; }
return v;
}
-CxJsonValue* cxJsonObjPutCxString(CxJsonValue* obj, cxstring name, cxstring str) {
- CxJsonValue* v = cxJsonCreateCxString(obj->allocator, str);
- if (v == NULL) return NULL;
- if (cxJsonObjPut(obj, name, v)) { cxJsonValueFree(v); return NULL; }
- return v;
-}
-
-CxJsonValue* cxJsonObjPutLiteral(CxJsonValue* obj, cxstring name, CxJsonLiteral lit) {
+CxJsonValue* cx_json_obj_put_literal(CxJsonValue* obj, cxstring name, CxJsonLiteral lit) {
CxJsonValue* v = cxJsonCreateLiteral(obj->allocator, lit);
if (v == NULL) return NULL;
if (cxJsonObjPut(obj, name, v)) { cxJsonValueFree(v); return NULL;}
return ret;
}
+char *cxJsonAsString(const CxJsonValue *value) {
+ return value->value.string.ptr;
+}
+
+cxstring cxJsonAsCxString(const CxJsonValue *value) {
+ return cx_strcast(value->value.string);
+}
+
+cxmutstr cxJsonAsCxMutStr(const CxJsonValue *value) {
+ return value->value.string;
+}
+
+double cxJsonAsDouble(const CxJsonValue *value) {
+ if (value->type == CX_JSON_INTEGER) {
+ return (double) value->value.integer;
+ } else {
+ return value->value.number;
+ }
+}
+
+int64_t cxJsonAsInteger(const CxJsonValue *value) {
+ if (value->type == CX_JSON_INTEGER) {
+ return value->value.integer;
+ } else {
+ return (int64_t) value->value.number;
+ }
+}
+
CxIterator cxJsonArrIter(const CxJsonValue *value) {
return cxIteratorPtr(
value->value.array.array,
- value->value.array.array_size
+ value->value.array.array_size,
+ true // arrays need to keep order
);
}
return cxIterator(
value->value.object.values,
sizeof(CxJsonObjValue),
- value->value.object.values_size
+ value->value.object.values_size,
+ true // TODO: objects do not always need to keep order
);
}
} else {
CxJsonObjValue kv = value->value.object.values[index];
cx_strfree_a(value->allocator, &kv.name);
- // TODO: replace with cx_array_remove()
+ // TODO: replace with cx_array_remove() / cx_array_remove_fast()
value->value.object.values_size--;
memmove(value->value.object.values + index, value->value.object.values + index + 1, (value->value.object.values_size - index) * sizeof(CxJsonObjValue));
return kv.value;
? look_idx
: value->value.object.indices[look_idx];
CxJsonObjValue *member = &value->value.object.values[elem_idx];
- if (settings->sort_members) {
- depth++;depth--;
- }
// possible indentation
if (settings->pretty) {
if (cx_json_write_rec(
target, element,
wfunc, settings, depth)
- ) return 1;
+ ) {
+ return 1; // LCOV_EXCL_LINE
+ }
if (iter.index < iter.elem_count - 1) {
const char *arr_value_sep = ", ";
}
static CxHashKey *cx_kv_list_loc_key(cx_kv_list *list, void *node_data) {
- return (CxHashKey*)((char*)node_data + list->list.base.collection.elem_size);
+ return (CxHashKey*)((char*)node_data - list->list.loc_data + list->list.loc_extra);
}
static void cx_kvl_deallocate(struct cx_list_s *list) {
const void *elem,
int prepend
) {
- cx_kv_list *kv_list = iter->src_handle.m;
+ cx_kv_list *kv_list = iter->src_handle;
return kv_list->list_methods->insert_iter(iter, elem, prepend);
}
struct cx_iterator_s *iter = it;
if (iter->base.remove) {
// remove the assigned key from the map before calling the actual function
- cx_kv_list *kv_list = iter->src_handle.m;
+ cx_kv_list *kv_list = iter->src_handle;
cx_kv_list_update_destructors(kv_list);
char *node = iter->elem_handle;
CxHashKey *key = cx_kv_list_loc_key(kv_list, node + kv_list->list.loc_data);
kv_list->map_methods->remove(&kv_list->map->map_base.base, *key, NULL);
}
}
+ // note that we do not clear the remove flag, because the next_impl will do that
iter->base.next_impl(it);
}
static void cx_kvl_iter_next(void *it) {
CxMapIterator *iter = it;
- cx_kv_list *kv_list = ((struct cx_kv_list_map_s*)iter->map.m)->list;
+ cx_kv_list *kv_list = ((struct cx_kv_list_map_s*)iter->map)->list;
// find the next list entry that has a key assigned
CxHashKey *key = NULL;
CxMapIterator iter = {0};
iter.type = type;
- iter.map.c = map;
+ iter.map = (CxMap*)map;
// although we iterate over the list, we only report that many elements that have a key in the map
iter.elem_count = map->collection.size;
assert(false); // LCOV_EXCL_LINE
}
+ iter.base.allow_remove = true;
iter.base.next = cx_kvl_iter_next;
iter.base.valid = cx_kvl_iter_valid;
return iter;
}
+static int cx_kvl_change_capacity(struct cx_list_s *list,
+ cx_attr_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;
+ cxMapRehash(&kv_list->map->map_base.base);
+ return 0;
+}
+
static cx_list_class cx_kv_list_class = {
cx_kvl_deallocate,
cx_kvl_insert_element,
cx_kvl_sort,
NULL,
cx_kvl_reverse,
+ cx_kvl_change_capacity,
cx_kvl_iterator,
};
CxList *list = cxLinkedListCreate(allocator, comparator, elem_size);
if (list == NULL) return NULL; // LCOV_EXCL_LINE
cx_linked_list *ll = (cx_linked_list*)list;
- ll->extra_data_len = sizeof(CxHashKey);
+ cx_linked_list_extra_data(ll, sizeof(CxHashKey));
CxMap *map = cxHashMapCreate(allocator, CX_STORE_POINTERS, 0);
if (map == NULL) { // LCOV_EXCL_START
cxListFree(list);
#include "cx/compare.h"
#include <string.h>
#include <assert.h>
-#include <unistd.h>
+
+#if __STDC_VERSION__ < 202311L
+// we cannot simply include stdalign.h
+// because Solaris is not entirely C11 complaint
+#ifndef __alignof_is_defined
+#define alignof _Alignof
+#define __alignof_is_defined 1
+#endif
+#endif
// LOW LEVEL LINKED LIST FUNCTIONS
return removed;
}
+void cx_linked_list_remove(
+ void **begin,
+ void **end,
+ ptrdiff_t loc_prev,
+ ptrdiff_t loc_next,
+ void *node
+) {
+ cx_linked_list_remove_chain(begin, end, loc_prev, loc_next, node, 1);
+}
+
size_t cx_linked_list_size(
const void *node,
ptrdiff_t loc_next
void *sbo[CX_LINKED_LIST_SORT_SBO_SIZE];
void **sorted = length >= CX_LINKED_LIST_SORT_SBO_SIZE ?
cxMallocDefault(sizeof(void *) * length) : sbo;
- if (sorted == NULL) abort();
+ if (sorted == NULL) abort(); // LCOV_EXCL_LINE
void *rc, *lc;
lc = ls;
}
static void *cx_ll_malloc_node(const cx_linked_list *list) {
- return cxZalloc(list->base.collection.allocator,
- list->loc_data + list->base.collection.elem_size + list->extra_data_len);
+ size_t n;
+ if (list->extra_data_len == 0) {
+ n = list->loc_data + list->base.collection.elem_size;
+ } else {
+ n = list->loc_extra + list->extra_data_len;
+ }
+ return cxZalloc(list->base.collection.allocator, n);
}
static int cx_ll_insert_at(
// we can add the remaining nodes and immediately advance to the inserted node
const char *source = array;
for (size_t i = 1; i < n; i++) {
- source += list->collection.elem_size;
+ if (source != NULL) {
+ source += list->collection.elem_size;
+ }
if (0 != cx_ll_insert_at(list, node, source)) return i;
node = CX_LL_PTR(node, ll->loc_next);
}
static void cx_ll_iter_next(void *it) {
struct cx_iterator_s *iter = it;
+ cx_linked_list *ll = iter->src_handle;
if (iter->base.remove) {
iter->base.remove = false;
- struct cx_list_s *list = iter->src_handle.m;
- cx_linked_list *ll = iter->src_handle.m;
+ struct cx_list_s *list = iter->src_handle;
char *node = iter->elem_handle;
iter->elem_handle = CX_LL_PTR(node, ll->loc_next);
cx_invoke_destructor(list, node + ll->loc_data);
iter->elem_count--;
cxFree(list->collection.allocator, node);
} else {
- const cx_linked_list *ll = iter->src_handle.c;
iter->index++;
void *node = iter->elem_handle;
iter->elem_handle = CX_LL_PTR(node, ll->loc_next);
static void cx_ll_iter_prev(void *it) {
struct cx_iterator_s *iter = it;
+ cx_linked_list *ll = iter->src_handle;
if (iter->base.remove) {
iter->base.remove = false;
- struct cx_list_s *list = iter->src_handle.m;
- cx_linked_list *ll = iter->src_handle.m;
+ struct cx_list_s *list = iter->src_handle;
char *node = iter->elem_handle;
iter->elem_handle = CX_LL_PTR(node, ll->loc_prev);
iter->index--;
iter->elem_count--;
cxFree(list->collection.allocator, node);
} else {
- const cx_linked_list *ll = iter->src_handle.c;
iter->index--;
char *node = iter->elem_handle;
iter->elem_handle = CX_LL_PTR(node, ll->loc_prev);
static void *cx_ll_iter_current(const void *it) {
const struct cx_iterator_s *iter = it;
- const cx_linked_list *ll = iter->src_handle.c;
+ const cx_linked_list *ll = iter->src_handle;
char *node = iter->elem_handle;
return node + ll->loc_data;
}
) {
CxIterator iter;
iter.index = index;
- iter.src_handle.c = list;
+ iter.src_handle = (void*)list;
iter.elem_handle = cx_ll_node_at((const cx_linked_list *) list, index);
iter.elem_size = list->collection.elem_size;
iter.elem_count = list->collection.size;
iter.base.valid = cx_ll_iter_valid;
iter.base.current = cx_ll_iter_current;
iter.base.next = backwards ? cx_ll_iter_prev : cx_ll_iter_next;
- iter.base.mutating = false;
+ iter.base.allow_remove = true;
iter.base.remove = false;
return iter;
}
const void *elem,
int prepend
) {
- struct cx_list_s *list = iter->src_handle.m;
- cx_linked_list *ll = iter->src_handle.m;
+ struct cx_list_s *list = iter->src_handle;
+ cx_linked_list *ll = iter->src_handle;
void *node = iter->elem_handle;
if (node != NULL) {
assert(prepend >= 0 && prepend <= 1);
return result;
} else {
if (cx_ll_insert_element(list, list->collection.size, elem) == NULL) {
- return 1;
+ return 1; // LCOV_EXCL_LINE
}
iter->elem_count++;
iter->index = list->collection.size;
cx_ll_sort,
cx_ll_compare,
cx_ll_reverse,
+ NULL, // no overallocation supported
cx_ll_iterator,
};
cx_linked_list *list = cxCalloc(allocator, 1, sizeof(cx_linked_list));
if (list == NULL) return NULL;
- list->extra_data_len = 0;
list->loc_prev = 0;
list->loc_next = sizeof(void*);
list->loc_data = sizeof(void*)*2;
+ list->loc_extra = -1;
+ list->extra_data_len = 0;
cx_list_init((CxList*)list, &cx_linked_list_class,
allocator, comparator, elem_size);
return (CxList *) 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;
+ size_t alignment = alignof(void*);
+ size_t padding = alignment - (loc_extra % alignment);
+ list->loc_extra = loc_extra + padding;
+}
#include "cx/list.h"
#include <string.h>
+#include <assert.h>
// <editor-fold desc="Store Pointers Functionality">
const void *elem,
int prepend
) {
- struct cx_list_s *list = iter->src_handle.m;
+ struct cx_list_s *list = iter->src_handle;
return list->climpl->insert_iter(iter, &elem, prepend);
}
return ptr == NULL ? NULL : *ptr;
}
+static int cx_pl_change_capacity(struct cx_list_s *list, size_t cap) {
+ if (list->climpl->change_capacity == NULL) {
+ return 0;
+ } else {
+ return list->climpl->change_capacity(list, cap);
+ }
+}
+
static struct cx_iterator_s cx_pl_iterator(
const struct cx_list_s *list,
size_t index,
cx_pl_sort,
cx_pl_compare,
cx_pl_reverse,
+ cx_pl_change_capacity,
cx_pl_iterator,
};
// </editor-fold>
cx_attr_unused bool backwards
) {
CxIterator iter = {0};
- iter.src_handle.c = list;
+ iter.src_handle = (void*) list;
iter.index = index;
iter.base.valid = cx_emptyl_iter_valid;
return iter;
cx_emptyl_noop,
NULL,
cx_emptyl_noop,
+ NULL,
cx_emptyl_iterator,
};
const void *data,
size_t n
) {
- size_t elem_size = list->collection.elem_size;
const char *src = data;
size_t i = 0;
for (; i < n; i++) {
if (NULL == invoke_list_func(
- insert_element, list, index + i,
- src + i * elem_size)
+ insert_element, list, index + i, src)
) {
return i; // LCOV_EXCL_LINE
}
+ if (src != NULL) {
+ src += list->collection.elem_size;
+ }
}
return i;
}
}
}
-CxIterator cxListMutIteratorAt(
- CxList *list,
- size_t index
-) {
- if (list == NULL) list = cxEmptyList;
- CxIterator it = list->cl->iterator(list, index, false);
- it.base.mutating = true;
- return it;
+size_t cxListSize(const CxList *list) {
+ return list->collection.size;
}
-CxIterator cxListMutBackwardsIteratorAt(
- CxList *list,
- size_t index
-) {
- if (list == NULL) list = cxEmptyList;
- CxIterator it = list->cl->iterator(list, index, true);
- it.base.mutating = true;
- return it;
+int cxListAdd(CxList *list, const void *elem) {
+ list->collection.sorted = false;
+ return list->cl->insert_element(list, list->collection.size, elem) == NULL;
}
-void cxListFree(CxList *list) {
- if (list == NULL) return;
- list->cl->deallocate(list);
+size_t cxListAddArray(CxList *list, const void *array, size_t n) {
+ list->collection.sorted = false;
+ return list->cl->insert_array(list, list->collection.size, array, n);
}
-int cxListSet(
- CxList *list,
- size_t index,
- const void *elem
-) {
+int cxListInsert(CxList *list, size_t index, const void *elem) {
+ list->collection.sorted = false;
+ return list->cl->insert_element(list, index, elem) == NULL;
+}
+
+void *cxListEmplaceAt(CxList *list, size_t index) {
+ list->collection.sorted = false;
+ return list->cl->insert_element(list, index, NULL);
+}
+
+void *cxListEmplace(CxList *list) {
+ list->collection.sorted = false;
+ return list->cl->insert_element(list, list->collection.size, NULL);
+}
+
+static bool cx_list_emplace_iterator_valid(const void *it) {
+ const CxIterator *iter = it;
+ return iter->index < iter->elem_count;
+}
+
+CxIterator cxListEmplaceArrayAt(CxList *list, size_t index, size_t n) {
+ list->collection.sorted = false;
+ size_t c = list->cl->insert_array(list, index, NULL, n);
+ CxIterator iter = list->cl->iterator(list, index, false);
+ // tweak the fields of this iterator
+ iter.elem_count = c;
+ iter.index = 0;
+ // replace the valid function to abort iteration when c is reached
+ iter.base.valid = cx_list_emplace_iterator_valid;
+ // if we are storing pointers, we want to return the pure pointers.
+ // therefore, we must unwrap the "current" method
+ if (list->collection.store_pointer) {
+ iter.base.current = iter.base.current_impl;
+ }
+ return iter;
+}
+
+CxIterator cxListEmplaceArray(CxList *list, size_t n) {
+ return cxListEmplaceArrayAt(list, list->collection.size, n);
+}
+
+int cxListInsertSorted(CxList *list, const void *elem) {
+ assert(cxCollectionSorted(list));
+ list->collection.sorted = true;
+ const void *data = list->collection.store_pointer ? &elem : elem;
+ return list->cl->insert_sorted(list, data, 1) == 0;
+}
+
+int cxListInsertUnique(CxList *list, const void *elem) {
+ if (cxCollectionSorted(list)) {
+ list->collection.sorted = true;
+ const void *data = list->collection.store_pointer ? &elem : elem;
+ return list->cl->insert_unique(list, data, 1) == 0;
+ } else {
+ if (cxListContains(list, elem)) {
+ return 0;
+ } else {
+ return cxListAdd(list, elem);
+ }
+ }
+}
+
+size_t cxListInsertArray(CxList *list, size_t index, const void *array, size_t n) {
+ list->collection.sorted = false;
+ return list->cl->insert_array(list, index, array, n);
+}
+
+size_t cxListInsertSortedArray(CxList *list, const void *array, size_t n) {
+ assert(cxCollectionSorted(list));
+ list->collection.sorted = true;
+ return list->cl->insert_sorted(list, array, n);
+}
+
+size_t cxListInsertUniqueArray(CxList *list, const void *array, size_t n) {
+ if (cxCollectionSorted(list)) {
+ list->collection.sorted = true;
+ return list->cl->insert_unique(list, array, n);
+ } else {
+ const char *source = array;
+ for (size_t i = 0 ; i < n; i++) {
+ // note: this also checks elements added in a previous iteration
+ const void *data = list->collection.store_pointer ?
+ *((const void**)source) : source;
+ if (!cxListContains(list, data)) {
+ if (cxListAdd(list, data)) {
+ return i; // LCOV_EXCL_LINE
+ }
+ }
+ source += list->collection.elem_size;
+ }
+ return n;
+ }
+}
+
+int cxListInsertAfter(CxIterator *iter, const void *elem) {
+ CxList* list = (CxList*)iter->src_handle;
+ list->collection.sorted = false;
+ return list->cl->insert_iter(iter, elem, 0);
+}
+
+int cxListInsertBefore(CxIterator *iter, const void *elem) {
+ CxList* list = (CxList*)iter->src_handle;
+ list->collection.sorted = false;
+ return list->cl->insert_iter(iter, elem, 1);
+}
+
+int cxListRemove(CxList *list, size_t index) {
+ return list->cl->remove(list, index, 1, NULL) == 0;
+}
+
+int cxListRemoveAndGet(CxList *list, size_t index, void *targetbuf) {
+ return list->cl->remove(list, index, 1, targetbuf) == 0;
+}
+
+int cxListRemoveAndGetFirst(CxList *list, void *targetbuf) {
+ return list->cl->remove(list, 0, 1, targetbuf) == 0;
+}
+
+int cxListRemoveAndGetLast(CxList *list, void *targetbuf) {
+ // note: index may wrap - member function will catch that
+ return list->cl->remove(list, list->collection.size - 1, 1, targetbuf) == 0;
+}
+
+size_t cxListRemoveArray(CxList *list, size_t index, size_t num) {
+ return list->cl->remove(list, index, num, NULL);
+}
+
+size_t cxListRemoveArrayAndGet(CxList *list, size_t index, size_t num, void *targetbuf) {
+ return list->cl->remove(list, index, num, targetbuf);
+}
+
+void cxListClear(CxList *list) {
+ list->cl->clear(list);
+ list->collection.sorted = true; // empty lists are always sorted
+}
+
+int cxListSwap(CxList *list, size_t i, size_t j) {
+ list->collection.sorted = false;
+ return list->cl->swap(list, i, j);
+}
+
+void *cxListAt(const CxList *list, size_t index) {
+ return list->cl->at(list, index);
+}
+
+void *cxListFirst(const CxList *list) {
+ return list->cl->at(list, 0);
+}
+
+void *cxListLast(const CxList *list) {
+ return list->cl->at(list, list->collection.size - 1);
+}
+
+int cxListSet(CxList *list, size_t index, const void *elem) {
if (index >= list->collection.size) {
return 1;
}
return 0;
}
+
+CxIterator cxListIteratorAt(const CxList *list, size_t index) {
+ if (list == NULL) list = cxEmptyList;
+ return list->cl->iterator(list, index, false);
+}
+
+CxIterator cxListBackwardsIteratorAt(const CxList *list, size_t index) {
+ if (list == NULL) list = cxEmptyList;
+ return list->cl->iterator(list, index, true);
+}
+
+CxIterator cxListIterator(const CxList *list) {
+ if (list == NULL) list = cxEmptyList;
+ return list->cl->iterator(list, 0, false);
+}
+
+CxIterator cxListBackwardsIterator(const CxList *list) {
+ if (list == NULL) list = cxEmptyList;
+ return list->cl->iterator(list, list->collection.size - 1, true);
+}
+
+size_t cxListFind(const CxList *list, const void *elem) {
+ return list->cl->find_remove((CxList*)list, elem, false);
+}
+
+bool cxListContains(const CxList* list, const void* elem) {
+ return list->cl->find_remove((CxList*)list, elem, false) < list->collection.size;
+}
+
+bool cxListIndexValid(const CxList *list, size_t index) {
+ return index < list->collection.size;
+}
+
+size_t cxListFindRemove(CxList *list, const void *elem) {
+ return list->cl->find_remove(list, elem, true);
+}
+
+void cxListSort(CxList *list) {
+ if (list->collection.sorted) return;
+ list->cl->sort(list);
+ list->collection.sorted = true;
+}
+
+void cxListReverse(CxList *list) {
+ // still sorted, but not according to the cmp_func
+ list->collection.sorted = false;
+ list->cl->reverse(list);
+}
+
+void cxListFree(CxList *list) {
+ if (list == NULL) return;
+ list->cl->deallocate(list);
+}
+
+static void cx_list_pop_uninitialized_elements(CxList *list, size_t n) {
+ cx_destructor_func destr_bak = list->collection.simple_destructor;
+ cx_destructor_func2 destr2_bak = list->collection.advanced_destructor;
+ list->collection.simple_destructor = NULL;
+ list->collection.advanced_destructor = NULL;
+ if (n == 1) {
+ cxListRemove(list, list->collection.size - 1);
+ } else {
+ cxListRemoveArray(list,list->collection.size - n, n);
+ }
+ list->collection.simple_destructor = destr_bak;
+ list->collection.advanced_destructor = destr2_bak;
+}
+
+static void* cx_list_simple_clone_func(void *dst, const void *src, const CxAllocator *al, void *data) {
+ size_t elem_size = *(size_t*)data;
+ if (dst == NULL) dst = cxMalloc(al, elem_size);
+ if (dst != NULL) memcpy(dst, src, elem_size);
+ return dst;
+}
+
+#define use_simple_clone_func(list) cx_list_simple_clone_func, NULL, (void*)&((list)->collection.elem_size)
+
+int cxListClone(CxList *dst, const CxList *src, cx_clone_func clone_func,
+ const CxAllocator *clone_allocator, void *data) {
+ if (clone_allocator == NULL) clone_allocator = cxDefaultAllocator;
+
+ // remember the original size
+ size_t orig_size = dst->collection.size;
+
+ // first, try to allocate the memory in the new list
+ CxIterator empl_iter = cxListEmplaceArray(dst, src->collection.size);
+
+ // get an iterator over the source elements
+ CxIterator src_iter = cxListIterator(src);
+
+ // now clone the elements
+ size_t cloned = empl_iter.elem_count;
+ for (size_t i = 0 ; i < empl_iter.elem_count; i++) {
+ void *src_elem = cxIteratorCurrent(src_iter);
+ void **dest_memory = cxIteratorCurrent(empl_iter);
+ void *target = cxCollectionStoresPointers(dst) ? NULL : dest_memory;
+ void *dest_ptr = clone_func(target, src_elem, clone_allocator, data);
+ if (dest_ptr == NULL) {
+ cloned = i;
+ break;
+ }
+ if (cxCollectionStoresPointers(dst)) {
+ *dest_memory = dest_ptr;
+ }
+ cxIteratorNext(src_iter);
+ cxIteratorNext(empl_iter);
+ }
+
+ // if we could not clone everything, free the allocated memory
+ // (disable the destructors!)
+ if (cloned < src->collection.size) {
+ cx_list_pop_uninitialized_elements(dst,
+ dst->collection.size - cloned - orig_size);
+ return 1;
+ }
+
+ // set the sorted flag when we know it's sorted
+ if (orig_size == 0 && src->collection.sorted) {
+ dst->collection.sorted = true;
+ }
+
+ return 0;
+}
+
+int cxListDifference(CxList *dst,
+ const CxList *minuend, const CxList *subtrahend,
+ cx_clone_func clone_func, const CxAllocator *clone_allocator, void *data) {
+ if (clone_allocator == NULL) clone_allocator = cxDefaultAllocator;
+
+ // optimize for sorted collections
+ if (cxCollectionSorted(minuend) && cxCollectionSorted(subtrahend)) {
+ bool dst_was_empty = cxCollectionSize(dst) == 0;
+
+ CxIterator min_iter = cxListIterator(minuend);
+ CxIterator sub_iter = cxListIterator(subtrahend);
+ while (cxIteratorValid(min_iter)) {
+ void *min_elem = cxIteratorCurrent(min_iter);
+ void *sub_elem;
+ int d;
+ if (cxIteratorValid(sub_iter)) {
+ sub_elem = cxIteratorCurrent(sub_iter);
+ cx_compare_func cmp = subtrahend->collection.cmpfunc;
+ d = cmp(sub_elem, min_elem);
+ } else {
+ // no more elements in the subtrahend,
+ // i.e., the min_elem is larger than any elem of the subtrahend
+ d = 1;
+ }
+ if (d == 0) {
+ // is contained, so skip it
+ cxIteratorNext(min_iter);
+ } else if (d < 0) {
+ // subtrahend is smaller than minuend,
+ // check the next element
+ cxIteratorNext(sub_iter);
+ } else {
+ // subtrahend is larger than the dst element,
+ // clone the minuend and advance
+ void **dst_mem = cxListEmplace(dst);
+ void *target = cxCollectionStoresPointers(dst) ? NULL : dst_mem;
+ void* dst_ptr = clone_func(target, min_elem, clone_allocator, data);
+ if (dst_ptr == NULL) {
+ cx_list_pop_uninitialized_elements(dst, 1);
+ return 1;
+ }
+ if (cxCollectionStoresPointers(dst)) {
+ *dst_mem = dst_ptr;
+ }
+ cxIteratorNext(min_iter);
+ }
+ }
+
+ // if dst was empty, it is now guaranteed to be sorted
+ dst->collection.sorted = dst_was_empty;
+ } else {
+ CxIterator min_iter = cxListIterator(minuend);
+ cx_foreach(void *, elem, min_iter) {
+ if (cxListContains(subtrahend, elem)) {
+ continue;
+ }
+ void **dst_mem = cxListEmplace(dst);
+ void *target = cxCollectionStoresPointers(dst) ? NULL : dst_mem;
+ void* dst_ptr = clone_func(target, elem, clone_allocator, data);
+ if (dst_ptr == NULL) {
+ cx_list_pop_uninitialized_elements(dst, 1);
+ return 1;
+ }
+ if (cxCollectionStoresPointers(dst)) {
+ *dst_mem = dst_ptr;
+ }
+ }
+ }
+
+ return 0;
+}
+
+int cxListIntersection(CxList *dst,
+ const CxList *src, const CxList *other,
+ cx_clone_func clone_func, const CxAllocator *clone_allocator, void *data) {
+ if (clone_allocator == NULL) clone_allocator = cxDefaultAllocator;
+
+ // optimize for sorted collections
+ if (cxCollectionSorted(src) && cxCollectionSorted(other)) {
+ bool dst_was_empty = cxCollectionSize(dst) == 0;
+
+ CxIterator src_iter = cxListIterator(src);
+ CxIterator other_iter = cxListIterator(other);
+ while (cxIteratorValid(src_iter) && cxIteratorValid(other_iter)) {
+ void *src_elem = cxIteratorCurrent(src_iter);
+ void *other_elem = cxIteratorCurrent(other_iter);
+ int d = src->collection.cmpfunc(src_elem, other_elem);
+ if (d == 0) {
+ // is contained, clone it
+ void **dst_mem = cxListEmplace(dst);
+ void *target = cxCollectionStoresPointers(dst) ? NULL : dst_mem;
+ void* dst_ptr = clone_func(target, src_elem, clone_allocator, data);
+ if (dst_ptr == NULL) {
+ cx_list_pop_uninitialized_elements(dst, 1);
+ return 1;
+ }
+ if (cxCollectionStoresPointers(dst)) {
+ *dst_mem = dst_ptr;
+ }
+ cxIteratorNext(src_iter);
+ } else if (d < 0) {
+ // the other element is larger, skip the source element
+ cxIteratorNext(src_iter);
+ } else {
+ // the source element is larger, try to find it in the other list
+ cxIteratorNext(other_iter);
+ }
+ }
+
+ // if dst was empty, it is now guaranteed to be sorted
+ dst->collection.sorted = dst_was_empty;
+ } else {
+ CxIterator src_iter = cxListIterator(src);
+ cx_foreach(void *, elem, src_iter) {
+ if (!cxListContains(other, elem)) {
+ continue;
+ }
+ void **dst_mem = cxListEmplace(dst);
+ void *target = cxCollectionStoresPointers(dst) ? NULL : dst_mem;
+ void* dst_ptr = clone_func(target, elem, clone_allocator, data);
+ if (dst_ptr == NULL) {
+ cx_list_pop_uninitialized_elements(dst, 1);
+ return 1;
+ }
+ if (cxCollectionStoresPointers(dst)) {
+ *dst_mem = dst_ptr;
+ }
+ }
+ }
+
+ return 0;
+}
+
+int cxListUnion(CxList *dst,
+ const CxList *src, const CxList *other,
+ cx_clone_func clone_func, const CxAllocator *clone_allocator, void *data) {
+ if (clone_allocator == NULL) clone_allocator = cxDefaultAllocator;
+
+ // optimize for sorted collections
+ if (cxCollectionSorted(src) && cxCollectionSorted(other)) {
+ bool dst_was_empty = cxCollectionSize(dst) == 0;
+
+ CxIterator src_iter = cxListIterator(src);
+ CxIterator other_iter = cxListIterator(other);
+ while (cxIteratorValid(src_iter) || cxIteratorValid(other_iter)) {
+ void *src_elem = NULL, *other_elem = NULL;
+ int d;
+ if (!cxIteratorValid(src_iter)) {
+ other_elem = cxIteratorCurrent(other_iter);
+ d = 1;
+ } else if (!cxIteratorValid(other_iter)) {
+ src_elem = cxIteratorCurrent(src_iter);
+ d = -1;
+ } else {
+ src_elem = cxIteratorCurrent(src_iter);
+ other_elem = cxIteratorCurrent(other_iter);
+ d = src->collection.cmpfunc(src_elem, other_elem);
+ }
+ void *clone_from;
+ if (d < 0) {
+ // source element is smaller clone it
+ clone_from = src_elem;
+ cxIteratorNext(src_iter);
+ } else if (d == 0) {
+ // both elements are equal, clone from the source, skip other
+ clone_from = src_elem;
+ cxIteratorNext(src_iter);
+ cxIteratorNext(other_iter);
+ } else {
+ // the other element is smaller, clone it
+ clone_from = other_elem;
+ cxIteratorNext(other_iter);
+ }
+ void **dst_mem = cxListEmplace(dst);
+ void *target = cxCollectionStoresPointers(dst) ? NULL : dst_mem;
+ void* dst_ptr = clone_func(target, clone_from, clone_allocator, data);
+ if (dst_ptr == NULL) {
+ cx_list_pop_uninitialized_elements(dst, 1);
+ return 1;
+ }
+ if (cxCollectionStoresPointers(dst)) {
+ *dst_mem = dst_ptr;
+ }
+ }
+
+ // if dst was empty, it is now guaranteed to be sorted
+ dst->collection.sorted = dst_was_empty;
+ } else {
+ if (cxListClone(dst, src, clone_func, clone_allocator, data)) {
+ return 1;
+ }
+ CxIterator other_iter = cxListIterator(other);
+ cx_foreach(void *, elem, other_iter) {
+ if (cxListContains(src, elem)) {
+ continue;
+ }
+ void **dst_mem = cxListEmplace(dst);
+ void *target = cxCollectionStoresPointers(dst) ? NULL : dst_mem;
+ void* dst_ptr = clone_func(target, elem, clone_allocator, data);
+ if (dst_ptr == NULL) {
+ cx_list_pop_uninitialized_elements(dst, 1);
+ return 1;
+ }
+ if (cxCollectionStoresPointers(dst)) {
+ *dst_mem = dst_ptr;
+ }
+ }
+ }
+
+ return 0;
+}
+
+int cxListCloneSimple(CxList *dst, const CxList *src) {
+ return cxListClone(dst, src, use_simple_clone_func(src));
+}
+
+int cxListDifferenceSimple(CxList *dst, const CxList *minuend, const CxList *subtrahend) {
+ return cxListDifference(dst, minuend, subtrahend, use_simple_clone_func(minuend));
+}
+
+int cxListIntersectionSimple(CxList *dst, const CxList *src, const CxList *other) {
+ return cxListIntersection(dst, src, other, use_simple_clone_func(src));
+}
+
+int cxListUnionSimple(CxList *dst, const CxList *src, const CxList *other) {
+ return cxListUnion(dst, src, other, use_simple_clone_func(src));
+}
+
+int cxListReserve(CxList *list, size_t capacity) {
+ if (list->cl->change_capacity == NULL) {
+ return 0;
+ }
+ if (capacity <= cxCollectionSize(list)) {
+ return 0;
+ }
+ return list->cl->change_capacity(list, capacity);
+}
+
+int cxListShrink(CxList *list) {
+ if (list->cl->change_capacity == NULL) {
+ return 0;
+ }
+ return list->cl->change_capacity(list, cxCollectionSize(list));
+}
#include "cx/map.h"\r
#include <string.h>\r
\r
+#include "cx/list.h"\r
+\r
// <editor-fold desc="empty map implementation">\r
\r
static void cx_empty_map_noop(cx_attr_unused CxMap *map) {\r
cx_attr_unused enum cx_map_iterator_type type\r
) {\r
CxMapIterator iter = {0};\r
- iter.map.c = map;\r
+ iter.map = (CxMap*) map;\r
iter.base.valid = cx_empty_map_iter_valid;\r
return iter;\r
}\r
\r
// </editor-fold>\r
\r
-CxMapIterator cxMapMutIteratorValues(CxMap *map) {\r
+void cxMapClear(CxMap *map) {\r
+ map->cl->clear(map);\r
+}\r
+\r
+size_t cxMapSize(const CxMap *map) {\r
+ return map->collection.size;\r
+}\r
+\r
+CxMapIterator cxMapIteratorValues(const CxMap *map) {\r
if (map == NULL) map = cxEmptyMap;\r
- CxMapIterator it = map->cl->iterator(map, CX_MAP_ITERATOR_VALUES);\r
- it.base.mutating = true;\r
- return it;\r
+ return map->cl->iterator(map, CX_MAP_ITERATOR_VALUES);\r
}\r
\r
-CxMapIterator cxMapMutIteratorKeys(CxMap *map) {\r
+CxMapIterator cxMapIteratorKeys(const CxMap *map) {\r
if (map == NULL) map = cxEmptyMap;\r
- CxMapIterator it = map->cl->iterator(map, CX_MAP_ITERATOR_KEYS);\r
- it.base.mutating = true;\r
- return it;\r
+ return map->cl->iterator(map, CX_MAP_ITERATOR_KEYS);\r
}\r
\r
-CxMapIterator cxMapMutIterator(CxMap *map) {\r
+CxMapIterator cxMapIterator(const CxMap *map) {\r
if (map == NULL) map = cxEmptyMap;\r
- CxMapIterator it = map->cl->iterator(map, CX_MAP_ITERATOR_PAIRS);\r
- it.base.mutating = true;\r
- return it;\r
+ return map->cl->iterator(map, CX_MAP_ITERATOR_PAIRS);\r
+}\r
+\r
+int cx_map_put(CxMap *map, CxHashKey key, void *value) {\r
+ return map->cl->put(map, key, value) == NULL;\r
+}\r
+\r
+void *cx_map_emplace(CxMap *map, CxHashKey key) {\r
+ return map->cl->put(map, key, NULL);\r
+}\r
+\r
+void *cx_map_get(const CxMap *map, CxHashKey key) {\r
+ return map->cl->get(map, key);\r
+}\r
+\r
+int cx_map_remove(CxMap *map, CxHashKey key, void *targetbuf) {\r
+ return map->cl->remove(map, key, targetbuf);\r
}\r
\r
void cxMapFree(CxMap *map) {\r
if (map == NULL) return;\r
map->cl->deallocate(map);\r
}\r
+\r
+static void cx_map_remove_uninitialized_entry(CxMap *map, CxHashKey key) {\r
+ cx_destructor_func destr_bak = map->collection.simple_destructor;\r
+ cx_destructor_func2 destr2_bak = map->collection.advanced_destructor;\r
+ map->collection.simple_destructor = NULL;\r
+ map->collection.advanced_destructor = NULL;\r
+ cxMapRemove(map, key);\r
+ map->collection.simple_destructor = destr_bak;\r
+ map->collection.advanced_destructor = destr2_bak;\r
+}\r
+\r
+static void* cx_map_simple_clone_func(void *dst, const void *src, const CxAllocator *al, void *data) {\r
+ size_t elem_size = *(size_t*)data;\r
+ if (dst == NULL) dst = cxMalloc(al, elem_size);\r
+ if (dst != NULL) memcpy(dst, src, elem_size);\r
+ return dst;\r
+}\r
+\r
+#define use_simple_clone_func(map) cx_map_simple_clone_func, NULL, (void*)&((map)->collection.elem_size)\r
+\r
+int cxMapClone(CxMap *dst, const CxMap *src, cx_clone_func clone_func,\r
+ const CxAllocator *clone_allocator, void *data) {\r
+ if (clone_allocator == NULL) clone_allocator = cxDefaultAllocator;\r
+ CxMapIterator src_iter = cxMapIterator(src);\r
+ for (size_t i = 0; i < cxMapSize(src); i++) {\r
+ const CxMapEntry *entry = cxIteratorCurrent(src_iter);\r
+ void **dst_mem = cxMapEmplace(dst, *(entry->key));\r
+ if (dst_mem == NULL) {\r
+ return 1; // LCOV_EXCL_LINE\r
+ }\r
+ void *target = cxCollectionStoresPointers(dst) ? NULL : dst_mem;\r
+ void *dst_ptr = clone_func(target, entry->value, clone_allocator, data);\r
+ if (dst_ptr == NULL) {\r
+ cx_map_remove_uninitialized_entry(dst, *(entry->key));\r
+ return 1;\r
+ }\r
+ if (cxCollectionStoresPointers(dst)) {\r
+ *dst_mem = dst_ptr;\r
+ }\r
+ cxIteratorNext(src_iter);\r
+ }\r
+ return 0;\r
+}\r
+\r
+int cxMapDifference(CxMap *dst, const CxMap *minuend, const CxMap *subtrahend,\r
+ cx_clone_func clone_func, const CxAllocator *clone_allocator, void *data) {\r
+ if (clone_allocator == NULL) clone_allocator = cxDefaultAllocator;\r
+\r
+ CxMapIterator src_iter = cxMapIterator(minuend);\r
+ cx_foreach(const CxMapEntry *, entry, src_iter) {\r
+ if (cxMapContains(subtrahend, *entry->key)) {\r
+ continue;\r
+ }\r
+ void** dst_mem = cxMapEmplace(dst, *entry->key);\r
+ if (dst_mem == NULL) {\r
+ return 1; // LCOV_EXCL_LINE\r
+ }\r
+ void *target = cxCollectionStoresPointers(dst) ? NULL : dst_mem;\r
+ void* dst_ptr = clone_func(target, entry->value, clone_allocator, data);\r
+ if (dst_ptr == NULL) {\r
+ cx_map_remove_uninitialized_entry(dst, *(entry->key));\r
+ return 1;\r
+ }\r
+ if (cxCollectionStoresPointers(dst)) {\r
+ *dst_mem = dst_ptr;\r
+ }\r
+ }\r
+ return 0;\r
+}\r
+\r
+int cxMapListDifference(CxMap *dst, const CxMap *src, const CxList *keys,\r
+ cx_clone_func clone_func, const CxAllocator *clone_allocator, void *data) {\r
+ if (clone_allocator == NULL) clone_allocator = cxDefaultAllocator;\r
+\r
+ CxMapIterator src_iter = cxMapIterator(src);\r
+ cx_foreach(const CxMapEntry *, entry, src_iter) {\r
+ if (cxListContains(keys, entry->key)) {\r
+ continue;\r
+ }\r
+ void** dst_mem = cxMapEmplace(dst, *entry->key);\r
+ if (dst_mem == NULL) {\r
+ return 1; // LCOV_EXCL_LINE\r
+ }\r
+ void *target = cxCollectionStoresPointers(dst) ? NULL : dst_mem;\r
+ void* dst_ptr = clone_func(target, entry->value, clone_allocator, data);\r
+ if (dst_ptr == NULL) {\r
+ cx_map_remove_uninitialized_entry(dst, *(entry->key));\r
+ return 1;\r
+ }\r
+ if (cxCollectionStoresPointers(dst)) {\r
+ *dst_mem = dst_ptr;\r
+ }\r
+ }\r
+ return 0;\r
+}\r
+\r
+int cxMapIntersection(CxMap *dst, const CxMap *src, const CxMap *other,\r
+ cx_clone_func clone_func, const CxAllocator *clone_allocator, void *data) {\r
+ if (clone_allocator == NULL) clone_allocator = cxDefaultAllocator;\r
+\r
+ CxMapIterator src_iter = cxMapIterator(src);\r
+ cx_foreach(const CxMapEntry *, entry, src_iter) {\r
+ if (!cxMapContains(other, *entry->key)) {\r
+ continue;\r
+ }\r
+ void** dst_mem = cxMapEmplace(dst, *entry->key);\r
+ if (dst_mem == NULL) {\r
+ return 1; // LCOV_EXCL_LINE\r
+ }\r
+ void *target = cxCollectionStoresPointers(dst) ? NULL : dst_mem;\r
+ void* dst_ptr = clone_func(target, entry->value, clone_allocator, data);\r
+ if (dst_ptr == NULL) {\r
+ cx_map_remove_uninitialized_entry(dst, *(entry->key));\r
+ return 1;\r
+ }\r
+ if (cxCollectionStoresPointers(dst)) {\r
+ *dst_mem = dst_ptr;\r
+ }\r
+ }\r
+ return 0;\r
+}\r
+\r
+int cxMapListIntersection(CxMap *dst, const CxMap *src, const CxList *keys,\r
+ cx_clone_func clone_func, const CxAllocator *clone_allocator, void *data) {\r
+ if (clone_allocator == NULL) clone_allocator = cxDefaultAllocator;\r
+\r
+ CxMapIterator src_iter = cxMapIterator(src);\r
+ cx_foreach(const CxMapEntry *, entry, src_iter) {\r
+ if (!cxListContains(keys, entry->key)) {\r
+ continue;\r
+ }\r
+ void** dst_mem = cxMapEmplace(dst, *entry->key);\r
+ if (dst_mem == NULL) {\r
+ return 1; // LCOV_EXCL_LINE\r
+ }\r
+ void *target = cxCollectionStoresPointers(dst) ? NULL : dst_mem;\r
+ void* dst_ptr = clone_func(target, entry->value, clone_allocator, data);\r
+ if (dst_ptr == NULL) {\r
+ cx_map_remove_uninitialized_entry(dst, *(entry->key));\r
+ return 1;\r
+ }\r
+ if (cxCollectionStoresPointers(dst)) {\r
+ *dst_mem = dst_ptr;\r
+ }\r
+ }\r
+ return 0;\r
+}\r
+\r
+int cxMapUnion(CxMap *dst, const CxMap *src,\r
+ cx_clone_func clone_func, const CxAllocator *clone_allocator, void *data) {\r
+ if (clone_allocator == NULL) clone_allocator = cxDefaultAllocator;\r
+\r
+ CxMapIterator src_iter = cxMapIterator(src);\r
+ cx_foreach(const CxMapEntry *, entry, src_iter) {\r
+ if (cxMapContains(dst, *entry->key)) {\r
+ continue;\r
+ }\r
+ void** dst_mem = cxMapEmplace(dst, *entry->key);\r
+ if (dst_mem == NULL) {\r
+ return 1; // LCOV_EXCL_LINE\r
+ }\r
+ void *target = cxCollectionStoresPointers(dst) ? NULL : dst_mem;\r
+ void* dst_ptr = clone_func(target, entry->value, clone_allocator, data);\r
+ if (dst_ptr == NULL) {\r
+ cx_map_remove_uninitialized_entry(dst, *(entry->key));\r
+ return 1;\r
+ }\r
+ if (cxCollectionStoresPointers(dst)) {\r
+ *dst_mem = dst_ptr;\r
+ }\r
+ }\r
+ return 0;\r
+}\r
+\r
+int cxMapCloneSimple(CxMap *dst, const CxMap *src) {\r
+ return cxMapClone(dst, src, use_simple_clone_func(src));\r
+}\r
+\r
+int cxMapDifferenceSimple(CxMap *dst, const CxMap *minuend, const CxMap *subtrahend) {\r
+ return cxMapDifference(dst, minuend, subtrahend, use_simple_clone_func(minuend));\r
+}\r
+\r
+int cxMapListDifferenceSimple(CxMap *dst, const CxMap *src, const CxList *keys) {\r
+ return cxMapListDifference(dst, src, keys, use_simple_clone_func(src));\r
+}\r
+\r
+int cxMapIntersectionSimple(CxMap *dst, const CxMap *src, const CxMap *other) {\r
+ return cxMapIntersection(dst, src, other, use_simple_clone_func(src));\r
+}\r
+\r
+int cxMapListIntersectionSimple(CxMap *dst, const CxMap *src, const CxList *keys) {\r
+ return cxMapListIntersection(dst, src, keys, use_simple_clone_func(src));\r
+}\r
+\r
+int cxMapUnionSimple(CxMap *dst, const CxMap *src) {\r
+ return cxMapUnion(dst, src, use_simple_clone_func(src));\r
+}\r
if (!ptr) return;
struct cx_mempool_s *pool = p;
+ cx_destructor_func destr = pool->destr;
+ cx_destructor_func2 destr2 = pool->destr2;
+
struct cx_mempool_memory_s *mem =
(void*) ((char *) ptr - sizeof(struct cx_mempool_memory_s));
if (mem->destructor) {
mem->destructor(mem->c);
}
- if (pool->destr) {
- pool->destr(mem->c);
+ if (destr != NULL) {
+ destr(mem->c);
}
- if (pool->destr2) {
- pool->destr2(pool->destr2_data, mem->c);
+ if (destr2 != NULL) {
+ destr2(pool->destr2_data, mem->c);
}
cxFree(pool->base_allocator, mem);
size_t last_index = pool->size - 1;
}
static void cx_mempool_free_all_simple(const struct cx_mempool_s *pool) {
- const bool has_destr = pool->destr;
- const bool has_destr2 = pool->destr2;
+ cx_destructor_func destr = pool->destr;
+ cx_destructor_func2 destr2 = pool->destr2;
for (size_t i = 0; i < pool->size; i++) {
struct cx_mempool_memory_s *mem = pool->data[i];
if (mem->destructor) {
mem->destructor(mem->c);
}
- if (has_destr) {
- pool->destr(mem->c);
+ if (destr != NULL) {
+ destr(mem->c);
}
- if (has_destr2) {
- pool->destr2(pool->destr2_data, mem->c);
+ if (destr2 != NULL) {
+ destr2(pool->destr2_data, mem->c);
}
cxFree(pool->base_allocator, mem);
}
if (!ptr) return;
struct cx_mempool_s *pool = p;
+ cx_destructor_func destr = pool->destr;
+ cx_destructor_func2 destr2 = pool->destr2;
+
struct cx_mempool_memory2_s *mem =
(void*) ((char *) ptr - sizeof(struct cx_mempool_memory2_s));
if (mem->destructor) {
mem->destructor(mem->data, mem->c);
}
- if (pool->destr) {
- pool->destr(mem->c);
+ if (destr != NULL) {
+ destr(mem->c);
}
- if (pool->destr2) {
- pool->destr2(pool->destr2_data, mem->c);
+ if (destr2 != NULL) {
+ destr2(pool->destr2_data, mem->c);
}
cxFree(pool->base_allocator, mem);
size_t last_index = pool->size - 1;
}
static void cx_mempool_free_all_advanced(const struct cx_mempool_s *pool) {
- const bool has_destr = pool->destr;
- const bool has_destr2 = pool->destr2;
+ cx_destructor_func destr = pool->destr;
+ cx_destructor_func2 destr2 = pool->destr2;
for (size_t i = 0; i < pool->size; i++) {
struct cx_mempool_memory2_s *mem = pool->data[i];
if (mem->destructor) {
mem->destructor(mem->data, mem->c);
}
- if (has_destr) {
- pool->destr(mem->c);
+ if (destr != NULL) {
+ destr(mem->c);
}
- if (has_destr2) {
- pool->destr2(pool->destr2_data, mem->c);
+ if (destr2 != NULL) {
+ destr2(pool->destr2_data, mem->c);
}
cxFree(pool->base_allocator, mem);
}
if (!ptr) return;
struct cx_mempool_s *pool = p;
+ cx_destructor_func destr = pool->destr;
+ cx_destructor_func2 destr2 = pool->destr2;
+
for (size_t i = 0; i < pool->size; i++) {
if (ptr == pool->data[i]) {
- if (pool->destr) {
- pool->destr(ptr);
+ if (destr != NULL) {
+ destr(ptr);
}
- if (pool->destr2) {
- pool->destr2(pool->destr2_data, ptr);
+ if (destr2 != NULL) {
+ destr2(pool->destr2_data, ptr);
}
cxFree(pool->base_allocator, ptr);
size_t last_index = pool->size - 1;
}
static void cx_mempool_free_all_pure(const struct cx_mempool_s *pool) {
- const bool has_destr = pool->destr;
- const bool has_destr2 = pool->destr2;
+ cx_destructor_func destr = pool->destr;
+ cx_destructor_func2 destr2 = pool->destr2;
for (size_t i = 0; i < pool->size; i++) {
void *mem = pool->data[i];
- if (has_destr) {
- pool->destr(mem);
+ if (destr != NULL) {
+ destr(mem);
}
- if (has_destr2) {
- pool->destr2(pool->destr2_data, mem);
+ if (destr2 != NULL) {
+ destr2(pool->destr2_data, mem);
}
cxFree(pool->base_allocator, mem);
}
va_copy(ap2, ap);
int ret = vsnprintf(buf, CX_PRINTF_SBO_SIZE, fmt, ap);
if (ret < 0) {
+ // LCOV_EXCL_START
va_end(ap2);
return ret;
+ // LCOV_EXCL_STOP
} else if (ret < CX_PRINTF_SBO_SIZE) {
va_end(ap2);
return (int) wfc(buf, 1, ret, stream);
if (s.ptr) {
ret = vsnprintf(s.ptr, len, fmt, ap2);
if (ret < 0) {
+ // LCOV_EXCL_START
cxFree(a, s.ptr);
s.ptr = NULL;
+ // LCOV_EXCL_STOP
} else {
s.length = (size_t) ret;
}
if (ptr) {
int newret = vsnprintf(ptr, newlen, fmt, ap2);
if (newret < 0) {
- cxFree(alloc, ptr);
+ cxFree(alloc, ptr); // LCOV_EXCL_LINE
} else {
*len = newlen;
*str = ptr;
if (ptr) {
int newret = vsnprintf(ptr, newlen, fmt, ap2);
if (newret < 0) {
- cxFree(alloc, ptr);
+ cxFree(alloc, ptr); // LCOV_EXCL_LINE
} else {
*len = newlen;
*str = ptr;
cxBufferDestroy(&prop->buffer);
}
+void cxPropertiesReset(CxProperties *prop) {
+ CxPropertiesConfig config = prop->config;
+ cxPropertiesDestroy(prop);
+ cxPropertiesInit(prop, config);
+}
+
int cxPropertiesFilln(
CxProperties *prop,
const char *buf,
// still not enough data, copy input buffer to internal buffer
if (cxBufferAppend(input.ptr, 1,
input.length, &prop->buffer) < input.length) {
- 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);
// initialize reader
if (source.read_init_func != NULL) {
if (source.read_init_func(prop, &source)) {
- return CX_PROPERTIES_READ_INIT_FAILED;
+ return CX_PROPERTIES_READ_INIT_FAILED; // LCOV_EXCL_LINE
}
}
while (true) {
// read input
cxstring input;
- if (source.read_func(prop, &source, &input)) {
+ if (source.read_func(prop, &source, &input)) { // LCOV_EXCL_START
status = CX_PROPERTIES_READ_FAILED;
break;
- }
+ } // LCOV_EXCL_STOP
// no more data - break
if (input.length == 0) {
if (kv_status == CX_PROPERTIES_NO_ERROR) {
found = true;
if (sink.sink_func(prop, &sink, key, value)) {
- kv_status = CX_PROPERTIES_SINK_FAILED;
+ kv_status = CX_PROPERTIES_SINK_FAILED; // LCOV_EXCL_LINE
}
}
} while (kv_status == CX_PROPERTIES_NO_ERROR);
cxstring src
) {
if (cxReallocate(alloc, &dest->ptr, src.length + 1)) {
- return 1;
+ return 1; // LCOV_EXCL_LINE
}
memcpy(dest->ptr, src.ptr, src.length);
size_t slen = str.length;
for (size_t i = 0; i < count; i++) {
cxstring s = va_arg(ap, cxstring);
- if (slen > SIZE_MAX - str.length) overflow = true;
+ if (slen > SIZE_MAX - s.length) overflow = true;
slen += s.length;
}
va_end(ap);
} else {
newstr = cxRealloc(alloc, str.ptr, slen + 1);
}
- if (newstr == NULL) {
+ if (newstr == NULL) { // LCOV_EXCL_START
va_end(ap2);
return (cxmutstr) {NULL, 0};
- }
+ } // LCOV_EXCL_STOP
str.ptr = newstr;
// concatenate strings
delim, limit, (cxstring **) output);
}
-int cx_strcmp(
+int cx_strcmp_(
cxstring s1,
cxstring s2
) {
}
}
-int cx_strcasecmp(
+int cx_strcasecmp_(
cxstring s1,
cxstring s2
) {
cxMalloc(allocator, string.length + 1),
string.length
};
+ // LCOV_EXCL_START
if (result.ptr == NULL) {
result.length = 0;
return result;
}
+ // LCOV_EXCL_STOP
memcpy(result.ptr, string.ptr, string.length);
result.ptr[string.length] = '\0';
return result;
return (cxmutstr) {(char *) result.ptr, result.length};
}
-bool cx_strprefix(
+bool cx_strprefix_(
cxstring string,
cxstring prefix
) {
return memcmp(string.ptr, prefix.ptr, prefix.length) == 0;
}
-bool cx_strsuffix(
+bool cx_strsuffix_(
cxstring string,
cxstring suffix
) {
suffix.ptr, suffix.length) == 0;
}
-bool cx_strcaseprefix(
+bool cx_strcaseprefix_(
cxstring string,
cxstring prefix
) {
#endif
}
-bool cx_strcasesuffix(
+bool cx_strcasesuffix_(
cxstring string,
cxstring suffix
) {
iter.skip = false;
// assign base iterator functions
- iter.base.mutating = false;
+ iter.base.allow_remove = false;
iter.base.remove = false;
iter.base.current_impl = NULL;
iter.base.valid = cx_tree_iter_valid;
iter.queue_last = NULL;
// assign base iterator functions
- iter.base.mutating = false;
+ iter.base.allow_remove = false;
iter.base.remove = false;
iter.base.current_impl = NULL;
iter.base.valid = cx_tree_visitor_valid;
ptrdiff_t loc_next
) {
*cnode = cfunc(src, cdata);
- if (*cnode == NULL) return 1;
+ if (*cnode == NULL) return 1; // LCOV_EXCL_LINE
cx_tree_zero_pointers(*cnode, cx_tree_ptr_locations);
void *match = NULL;
// create the new node
void *new_node = cfunc(elem, cdata);
- if (new_node == NULL) return processed;
+ if (new_node == NULL) return processed; // LCOV_EXCL_LINE
cx_tree_zero_pointers(new_node, cx_tree_ptr_locations);
// start searching from current node
}
// otherwise, create iterator and hand over to other function
- CxIterator iter = cxIterator(src, elem_size, num);
+ CxIterator iter = cxIterator(src, elem_size, num, false);
return cx_tree_add_iter(cxIteratorRef(iter), num, sfunc,
cfunc, cdata, failed, root,
loc_parent, loc_children, loc_last_child,
void *node;
if (tree->root == NULL) {
node = tree->node_create(data, tree);
- if (node == NULL) return 1;
+ if (node == NULL) return 1; // LCOV_EXCL_LINE
cx_tree_zero_pointers(node, cx_tree_node_layout(tree));
tree->root = node;
tree->size = 1;
// 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;
+ if (node == NULL) return 0; // LCOV_EXCL_LINE
cx_tree_zero_pointers(node, cx_tree_node_layout(tree));
tree->root = node;
ins = 1;
const void *data,
size_t depth
) {
- if (tree->root == NULL) return NULL;
+ if (tree->root == NULL) return NULL; // LCOV_EXCL_LINE
void *found;
if (0 == cx_tree_search_data(
cx_tree_default_find
};
-CxTree *cxTreeCreate(
- const CxAllocator *allocator,
+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
+ 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(search_data_func != NULL);
CxTree *tree = cxMalloc(allocator, sizeof(CxTree));
- if (tree == NULL) return NULL;
+ if (tree == NULL) return NULL; // LCOV_EXCL_LINE
tree->cl = &cx_tree_default_class;
tree->allocator = allocator;
cxFree(tree->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
-) {
+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 = cxMalloc(allocator, sizeof(CxTree));
- if (tree == NULL) return NULL;
+ if (tree == NULL) return NULL; // LCOV_EXCL_LINE
tree->cl = &cx_tree_default_class;
// set the allocator anyway, just in case...
return tree;
}
-void cxTreeSetParent(
- CxTree *tree,
- void *parent,
- void *child
-) {
+void cxTreeSetParent(CxTree *tree, void *parent, void *child) {
size_t loc_parent = tree->loc_parent;
if (tree_parent(child) == NULL) {
tree->size++;
cx_tree_link(parent, child, cx_tree_node_layout(tree));
}
-void cxTreeAddChildNode(
- CxTree *tree,
- void *parent,
- void *child
-) {
+void cxTreeAddChildNode(CxTree *tree, void *parent, void *child) {
cx_tree_link(parent, child, cx_tree_node_layout(tree));
tree->size++;
}
-int cxTreeAddChild(
- CxTree *tree,
- void *parent,
- const void *data) {
+int cxTreeAddChild(CxTree *tree, void *parent, const void *data) {
void *node = tree->node_create(data, tree);
- if (node == NULL) return 1;
+ 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));
tree->size++;
return 0;
}
+int cxTreeInsert(CxTree *tree, const void *data) {
+ return tree->cl->insert_element(tree, data);
+}
+
+size_t cxTreeInsertIter(CxTree *tree, CxIteratorBase *iter, size_t n) {
+ return tree->cl->insert_many(tree, iter, n);
+}
+
+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, false);
+ return cxTreeInsertIter(tree, cxIteratorRef(iter), n);
+}
+
+void *cxTreeFind( CxTree *tree, const void *data) {
+ return tree->cl->find(tree, tree->root, data, 0);
+}
+
+void *cxTreeFindInSubtree(CxTree *tree, const void *data, void *subtree_root, size_t max_depth) {
+ return tree->cl->find(tree, subtree_root, data, max_depth);
+}
+
size_t cxTreeSubtreeSize(CxTree *tree, void *subtree_root) {
CxTreeVisitor visitor = cx_tree_visitor(
subtree_root,
return visitor.depth;
}
+size_t cxTreeSize(CxTree *tree) {
+ return tree->size;
+}
+
size_t cxTreeDepth(CxTree *tree) {
CxTreeVisitor visitor = cx_tree_visitor(
tree->root, tree->loc_children, tree->loc_next
tree->root = NULL;
}
}
+
+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;
+ }
+ visitor->queue_next = visitor->queue_last = NULL;
+}
+
+CxTreeIterator cxTreeIterateSubtree(CxTree *tree, void *node, bool visit_on_exit) {
+ return cx_tree_iterator(
+ node, visit_on_exit,
+ tree->loc_children, tree->loc_next
+ );
+}
+
+CxTreeVisitor cxTreeVisitSubtree(CxTree *tree, void *node) {
+ return cx_tree_visitor(
+ node, tree->loc_children, tree->loc_next
+ );
+}
+
+CxTreeIterator cxTreeIterate(CxTree *tree, bool visit_on_exit) {
+ return cxTreeIterateSubtree(tree, tree->root, visit_on_exit);
+}
+
+CxTreeVisitor cxTreeVisit(CxTree *tree) {
+ return cxTreeVisitSubtree(tree, tree->root);
+}