From 8ac0fad5d22ba8010b2efee193041267526f8641 Mon Sep 17 00:00:00 2001 From: Olaf Wintermann Date: Sun, 30 Nov 2025 18:23:23 +0100 Subject: [PATCH] update ucx to version 3.2 --- ucx/array_list.c | 135 ++++++++++++++++++++----------------- ucx/buffer.c | 127 ++++++++++++++++++++++++---------- ucx/cx/array_list.h | 9 +++ ucx/cx/buffer.h | 39 ++++++++++- ucx/cx/common.h | 3 + ucx/cx/json.h | 157 ++++++++++++++++++++++++++++++++++--------- ucx/cx/linked_list.h | 24 +++++++ ucx/cx/tree.h | 4 +- ucx/hash_map.c | 11 +-- ucx/json.c | 58 +++++++--------- ucx/kv_list.c | 4 +- ucx/linked_list.c | 34 ++++++++-- ucx/list.c | 2 +- ucx/printf.c | 8 ++- ucx/properties.c | 10 +-- ucx/string.c | 10 +-- ucx/tree.c | 17 ++--- 17 files changed, 452 insertions(+), 200 deletions(-) diff --git a/ucx/array_list.c b/ucx/array_list.c index 964873f..102ec58 100644 --- a/ucx/array_list.c +++ b/ucx/array_list.c @@ -42,10 +42,11 @@ static void *cx_array_default_realloc( 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); } @@ -66,10 +67,11 @@ static void *cx_array_advanced_realloc( ) { // 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->allocator; @@ -108,13 +110,11 @@ struct cx_array_reallocator_s cx_array_reallocator( * * @param current_capacity the current capacity of the array * @param needed_capacity the required capacity of the array - * @param maximum_capacity the maximum capacity (given by the data type) * @return the new capacity */ static size_t cx_array_grow_capacity( size_t current_capacity, - size_t needed_capacity, - size_t maximum_capacity + size_t needed_capacity ) { if (current_capacity >= needed_capacity) { return current_capacity; @@ -125,12 +125,7 @@ static size_t cx_array_grow_capacity( else if (cap < 1024) alignment = 64; else if (cap < 8192) alignment = 512; else alignment = 1024; - - if (cap - 1 > maximum_capacity - alignment) { - return maximum_capacity; - } else { - return cap - (cap % alignment) + alignment; - } + return cap - (cap % alignment) + alignment; } int cx_array_reserve( @@ -288,7 +283,7 @@ int cx_array_copy( const size_t newsize = oldsize < minsize ? minsize : oldsize; // reallocate if necessary - const size_t newcap = cx_array_grow_capacity(oldcap, newsize, max_size); + 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; @@ -372,17 +367,18 @@ static int cx_array_insert_sorted_impl( 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 const size_t old_size = *size; const size_t old_capacity = *capacity; // the necessary capacity is the worst case assumption, including duplicates - const size_t needed_capacity = cx_array_grow_capacity(old_capacity, - old_size + elem_count, SIZE_MAX); + 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) { @@ -421,21 +417,23 @@ static int cx_array_insert_sorted_impl( // 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) { @@ -512,26 +510,17 @@ static int cx_array_insert_sorted_impl( // 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) { @@ -599,7 +588,8 @@ int cx_array_insert_unique( 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, @@ -644,13 +634,6 @@ size_t cx_array_binary_search_inf( 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 @@ -665,6 +648,24 @@ size_t cx_array_binary_search_inf( 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, @@ -690,16 +691,25 @@ size_t cx_array_binary_search_sup( 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; } } @@ -792,14 +802,13 @@ static size_t cx_arl_insert_array( // guarantee enough capacity if (arl->capacity < list->collection.size + n) { - const size_t new_capacity = cx_array_grow_capacity(arl->capacity, - list->collection.size + n, SIZE_MAX); + 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; } @@ -843,7 +852,7 @@ static size_t cx_arl_insert_sorted( &arl->reallocator )) { // array list implementation is "all or nothing" - return 0; + return 0; // LCOV_EXCL_LINE } else { return n; } @@ -868,7 +877,7 @@ static size_t cx_arl_insert_unique( &arl->reallocator )) { // array list implementation is "all or nothing" - return 0; + return 0; // LCOV_EXCL_LINE } else { return n; } @@ -895,7 +904,7 @@ static int cx_arl_insert_iter( 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) { @@ -905,7 +914,7 @@ static int cx_arl_insert_iter( 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; diff --git a/ucx/buffer.c b/ucx/buffer.c index 658dddf..a652abc 100644 --- a/ucx/buffer.c +++ b/ucx/buffer.c @@ -35,7 +35,7 @@ #ifdef _WIN32 #include #include -static unsigned long system_page_size() { +static unsigned long system_page_size(void) { static unsigned long ps = 0; if (ps == 0) { SYSTEM_INFO sysinfo; @@ -44,16 +44,27 @@ static unsigned long system_page_size() { } return ps; } -#define SYSTEM_PAGE_SIZE system_page_size() #else #include -#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; @@ -78,9 +89,7 @@ int cxBufferInit( 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; @@ -122,7 +131,7 @@ CxBuffer *cxBufferCreate( 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 { @@ -183,6 +192,35 @@ int cxBufferSeek( } +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); @@ -200,36 +238,10 @@ bool cxBufferEof(const CxBuffer *buffer) { 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); @@ -249,6 +261,38 @@ int cxBufferMinimumCapacity( } } +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 @@ -351,8 +395,17 @@ cx_buffer_write_retry: 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 diff --git a/ucx/cx/array_list.h b/ucx/cx/array_list.h index 88f9542..da27615 100644 --- a/ucx/cx/array_list.h +++ b/ucx/cx/array_list.h @@ -676,6 +676,9 @@ CX_EXPORT int cx_array_insert_unique(void **target, size_t *size, size_t *capaci * 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(). * @@ -698,6 +701,9 @@ CX_EXPORT size_t cx_array_binary_search_inf(const void *arr, size_t size, /** * 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. * @@ -722,6 +728,9 @@ CX_EXPORT size_t cx_array_binary_search(const void *arr, size_t size, * 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(). * diff --git a/ucx/cx/buffer.h b/ucx/cx/buffer.h index 6324a0b..70b5667 100644 --- a/ucx/cx/buffer.h +++ b/ucx/cx/buffer.h @@ -118,7 +118,7 @@ struct cx_buffer_flush_config_s { /** * 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 @@ -387,6 +387,20 @@ CX_EXPORT int cxBufferShiftLeft(CxBuffer *buffer, size_t shift); cx_attr_nonnull 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. * @@ -425,11 +439,30 @@ CX_EXPORT void cxBufferReset(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. @@ -438,6 +471,7 @@ CX_EXPORT bool cxBufferEof(const CxBuffer *buffer); * @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 @@ -457,6 +491,7 @@ CX_EXPORT int cxBufferMinimumCapacity(CxBuffer *buffer, size_t capacity); * * @param buffer the buffer * @param reserve the number of bytes that shall remain reserved + * @see cxBufferReserve() * @see cxBufferMinimumCapacity() */ cx_attr_nonnull diff --git a/ucx/cx/common.h b/ucx/cx/common.h index 45a61d5..9217585 100644 --- a/ucx/cx/common.h +++ b/ucx/cx/common.h @@ -284,6 +284,9 @@ */ #define CX_INLINE __attribute__((always_inline)) static inline #else +/** + * Declares a function to be inlined. + */ #define CX_INLINE static inline #endif /** diff --git a/ucx/cx/json.h b/ucx/cx/json.h index 8856ad4..ab5af4f 100644 --- a/ucx/cx/json.h +++ b/ucx/cx/json.h @@ -556,7 +556,7 @@ CX_EXPORT void cxJsonReset(CxJson *json); * @retval non-zero internal allocation error * @see cxJsonFill() */ -cx_attr_nonnull cx_attr_access_r(2, 3) +cx_attr_nonnull_arg(1) cx_attr_access_r(2, 3) CX_EXPORT int cxJsonFilln(CxJson *json, const char *buf, size_t len); @@ -641,28 +641,27 @@ CX_EXPORT CxJsonValue* cxJsonCreateInteger(const CxAllocator* allocator, int64_t /** * 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_EXPORT CxJsonValue* cxJsonCreateString(const CxAllocator* allocator, const char *str); +cx_attr_nodiscard +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_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. @@ -760,10 +759,7 @@ CX_EXPORT int cxJsonArrAddValues(CxJsonValue* arr, CxJsonValue* const* val, size /** * Adds or replaces a value within a JSON object. * - * The value will be directly added and not copied. - * - * @note If a value with the specified @p name already exists, - * it will be (recursively) freed with its own allocator. + * Internal function - use cxJsonObjPut(). * * @param obj the JSON object * @param name the name of the value @@ -772,11 +768,29 @@ CX_EXPORT int cxJsonArrAddValues(CxJsonValue* arr, CxJsonValue* const* val, size * @retval non-zero allocation failure */ cx_attr_nonnull -CX_EXPORT int cxJsonObjPut(CxJsonValue* obj, cxstring name, CxJsonValue* child); +CX_EXPORT int cx_json_obj_put(CxJsonValue* obj, cxstring name, CxJsonValue* child); + +/** + * Adds or replaces a value within a JSON object. + * + * The value will be directly added and not copied. + * + * @note If a value with the specified @p name already exists, + * it will be (recursively) freed with its own allocator. + * + * @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 + */ +#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 @@ -784,11 +798,24 @@ CX_EXPORT int cxJsonObjPut(CxJsonValue* obj, cxstring name, CxJsonValue* child); * @see cxJsonCreateObj() */ cx_attr_nonnull -CX_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 @@ -796,11 +823,24 @@ CX_EXPORT CxJsonValue* cxJsonObjPutObj(CxJsonValue* obj, cxstring name); * @see cxJsonCreateArr() */ cx_attr_nonnull -CX_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 @@ -809,11 +849,25 @@ CX_EXPORT CxJsonValue* cxJsonObjPutArr(CxJsonValue* obj, cxstring name); * @see cxJsonCreateNumber() */ cx_attr_nonnull -CX_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 @@ -822,12 +876,24 @@ CX_EXPORT CxJsonValue* cxJsonObjPutNumber(CxJsonValue* obj, cxstring name, doubl * @see cxJsonCreateInteger() */ cx_attr_nonnull -CX_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 @@ -836,27 +902,28 @@ CX_EXPORT CxJsonValue* cxJsonObjPutInteger(CxJsonValue* obj, cxstring name, int6 * @see cxJsonObjPut() * @see cxJsonCreateString() */ -cx_attr_nonnull cx_attr_cstr_arg(3) -CX_EXPORT CxJsonValue* cxJsonObjPutString(CxJsonValue* obj, cxstring name, const char* str); +cx_attr_nonnull +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_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 @@ -865,7 +932,19 @@ CX_EXPORT CxJsonValue* cxJsonObjPutCxString(CxJsonValue* obj, cxstring name, cxs * @see cxJsonCreateLiteral() */ cx_attr_nonnull -CX_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. @@ -1187,6 +1266,20 @@ CX_EXPORT CxJsonValue *cxJsonArrRemove(CxJsonValue *value, size_t index); 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_INLINE size_t cxJsonObjSize(const CxJsonValue *value) { + return value->value.object.values_size; +} + /** * Returns an iterator over the JSON object members. * diff --git a/ucx/cx/linked_list.h b/ucx/cx/linked_list.h index 996dc58..0d29004 100644 --- a/ucx/cx/linked_list.h +++ b/ucx/cx/linked_list.h @@ -61,8 +61,15 @@ typedef struct cx_linked_list_s { * 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; /** @@ -111,6 +118,23 @@ CX_EXPORT CxList *cxLinkedListCreate(const CxAllocator *allocator, #define cxLinkedListCreateSimple(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. * diff --git a/ucx/cx/tree.h b/ucx/cx/tree.h index a1412ca..e4d10a8 100644 --- a/ucx/cx/tree.h +++ b/ucx/cx/tree.h @@ -88,6 +88,7 @@ typedef struct cx_tree_iterator_s { ptrdiff_t loc_next; /** * The total number of distinct nodes that have been passed so far. + * This includes the current node. */ size_t counter; /** @@ -185,6 +186,7 @@ typedef struct cx_tree_visitor_s { 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; /** @@ -1094,7 +1096,7 @@ CX_EXPORT CxTreeIterator cxTreeIterate(CxTree *tree, bool visit_on_exit); * @see cxTreeIterate() */ cx_attr_nonnull cx_attr_nodiscard -CxTreeVisitor cxTreeVisit(CxTree *tree); +CX_EXPORT CxTreeVisitor cxTreeVisit(CxTree *tree); /** * Sets the (new) parent of the specified child. diff --git a/ucx/hash_map.c b/ucx/hash_map.c index be02f22..504784e 100644 --- a/ucx/hash_map.c +++ b/ucx/hash_map.c @@ -117,7 +117,7 @@ static void *cx_hash_map_put( 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) { @@ -130,10 +130,10 @@ static void *cx_hash_map_put( // 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; @@ -447,15 +447,16 @@ int cxMapRehash(CxMap *map) { 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++) { diff --git a/ucx/json.c b/ucx/json.c index caf1c72..eb5fc94 100644 --- a/ucx/json.c +++ b/ucx/json.c @@ -94,7 +94,7 @@ static int json_add_objvalue(CxJsonValue *objv, CxJsonObjValue member) { 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 } } @@ -437,7 +437,7 @@ static cxmutstr unescape_string(const CxAllocator *a, cxmutstr str) { } 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) { @@ -456,7 +456,7 @@ static cxmutstr unescape_string(const CxAllocator *a, cxmutstr str) { } 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; @@ -640,6 +640,7 @@ 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; @@ -734,7 +735,8 @@ static enum cx_json_status json_parse(CxJson *json) { } } 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); @@ -815,19 +817,19 @@ static enum cx_json_status json_parse(CxJson *json) { } 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 { @@ -943,11 +945,7 @@ CxJsonValue* cxJsonCreateInteger(const CxAllocator* allocator, int64_t num) { 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; @@ -1020,7 +1018,7 @@ int cxJsonArrAddCxStrings(CxJsonValue* arr, const cxstring* str, size_t count) { 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); @@ -1050,61 +1048,56 @@ int cxJsonArrAddValues(CxJsonValue* arr, CxJsonValue* const* val, size_t 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;} @@ -1286,9 +1279,6 @@ int cx_json_write_rec( ? 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) { @@ -1350,7 +1340,9 @@ int cx_json_write_rec( 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 = ", "; diff --git a/ucx/kv_list.c b/ucx/kv_list.c index 5343be1..3d1a783 100644 --- a/ucx/kv_list.c +++ b/ucx/kv_list.c @@ -98,7 +98,7 @@ static void cx_kv_list_update_destructors(cx_kv_list *list) { } 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) { @@ -559,7 +559,7 @@ CxList *cxKvListCreate( 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); diff --git a/ucx/linked_list.c b/ucx/linked_list.c index cac413c..aa36de0 100644 --- a/ucx/linked_list.c +++ b/ucx/linked_list.c @@ -31,6 +31,15 @@ #include #include +#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 #define CX_LL_PTR(cur, off) (*(void**)(((char*)(cur))+(off))) @@ -516,7 +525,7 @@ static void cx_linked_list_sort_merge( 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; @@ -692,8 +701,13 @@ static void *cx_ll_node_at( } 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( @@ -1215,7 +1229,7 @@ static int cx_ll_insert_iter( 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; @@ -1267,12 +1281,22 @@ CxList *cxLinkedListCreate( 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; +} diff --git a/ucx/list.c b/ucx/list.c index a3a32fb..75268c5 100644 --- a/ucx/list.c +++ b/ucx/list.c @@ -1030,7 +1030,7 @@ int cxListUnion(CxList *dst, CxIterator src_iter = cxListIterator(src); CxIterator other_iter = cxListIterator(other); while (cxIteratorValid(src_iter) || cxIteratorValid(other_iter)) { - void *src_elem, *other_elem; + void *src_elem = NULL, *other_elem = NULL; int d; if (!cxIteratorValid(src_iter)) { other_elem = cxIteratorCurrent(other_iter); diff --git a/ucx/printf.c b/ucx/printf.c index 9d18673..2b684f0 100644 --- a/ucx/printf.c +++ b/ucx/printf.c @@ -61,8 +61,10 @@ int cx_vfprintf( 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); @@ -121,8 +123,10 @@ cxmutstr cx_vasprintf_a( 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; } @@ -162,7 +166,7 @@ int cx_vsprintf_a( 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; @@ -207,7 +211,7 @@ int cx_vsprintf_sa( 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; diff --git a/ucx/properties.c b/ucx/properties.c index 3583532..8f15f96 100644 --- a/ucx/properties.c +++ b/ucx/properties.c @@ -120,7 +120,7 @@ CxPropertiesStatus cxPropertiesNext( // 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); @@ -360,7 +360,7 @@ CxPropertiesStatus cxPropertiesLoad( // 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 } } @@ -371,10 +371,10 @@ CxPropertiesStatus cxPropertiesLoad( 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) { @@ -401,7 +401,7 @@ CxPropertiesStatus cxPropertiesLoad( 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); diff --git a/ucx/string.c b/ucx/string.c index 52ce290..4367594 100644 --- a/ucx/string.c +++ b/ucx/string.c @@ -91,7 +91,7 @@ int cx_strcpy_a( cxstring src ) { if (cxReallocate(alloc, &dest->ptr, src.length + 1)) { - return 1; + return 1; // LCOV_EXCL_LINE } memcpy(dest->ptr, src.ptr, src.length); @@ -137,7 +137,7 @@ cxmutstr cx_strcat_ma( 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); @@ -156,10 +156,10 @@ cxmutstr cx_strcat_ma( } 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 @@ -521,10 +521,12 @@ cxmutstr cx_strdup_a_( 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; diff --git a/ucx/tree.c b/ucx/tree.c index d948a4c..8be9b6d 100644 --- a/ucx/tree.c +++ b/ucx/tree.c @@ -566,7 +566,7 @@ int cx_tree_add( 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; @@ -627,7 +627,7 @@ size_t cx_tree_add_iter( // 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 @@ -731,7 +731,7 @@ static int cx_tree_default_insert_element( 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; @@ -758,7 +758,7 @@ static size_t cx_tree_default_insert_many( // 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; @@ -780,7 +780,7 @@ static void *cx_tree_default_find( 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( @@ -819,7 +819,7 @@ CxTree *cxTreeCreate(const CxAllocator *allocator, 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; @@ -857,7 +857,7 @@ CxTree *cxTreeCreateWrapped(const CxAllocator *allocator, void *root, 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... @@ -893,7 +893,7 @@ void cxTreeAddChildNode(CxTree *tree, void *parent, void *child) { 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++; @@ -1071,6 +1071,7 @@ void cxTreeVisitorDispose(CxTreeVisitor *visitor) { cxFreeDefault(q); q = next; } + visitor->queue_next = visitor->queue_last = NULL; } CxTreeIterator cxTreeIterateSubtree(CxTree *tree, void *node, bool visit_on_exit) { -- 2.47.3