Refactor
This commit is contained in:
parent
8b02eff3b7
commit
cd1c1cd5db
@ -21,7 +21,7 @@ endif ()
|
||||
add_executable(libguf_example src/test/example.c src/test/guf_dict_impl.c)
|
||||
target_include_directories(libguf_example PRIVATE src src/test)
|
||||
|
||||
add_executable(libguf_test src/test/test.cpp src/test/guf_dbuf_impl.c src/test/guf_dict_impl.c src/test/guf_rand_impl.c src/test/guf_sort_impl.c src/test/guf_utf8_impl.c)
|
||||
add_executable(libguf_test src/test/test.cpp src/test/guf_dbuf_impl.c src/test/guf_dict_impl.c src/test/guf_rand_impl.c src/test/guf_sort_impl.c src/test/guf_str_impl.c)
|
||||
target_include_directories(libguf_test PRIVATE src src/test)
|
||||
|
||||
if (NOT DEFINED MSVC)
|
||||
|
||||
@ -6,6 +6,8 @@
|
||||
#include <inttypes.h>
|
||||
#include <stddef.h>
|
||||
|
||||
// #define GUF_HASH_32_BIT
|
||||
|
||||
/*
|
||||
// Copy- and move constructors:
|
||||
GUF_T_COPY: GUF_T *(*copy)(GUF_T *dst, const GUF_T *src, void *ctx);
|
||||
@ -31,7 +33,7 @@ typedef enum guf_cpy_opt {
|
||||
|
||||
#define GUF_MIN(X, Y) ((X) < (Y) ? (X) : (Y))
|
||||
#define GUF_MAX(X, Y) ((X) > (Y) ? (X) : (Y))
|
||||
#define GUF_CLAMP(X, MIN, MAX) GUF_MAX(GUF_MIN((X), (MAX)), (MIN))
|
||||
#define GUF_CLAMP(X, MIN, MAX) (GUF_MAX(GUF_MIN((X), (MAX)), (MIN)))
|
||||
|
||||
// The GUF_CAT/GUF_TOK_CAT indirection is necessary because the ## operation alone does not evaluate the macro arguments.
|
||||
#define GUF_TOK_CAT(a, b) a##b
|
||||
|
||||
433
src/guf_dbuf.h
433
src/guf_dbuf.h
@ -1,3 +1,9 @@
|
||||
#if defined(GUF_DBUF_STATIC_IMPL)
|
||||
#define GUF_DBUF_KWRDS static
|
||||
#else
|
||||
#define GUF_DBUF_KWRDS
|
||||
#endif
|
||||
|
||||
#ifndef GUF_DBUF_H
|
||||
#define GUF_DBUF_H
|
||||
#include "guf_common.h"
|
||||
@ -9,7 +15,7 @@
|
||||
/*
|
||||
Template parameters:
|
||||
- GUF_T: The value type stored in the container.
|
||||
- GUF_CNT_NAME: The typename of the resulting container (default: dbuf_GUF_T)
|
||||
- GUF_DBUF_NAME: The typename of the resulting container (default: dbuf_GUF_T)
|
||||
- GUF_T_IS_INTEGRAL_TYPE: whether the type is an integral type (if defined, must not define COPY, MOVE, FREE and EQ)
|
||||
|
||||
- GUF_T_COPY: cpy function with signature GUF_T *copy(GUF_T *dst, const GUF_T *src, void *ctx) (default: copy by value)
|
||||
@ -25,25 +31,24 @@
|
||||
#error "Undefined container template GUF_T"
|
||||
#endif
|
||||
|
||||
#ifndef GUF_CNT_NAME
|
||||
#define GUF_CNT_NAME GUF_CAT(dbuf_, GUF_T)
|
||||
#ifndef GUF_DBUF_NAME
|
||||
#define GUF_DBUF_NAME GUF_CAT(dbuf_, GUF_T)
|
||||
#endif
|
||||
|
||||
#ifdef GUF_ONLY_TYPES
|
||||
#undef GUF_ONLY_TYPES
|
||||
typedef struct GUF_CNT_NAME {
|
||||
#ifdef GUF_DBUF_ONLY_TYPES
|
||||
typedef struct GUF_DBUF_NAME {
|
||||
GUF_T *data;
|
||||
ptrdiff_t size, capacity;
|
||||
guf_allocator *allocator;
|
||||
#ifdef GUF_CNT_WITH_ELEM_CTX
|
||||
void *elem_ctx; // NULL by default; is passed as the ctx argument to GUF_T_COPY, GUF_T_MOVE and GUF_T_FREE
|
||||
#endif
|
||||
} GUF_CNT_NAME;
|
||||
} GUF_DBUF_NAME;
|
||||
|
||||
typedef struct GUF_CAT(GUF_CNT_NAME, _iter) {
|
||||
typedef struct GUF_CAT(GUF_DBUF_NAME, _iter) {
|
||||
GUF_T *ptr;
|
||||
GUF_T *base; // Not NULL For reverse iterators (unless dbuf->size == 0, then ptr and base are NULL for both iterator types)
|
||||
} GUF_CAT(GUF_CNT_NAME, _iter);
|
||||
} GUF_CAT(GUF_DBUF_NAME, _iter);
|
||||
#else
|
||||
|
||||
// Used for the first growth if dbuf->capacity is zero.
|
||||
@ -59,22 +64,16 @@
|
||||
#error "Integral types do not need COPY, MOVE, FREE or EQ functions"
|
||||
#endif
|
||||
|
||||
#if defined(GUF_STATIC) || defined(GUF_IMPL_STATIC)
|
||||
#define GUF_FN_KEYWORDS static
|
||||
#else
|
||||
#define GUF_FN_KEYWORDS
|
||||
#endif
|
||||
#if !defined(GUF_DBUF_IMPL) && !defined(GUF_DBUF_WITHOUT_TYPES)
|
||||
|
||||
#if !defined(GUF_IMPL)
|
||||
|
||||
typedef struct GUF_CNT_NAME {
|
||||
typedef struct GUF_DBUF_NAME {
|
||||
GUF_T *data;
|
||||
ptrdiff_t size, capacity;
|
||||
guf_allocator *allocator;
|
||||
#ifdef GUF_CNT_WITH_ELEM_CTX
|
||||
void *elem_ctx; // NULL by default; is passed as the ctx argument to GUF_T_COPY, GUF_T_MOVE and GUF_T_FREE
|
||||
#endif
|
||||
} GUF_CNT_NAME;
|
||||
} GUF_DBUF_NAME;
|
||||
|
||||
/*
|
||||
- Regular iterator: base is always NULL
|
||||
@ -84,93 +83,93 @@ typedef struct GUF_CNT_NAME {
|
||||
- rend(): base points to begin().ptr and ptr to NULL
|
||||
- reverse iterator for the first element of the container: base points to the second element, ptr points to the first element
|
||||
*/
|
||||
typedef struct GUF_CAT(GUF_CNT_NAME, _iter) {
|
||||
typedef struct GUF_CAT(GUF_DBUF_NAME, _iter) {
|
||||
GUF_T *ptr;
|
||||
GUF_T *base; // Not NULL For reverse iterators (unless dbuf->size == 0, then ptr and base are NULL for both iterator types)
|
||||
} GUF_CAT(GUF_CNT_NAME, _iter);
|
||||
} GUF_CAT(GUF_DBUF_NAME, _iter);
|
||||
|
||||
#endif
|
||||
|
||||
GUF_FN_KEYWORDS bool GUF_CAT(GUF_CNT_NAME, _valid)(const GUF_CNT_NAME* dbuf);
|
||||
GUF_DBUF_KWRDS bool GUF_CAT(GUF_DBUF_NAME, _valid)(const GUF_DBUF_NAME* dbuf);
|
||||
|
||||
GUF_FN_KEYWORDS void GUF_CAT(GUF_CNT_NAME, _try_reserve)(GUF_CNT_NAME *dbuf, ptrdiff_t min_capacity, guf_err *err);
|
||||
GUF_FN_KEYWORDS void GUF_CAT(GUF_CNT_NAME, _reserve)(GUF_CNT_NAME *dbuf, ptrdiff_t min_capacity);
|
||||
GUF_DBUF_KWRDS void GUF_CAT(GUF_DBUF_NAME, _try_reserve)(GUF_DBUF_NAME *dbuf, ptrdiff_t min_capacity, guf_err *err);
|
||||
GUF_DBUF_KWRDS void GUF_CAT(GUF_DBUF_NAME, _reserve)(GUF_DBUF_NAME *dbuf, ptrdiff_t min_capacity);
|
||||
|
||||
GUF_FN_KEYWORDS void GUF_CAT(GUF_CNT_NAME, _try_init)(GUF_CNT_NAME *dbuf, ptrdiff_t capacity, guf_allocator *allocator, guf_err *err);
|
||||
GUF_FN_KEYWORDS void GUF_CAT(GUF_CNT_NAME, _init)(GUF_CNT_NAME *dbuf, ptrdiff_t start_cap, guf_allocator *allocator);
|
||||
GUF_FN_KEYWORDS GUF_CNT_NAME GUF_CAT(GUF_CNT_NAME, _new)(guf_allocator *allocator);
|
||||
GUF_FN_KEYWORDS GUF_CNT_NAME GUF_CAT(GUF_CNT_NAME, _try_new_with_capacity)(ptrdiff_t capacity, guf_allocator *allocator, guf_err *err);
|
||||
GUF_FN_KEYWORDS GUF_CNT_NAME GUF_CAT(GUF_CNT_NAME, _new_with_capacity)(ptrdiff_t capacity, guf_allocator *allocator);
|
||||
GUF_DBUF_KWRDS void GUF_CAT(GUF_DBUF_NAME, _try_init)(GUF_DBUF_NAME *dbuf, ptrdiff_t capacity, guf_allocator *allocator, guf_err *err);
|
||||
GUF_DBUF_KWRDS void GUF_CAT(GUF_DBUF_NAME, _init)(GUF_DBUF_NAME *dbuf, ptrdiff_t start_cap, guf_allocator *allocator);
|
||||
GUF_DBUF_KWRDS GUF_DBUF_NAME GUF_CAT(GUF_DBUF_NAME, _new)(guf_allocator *allocator);
|
||||
GUF_DBUF_KWRDS GUF_DBUF_NAME GUF_CAT(GUF_DBUF_NAME, _try_new_with_capacity)(ptrdiff_t capacity, guf_allocator *allocator, guf_err *err);
|
||||
GUF_DBUF_KWRDS GUF_DBUF_NAME GUF_CAT(GUF_DBUF_NAME, _new_with_capacity)(ptrdiff_t capacity, guf_allocator *allocator);
|
||||
|
||||
#ifdef GUF_CNT_WITH_ELEM_CTX
|
||||
GUF_FN_KEYWORDS void GUF_CAT(GUF_CNT_NAME, _set_elem_ctx)(GUF_CNT_NAME *dbuf, void *elem_ctx);
|
||||
GUF_DBUF_KWRDS void GUF_CAT(GUF_DBUF_NAME, _set_elem_ctx)(GUF_DBUF_NAME *dbuf, void *elem_ctx);
|
||||
#endif
|
||||
GUF_FN_KEYWORDS void *GUF_CAT(GUF_CNT_NAME, _get_elem_ctx)(const GUF_CNT_NAME *dbuf); // Always returns NULL if GUF_CNT_WITH_ELEM_CTX is not defined
|
||||
GUF_DBUF_KWRDS void *GUF_CAT(GUF_DBUF_NAME, _get_elem_ctx)(const GUF_DBUF_NAME *dbuf); // Always returns NULL if GUF_CNT_WITH_ELEM_CTX is not defined
|
||||
|
||||
GUF_FN_KEYWORDS void GUF_CAT(GUF_CNT_NAME, _free)(GUF_CNT_NAME *dbuf, void *ctx);
|
||||
GUF_FN_KEYWORDS GUF_CNT_NAME *GUF_CAT(GUF_CNT_NAME, _copy)(GUF_CNT_NAME *dst, const GUF_CNT_NAME *src, void *ctx);
|
||||
GUF_FN_KEYWORDS GUF_CNT_NAME *GUF_CAT(GUF_CNT_NAME, _move)(GUF_CNT_NAME *dst, GUF_CNT_NAME *src, void *ctx);
|
||||
GUF_DBUF_KWRDS void GUF_CAT(GUF_DBUF_NAME, _free)(GUF_DBUF_NAME *dbuf, void *ctx);
|
||||
GUF_DBUF_KWRDS GUF_DBUF_NAME *GUF_CAT(GUF_DBUF_NAME, _copy)(GUF_DBUF_NAME *dst, const GUF_DBUF_NAME *src, void *ctx);
|
||||
GUF_DBUF_KWRDS GUF_DBUF_NAME *GUF_CAT(GUF_DBUF_NAME, _move)(GUF_DBUF_NAME *dst, GUF_DBUF_NAME *src, void *ctx);
|
||||
|
||||
GUF_FN_KEYWORDS ptrdiff_t GUF_CAT(GUF_CNT_NAME, _try_get_next_capacity)(ptrdiff_t old_cap, guf_err *err);
|
||||
GUF_FN_KEYWORDS void GUF_CAT(GUF_CNT_NAME, _try_grow_if_full)(GUF_CNT_NAME *dbuf, guf_err *err);
|
||||
GUF_FN_KEYWORDS void GUF_CAT(GUF_CNT_NAME, _try_shrink_to_fit)(GUF_CNT_NAME *dbuf, guf_err *err);
|
||||
GUF_DBUF_KWRDS ptrdiff_t GUF_CAT(GUF_DBUF_NAME, _try_get_next_capacity)(ptrdiff_t old_cap, guf_err *err);
|
||||
GUF_DBUF_KWRDS void GUF_CAT(GUF_DBUF_NAME, _try_grow_if_full)(GUF_DBUF_NAME *dbuf, guf_err *err);
|
||||
GUF_DBUF_KWRDS void GUF_CAT(GUF_DBUF_NAME, _try_shrink_to_fit)(GUF_DBUF_NAME *dbuf, guf_err *err);
|
||||
|
||||
GUF_FN_KEYWORDS GUF_T *GUF_CAT(GUF_CNT_NAME, _try_insert)(GUF_CNT_NAME *dbuf, GUF_T *elem, ptrdiff_t idx, guf_cpy_opt cpy_opt, guf_err *err);
|
||||
GUF_FN_KEYWORDS GUF_T *GUF_CAT(GUF_CNT_NAME, _insert)(GUF_CNT_NAME *dbuf, GUF_T *elem, ptrdiff_t idx, guf_cpy_opt cpy_opt);
|
||||
GUF_FN_KEYWORDS GUF_T *GUF_CAT(GUF_CNT_NAME, _try_insert_val)(GUF_CNT_NAME *dbuf, GUF_T elem, ptrdiff_t idx, guf_err *err);
|
||||
GUF_FN_KEYWORDS GUF_T *GUF_CAT(GUF_CNT_NAME, _insert_val)(GUF_CNT_NAME *dbuf, GUF_T elem, ptrdiff_t idx);
|
||||
GUF_DBUF_KWRDS GUF_T *GUF_CAT(GUF_DBUF_NAME, _try_insert)(GUF_DBUF_NAME *dbuf, GUF_T *elem, ptrdiff_t idx, guf_cpy_opt cpy_opt, guf_err *err);
|
||||
GUF_DBUF_KWRDS GUF_T *GUF_CAT(GUF_DBUF_NAME, _insert)(GUF_DBUF_NAME *dbuf, GUF_T *elem, ptrdiff_t idx, guf_cpy_opt cpy_opt);
|
||||
GUF_DBUF_KWRDS GUF_T *GUF_CAT(GUF_DBUF_NAME, _try_insert_val)(GUF_DBUF_NAME *dbuf, GUF_T elem, ptrdiff_t idx, guf_err *err);
|
||||
GUF_DBUF_KWRDS GUF_T *GUF_CAT(GUF_DBUF_NAME, _insert_val)(GUF_DBUF_NAME *dbuf, GUF_T elem, ptrdiff_t idx);
|
||||
#ifdef GUF_T_COPY
|
||||
GUF_FN_KEYWORDS GUF_T *GUF_CAT(GUF_CNT_NAME, _try_insert_val_cpy)(GUF_CNT_NAME *dbuf, GUF_T elem, ptrdiff_t idx, guf_err *err);
|
||||
GUF_FN_KEYWORDS GUF_T *GUF_CAT(GUF_CNT_NAME, _insert_val_cpy)(GUF_CNT_NAME *dbuf, GUF_T elem, ptrdiff_t idx);
|
||||
GUF_DBUF_KWRDS GUF_T *GUF_CAT(GUF_DBUF_NAME, _try_insert_val_cpy)(GUF_DBUF_NAME *dbuf, GUF_T elem, ptrdiff_t idx, guf_err *err);
|
||||
GUF_DBUF_KWRDS GUF_T *GUF_CAT(GUF_DBUF_NAME, _insert_val_cpy)(GUF_DBUF_NAME *dbuf, GUF_T elem, ptrdiff_t idx);
|
||||
#endif
|
||||
|
||||
GUF_FN_KEYWORDS GUF_T *GUF_CAT(GUF_CNT_NAME, _try_push)(GUF_CNT_NAME *dbuf, GUF_T *elem, guf_cpy_opt cpy_opt, guf_err *err);
|
||||
GUF_FN_KEYWORDS GUF_T *GUF_CAT(GUF_CNT_NAME, _push)(GUF_CNT_NAME *dbuf, GUF_T *elem, guf_cpy_opt cpy_opt);
|
||||
GUF_FN_KEYWORDS GUF_T *GUF_CAT(GUF_CNT_NAME, _try_push_val)(GUF_CNT_NAME *dbuf, GUF_T elem, guf_err *err);
|
||||
GUF_FN_KEYWORDS GUF_T *GUF_CAT(GUF_CNT_NAME, _push_val)(GUF_CNT_NAME *dbuf, GUF_T elem);
|
||||
GUF_DBUF_KWRDS GUF_T *GUF_CAT(GUF_DBUF_NAME, _try_push)(GUF_DBUF_NAME *dbuf, GUF_T *elem, guf_cpy_opt cpy_opt, guf_err *err);
|
||||
GUF_DBUF_KWRDS GUF_T *GUF_CAT(GUF_DBUF_NAME, _push)(GUF_DBUF_NAME *dbuf, GUF_T *elem, guf_cpy_opt cpy_opt);
|
||||
GUF_DBUF_KWRDS GUF_T *GUF_CAT(GUF_DBUF_NAME, _try_push_val)(GUF_DBUF_NAME *dbuf, GUF_T elem, guf_err *err);
|
||||
GUF_DBUF_KWRDS GUF_T *GUF_CAT(GUF_DBUF_NAME, _push_val)(GUF_DBUF_NAME *dbuf, GUF_T elem);
|
||||
#ifdef GUF_T_COPY
|
||||
GUF_FN_KEYWORDS GUF_T *GUF_CAT(GUF_CNT_NAME, _try_push_val_cpy)(GUF_CNT_NAME *dbuf, GUF_T elem, guf_err *err);
|
||||
GUF_FN_KEYWORDS GUF_T *GUF_CAT(GUF_CNT_NAME, _push_val_cpy)(GUF_CNT_NAME *dbuf, GUF_T elem);
|
||||
GUF_DBUF_KWRDS GUF_T *GUF_CAT(GUF_DBUF_NAME, _try_push_val_cpy)(GUF_DBUF_NAME *dbuf, GUF_T elem, guf_err *err);
|
||||
GUF_DBUF_KWRDS GUF_T *GUF_CAT(GUF_DBUF_NAME, _push_val_cpy)(GUF_DBUF_NAME *dbuf, GUF_T elem);
|
||||
#endif
|
||||
|
||||
GUF_FN_KEYWORDS bool GUF_CAT(GUF_CNT_NAME, _try_erase)(GUF_CNT_NAME *dbuf, ptrdiff_t idx, guf_err *err);
|
||||
GUF_FN_KEYWORDS void GUF_CAT(GUF_CNT_NAME, _erase)(GUF_CNT_NAME *dbuf, ptrdiff_t idx);
|
||||
GUF_DBUF_KWRDS bool GUF_CAT(GUF_DBUF_NAME, _try_erase)(GUF_DBUF_NAME *dbuf, ptrdiff_t idx, guf_err *err);
|
||||
GUF_DBUF_KWRDS void GUF_CAT(GUF_DBUF_NAME, _erase)(GUF_DBUF_NAME *dbuf, ptrdiff_t idx);
|
||||
|
||||
GUF_FN_KEYWORDS bool GUF_CAT(GUF_CNT_NAME, _try_pop)(GUF_CNT_NAME *dbuf, guf_err *err);
|
||||
GUF_FN_KEYWORDS void GUF_CAT(GUF_CNT_NAME, _pop)(GUF_CNT_NAME *dbuf);
|
||||
GUF_FN_KEYWORDS GUF_T GUF_CAT(GUF_CNT_NAME, _try_pop_move)(GUF_CNT_NAME *dbuf, guf_err *err);
|
||||
GUF_FN_KEYWORDS GUF_T GUF_CAT(GUF_CNT_NAME, _pop_move)(GUF_CNT_NAME *dbuf);
|
||||
GUF_DBUF_KWRDS bool GUF_CAT(GUF_DBUF_NAME, _try_pop)(GUF_DBUF_NAME *dbuf, guf_err *err);
|
||||
GUF_DBUF_KWRDS void GUF_CAT(GUF_DBUF_NAME, _pop)(GUF_DBUF_NAME *dbuf);
|
||||
GUF_DBUF_KWRDS GUF_T GUF_CAT(GUF_DBUF_NAME, _try_pop_move)(GUF_DBUF_NAME *dbuf, guf_err *err);
|
||||
GUF_DBUF_KWRDS GUF_T GUF_CAT(GUF_DBUF_NAME, _pop_move)(GUF_DBUF_NAME *dbuf);
|
||||
|
||||
GUF_FN_KEYWORDS GUF_T *GUF_CAT(GUF_CNT_NAME, _try_at)(GUF_CNT_NAME *dbuf, ptrdiff_t idx, guf_err *err);
|
||||
GUF_FN_KEYWORDS GUF_T *GUF_CAT(GUF_CNT_NAME, _at)(GUF_CNT_NAME *dbuf, ptrdiff_t idx);
|
||||
GUF_FN_KEYWORDS GUF_T *GUF_CAT(GUF_CNT_NAME, _try_front)(GUF_CNT_NAME *dbuf, guf_err *err);
|
||||
GUF_FN_KEYWORDS GUF_T *GUF_CAT(GUF_CNT_NAME, _front)(GUF_CNT_NAME *dbuf);
|
||||
GUF_FN_KEYWORDS GUF_T *GUF_CAT(GUF_CNT_NAME, _try_back)(GUF_CNT_NAME *dbuf, guf_err *err);
|
||||
GUF_FN_KEYWORDS GUF_T *GUF_CAT(GUF_CNT_NAME, _back)(GUF_CNT_NAME *dbuf);
|
||||
GUF_DBUF_KWRDS GUF_T *GUF_CAT(GUF_DBUF_NAME, _try_at)(GUF_DBUF_NAME *dbuf, ptrdiff_t idx, guf_err *err);
|
||||
GUF_DBUF_KWRDS GUF_T *GUF_CAT(GUF_DBUF_NAME, _at)(GUF_DBUF_NAME *dbuf, ptrdiff_t idx);
|
||||
GUF_DBUF_KWRDS GUF_T *GUF_CAT(GUF_DBUF_NAME, _try_front)(GUF_DBUF_NAME *dbuf, guf_err *err);
|
||||
GUF_DBUF_KWRDS GUF_T *GUF_CAT(GUF_DBUF_NAME, _front)(GUF_DBUF_NAME *dbuf);
|
||||
GUF_DBUF_KWRDS GUF_T *GUF_CAT(GUF_DBUF_NAME, _try_back)(GUF_DBUF_NAME *dbuf, guf_err *err);
|
||||
GUF_DBUF_KWRDS GUF_T *GUF_CAT(GUF_DBUF_NAME, _back)(GUF_DBUF_NAME *dbuf);
|
||||
|
||||
GUF_FN_KEYWORDS GUF_CAT(GUF_CNT_NAME, _iter) GUF_CAT(GUF_CNT_NAME, _begin)(const GUF_CNT_NAME* dbuf);
|
||||
GUF_FN_KEYWORDS GUF_CAT(GUF_CNT_NAME, _iter) GUF_CAT(GUF_CNT_NAME, _end)(const GUF_CNT_NAME* dbuf);
|
||||
GUF_FN_KEYWORDS GUF_CAT(GUF_CNT_NAME, _iter) GUF_CAT(GUF_CNT_NAME, _rbegin)(const GUF_CNT_NAME* dbuf);
|
||||
GUF_FN_KEYWORDS GUF_CAT(GUF_CNT_NAME, _iter) GUF_CAT(GUF_CNT_NAME, _rend)(const GUF_CNT_NAME* dbuf);
|
||||
GUF_FN_KEYWORDS bool GUF_CAT(GUF_CNT_NAME, _iter_is_end)(const GUF_CNT_NAME* dbuf, GUF_CAT(GUF_CNT_NAME, _iter) it);
|
||||
GUF_DBUF_KWRDS GUF_CAT(GUF_DBUF_NAME, _iter) GUF_CAT(GUF_DBUF_NAME, _begin)(const GUF_DBUF_NAME* dbuf);
|
||||
GUF_DBUF_KWRDS GUF_CAT(GUF_DBUF_NAME, _iter) GUF_CAT(GUF_DBUF_NAME, _end)(const GUF_DBUF_NAME* dbuf);
|
||||
GUF_DBUF_KWRDS GUF_CAT(GUF_DBUF_NAME, _iter) GUF_CAT(GUF_DBUF_NAME, _rbegin)(const GUF_DBUF_NAME* dbuf);
|
||||
GUF_DBUF_KWRDS GUF_CAT(GUF_DBUF_NAME, _iter) GUF_CAT(GUF_DBUF_NAME, _rend)(const GUF_DBUF_NAME* dbuf);
|
||||
GUF_DBUF_KWRDS bool GUF_CAT(GUF_DBUF_NAME, _iter_is_end)(const GUF_DBUF_NAME* dbuf, GUF_CAT(GUF_DBUF_NAME, _iter) it);
|
||||
|
||||
GUF_FN_KEYWORDS GUF_CAT(GUF_CNT_NAME, _iter) GUF_CAT(GUF_CNT_NAME, _iter_next)(const GUF_CNT_NAME *dbuf, GUF_CAT(GUF_CNT_NAME, _iter) it, ptrdiff_t step);
|
||||
GUF_FN_KEYWORDS GUF_CAT(GUF_CNT_NAME, _iter) GUF_CAT(GUF_CNT_NAME, _iter_at_idx)(const GUF_CNT_NAME* dbuf, ptrdiff_t idx);
|
||||
GUF_FN_KEYWORDS GUF_CAT(GUF_CNT_NAME, _iter) GUF_CAT(GUF_CNT_NAME, _reverse_iter_at_idx)(const GUF_CNT_NAME* dbuf, ptrdiff_t idx);
|
||||
GUF_FN_KEYWORDS ptrdiff_t GUF_CAT(GUF_CNT_NAME, _iter_to_idx)(const GUF_CNT_NAME* dbuf, GUF_CAT(GUF_CNT_NAME, _iter) it);
|
||||
GUF_DBUF_KWRDS GUF_CAT(GUF_DBUF_NAME, _iter) GUF_CAT(GUF_DBUF_NAME, _iter_next)(const GUF_DBUF_NAME *dbuf, GUF_CAT(GUF_DBUF_NAME, _iter) it, ptrdiff_t step);
|
||||
GUF_DBUF_KWRDS GUF_CAT(GUF_DBUF_NAME, _iter) GUF_CAT(GUF_DBUF_NAME, _iter_at_idx)(const GUF_DBUF_NAME* dbuf, ptrdiff_t idx);
|
||||
GUF_DBUF_KWRDS GUF_CAT(GUF_DBUF_NAME, _iter) GUF_CAT(GUF_DBUF_NAME, _reverse_iter_at_idx)(const GUF_DBUF_NAME* dbuf, ptrdiff_t idx);
|
||||
GUF_DBUF_KWRDS ptrdiff_t GUF_CAT(GUF_DBUF_NAME, _iter_to_idx)(const GUF_DBUF_NAME* dbuf, GUF_CAT(GUF_DBUF_NAME, _iter) it);
|
||||
|
||||
#if defined(GUF_T_IS_INTEGRAL_TYPE) || defined(GUF_T_EQ)
|
||||
GUF_FN_KEYWORDS GUF_CAT(GUF_CNT_NAME, _iter) GUF_CAT(GUF_CNT_NAME, _find)(GUF_CNT_NAME *dbuf, GUF_CAT(GUF_CNT_NAME, _iter) begin, GUF_CAT(GUF_CNT_NAME, _iter) end, const GUF_T *needle);
|
||||
GUF_FN_KEYWORDS GUF_CAT(GUF_CNT_NAME, _iter) GUF_CAT(GUF_CNT_NAME, _find_val)(GUF_CNT_NAME *dbuf, GUF_CAT(GUF_CNT_NAME, _iter) begin, GUF_CAT(GUF_CNT_NAME, _iter) end, GUF_T needle_val);
|
||||
GUF_FN_KEYWORDS bool GUF_CAT(GUF_CNT_NAME, _contains)(GUF_CNT_NAME *dbuf, const GUF_T *needle);
|
||||
GUF_FN_KEYWORDS bool GUF_CAT(GUF_CNT_NAME, _contains_val)(GUF_CNT_NAME *dbuf, GUF_T needle);
|
||||
GUF_DBUF_KWRDS GUF_CAT(GUF_DBUF_NAME, _iter) GUF_CAT(GUF_DBUF_NAME, _find)(GUF_DBUF_NAME *dbuf, GUF_CAT(GUF_DBUF_NAME, _iter) begin, GUF_CAT(GUF_DBUF_NAME, _iter) end, const GUF_T *needle);
|
||||
GUF_DBUF_KWRDS GUF_CAT(GUF_DBUF_NAME, _iter) GUF_CAT(GUF_DBUF_NAME, _find_val)(GUF_DBUF_NAME *dbuf, GUF_CAT(GUF_DBUF_NAME, _iter) begin, GUF_CAT(GUF_DBUF_NAME, _iter) end, GUF_T needle_val);
|
||||
GUF_DBUF_KWRDS bool GUF_CAT(GUF_DBUF_NAME, _contains)(GUF_DBUF_NAME *dbuf, const GUF_T *needle);
|
||||
GUF_DBUF_KWRDS bool GUF_CAT(GUF_DBUF_NAME, _contains_val)(GUF_DBUF_NAME *dbuf, GUF_T needle);
|
||||
#endif
|
||||
GUF_FN_KEYWORDS GUF_CAT(GUF_CNT_NAME, _iter) GUF_CAT(GUF_CNT_NAME, _find_if)(GUF_CNT_NAME *dbuf, GUF_CAT(GUF_CNT_NAME, _iter) begin, GUF_CAT(GUF_CNT_NAME, _iter) end, bool (*predicate)(const GUF_T *));
|
||||
GUF_DBUF_KWRDS GUF_CAT(GUF_DBUF_NAME, _iter) GUF_CAT(GUF_DBUF_NAME, _find_if)(GUF_DBUF_NAME *dbuf, GUF_CAT(GUF_DBUF_NAME, _iter) begin, GUF_CAT(GUF_DBUF_NAME, _iter) end, bool (*predicate)(const GUF_T *));
|
||||
|
||||
|
||||
#if defined(GUF_IMPL) || defined(GUF_IMPL_STATIC)
|
||||
#if defined(GUF_DBUF_IMPL) || defined(GUF_DBUF_IMPL_STATIC)
|
||||
|
||||
GUF_FN_KEYWORDS bool GUF_CAT(GUF_CNT_NAME, _valid)(const GUF_CNT_NAME* dbuf)
|
||||
GUF_DBUF_KWRDS bool GUF_CAT(GUF_DBUF_NAME, _valid)(const GUF_DBUF_NAME* dbuf)
|
||||
{
|
||||
if (!dbuf) {
|
||||
return false;
|
||||
@ -180,9 +179,9 @@ GUF_FN_KEYWORDS bool GUF_CAT(GUF_CNT_NAME, _valid)(const GUF_CNT_NAME* dbuf)
|
||||
return valid_data_ptr && valid_allocator && dbuf->capacity >= 0 && dbuf->size >= 0 && dbuf->size <= dbuf->capacity;
|
||||
}
|
||||
|
||||
GUF_FN_KEYWORDS void GUF_CAT(GUF_CNT_NAME, _try_reserve)(GUF_CNT_NAME *dbuf, ptrdiff_t min_capacity, guf_err *err)
|
||||
GUF_DBUF_KWRDS void GUF_CAT(GUF_DBUF_NAME, _try_reserve)(GUF_DBUF_NAME *dbuf, ptrdiff_t min_capacity, guf_err *err)
|
||||
{
|
||||
GUF_ASSERT_RELEASE(GUF_CAT(GUF_CNT_NAME, _valid)(dbuf));
|
||||
GUF_ASSERT_RELEASE(GUF_CAT(GUF_DBUF_NAME, _valid)(dbuf));
|
||||
GUF_ASSERT_RELEASE(min_capacity >= 0);
|
||||
|
||||
if (min_capacity <= dbuf->capacity || min_capacity == 0) {
|
||||
@ -221,17 +220,17 @@ GUF_FN_KEYWORDS void GUF_CAT(GUF_CNT_NAME, _try_reserve)(GUF_CNT_NAME *dbuf, ptr
|
||||
GUF_ASSERT(dbuf->data && dbuf->capacity);
|
||||
}
|
||||
|
||||
GUF_FN_KEYWORDS void GUF_CAT(GUF_CNT_NAME, _reserve)(GUF_CNT_NAME *dbuf, ptrdiff_t min_capacity)
|
||||
GUF_DBUF_KWRDS void GUF_CAT(GUF_DBUF_NAME, _reserve)(GUF_DBUF_NAME *dbuf, ptrdiff_t min_capacity)
|
||||
{
|
||||
GUF_CAT(GUF_CNT_NAME, _try_reserve)(dbuf, min_capacity, NULL);
|
||||
GUF_CAT(GUF_DBUF_NAME, _try_reserve)(dbuf, min_capacity, NULL);
|
||||
}
|
||||
|
||||
GUF_FN_KEYWORDS void GUF_CAT(GUF_CNT_NAME, _try_init)(GUF_CNT_NAME *dbuf, ptrdiff_t capacity, guf_allocator *allocator, guf_err *err)
|
||||
GUF_DBUF_KWRDS void GUF_CAT(GUF_DBUF_NAME, _try_init)(GUF_DBUF_NAME *dbuf, ptrdiff_t capacity, guf_allocator *allocator, guf_err *err)
|
||||
{
|
||||
GUF_ASSERT_RELEASE(dbuf);
|
||||
GUF_ASSERT_RELEASE(capacity >= 0);
|
||||
|
||||
if (dbuf->size != 0 || dbuf->capacity != 0 || dbuf->data || GUF_CAT(GUF_CNT_NAME, _get_elem_ctx)(dbuf)) {
|
||||
if (dbuf->size != 0 || dbuf->capacity != 0 || dbuf->data || GUF_CAT(GUF_DBUF_NAME, _get_elem_ctx)(dbuf)) {
|
||||
guf_err_set_or_panic(err, GUF_ERR_INVALID_ARG, GUF_ERR_MSG("in function dbuf_try_init: dbuf might have been already initialised"));
|
||||
return;
|
||||
}
|
||||
@ -252,44 +251,44 @@ GUF_FN_KEYWORDS void GUF_CAT(GUF_CNT_NAME, _try_init)(GUF_CNT_NAME *dbuf, ptrdif
|
||||
dbuf->data = NULL;
|
||||
guf_err_set_if_not_null(err, GUF_ERR_NONE);
|
||||
} else {
|
||||
GUF_CAT(GUF_CNT_NAME, _try_reserve)(dbuf, capacity, err);
|
||||
GUF_CAT(GUF_DBUF_NAME, _try_reserve)(dbuf, capacity, err);
|
||||
}
|
||||
}
|
||||
|
||||
GUF_FN_KEYWORDS void GUF_CAT(GUF_CNT_NAME, _init)(GUF_CNT_NAME *dbuf, ptrdiff_t start_cap, guf_allocator *allocator)
|
||||
GUF_DBUF_KWRDS void GUF_CAT(GUF_DBUF_NAME, _init)(GUF_DBUF_NAME *dbuf, ptrdiff_t start_cap, guf_allocator *allocator)
|
||||
{
|
||||
GUF_CAT(GUF_CNT_NAME, _try_init)(dbuf, start_cap, allocator, NULL);
|
||||
GUF_CAT(GUF_DBUF_NAME, _try_init)(dbuf, start_cap, allocator, NULL);
|
||||
}
|
||||
|
||||
GUF_FN_KEYWORDS GUF_CNT_NAME GUF_CAT(GUF_CNT_NAME, _new)(guf_allocator *allocator)
|
||||
GUF_DBUF_KWRDS GUF_DBUF_NAME GUF_CAT(GUF_DBUF_NAME, _new)(guf_allocator *allocator)
|
||||
{
|
||||
GUF_CNT_NAME dbuf = {0};
|
||||
GUF_CAT(GUF_CNT_NAME, _init)(&dbuf, 0, allocator);
|
||||
GUF_DBUF_NAME dbuf = {0};
|
||||
GUF_CAT(GUF_DBUF_NAME, _init)(&dbuf, 0, allocator);
|
||||
GUF_ASSERT(dbuf.size == 0 && dbuf.capacity == 0);
|
||||
return dbuf;
|
||||
}
|
||||
|
||||
GUF_FN_KEYWORDS GUF_CNT_NAME GUF_CAT(GUF_CNT_NAME, _try_new_with_capacity)(ptrdiff_t capacity, guf_allocator *allocator, guf_err *err)
|
||||
GUF_DBUF_KWRDS GUF_DBUF_NAME GUF_CAT(GUF_DBUF_NAME, _try_new_with_capacity)(ptrdiff_t capacity, guf_allocator *allocator, guf_err *err)
|
||||
{
|
||||
GUF_CNT_NAME dbuf = {0};
|
||||
GUF_DBUF_NAME dbuf = {0};
|
||||
|
||||
GUF_CAT(GUF_CNT_NAME, _try_init)(&dbuf, capacity, allocator, err);
|
||||
GUF_CAT(GUF_DBUF_NAME, _try_init)(&dbuf, capacity, allocator, err);
|
||||
if (err && *err != GUF_ERR_NONE) {
|
||||
return (GUF_CNT_NAME){0};
|
||||
return (GUF_DBUF_NAME){0};
|
||||
}
|
||||
guf_err_set_if_not_null(err, GUF_ERR_NONE);
|
||||
return dbuf;
|
||||
}
|
||||
|
||||
GUF_FN_KEYWORDS GUF_CNT_NAME GUF_CAT(GUF_CNT_NAME, _new_with_capacity)(ptrdiff_t capacity, guf_allocator *allocator)
|
||||
GUF_DBUF_KWRDS GUF_DBUF_NAME GUF_CAT(GUF_DBUF_NAME, _new_with_capacity)(ptrdiff_t capacity, guf_allocator *allocator)
|
||||
{
|
||||
return GUF_CAT(GUF_CNT_NAME, _try_new_with_capacity)(capacity, allocator, NULL);
|
||||
return GUF_CAT(GUF_DBUF_NAME, _try_new_with_capacity)(capacity, allocator, NULL);
|
||||
}
|
||||
|
||||
#ifdef GUF_CNT_WITH_ELEM_CTX
|
||||
GUF_FN_KEYWORDS void GUF_CAT(GUF_CNT_NAME, _set_elem_ctx)(GUF_CNT_NAME *dbuf, void *elem_ctx)
|
||||
GUF_DBUF_KWRDS void GUF_CAT(GUF_DBUF_NAME, _set_elem_ctx)(GUF_DBUF_NAME *dbuf, void *elem_ctx)
|
||||
{
|
||||
GUF_ASSERT_RELEASE(GUF_CAT(GUF_CNT_NAME, _valid)(dbuf));
|
||||
GUF_ASSERT_RELEASE(GUF_CAT(GUF_DBUF_NAME, _valid)(dbuf));
|
||||
#ifdef GUF_CNT_WITH_ELEM_CTX
|
||||
dbuf->elem_ctx = elem_ctx;
|
||||
#else
|
||||
@ -299,7 +298,7 @@ GUF_FN_KEYWORDS void GUF_CAT(GUF_CNT_NAME, _set_elem_ctx)(GUF_CNT_NAME *dbuf, vo
|
||||
}
|
||||
#endif
|
||||
|
||||
GUF_FN_KEYWORDS void *GUF_CAT(GUF_CNT_NAME, _get_elem_ctx)(const GUF_CNT_NAME *dbuf)
|
||||
GUF_DBUF_KWRDS void *GUF_CAT(GUF_DBUF_NAME, _get_elem_ctx)(const GUF_DBUF_NAME *dbuf)
|
||||
{
|
||||
#ifdef GUF_CNT_WITH_ELEM_CTX
|
||||
return dbuf->elem_ctx;
|
||||
@ -309,10 +308,10 @@ GUF_FN_KEYWORDS void *GUF_CAT(GUF_CNT_NAME, _get_elem_ctx)(const GUF_CNT_NAME *d
|
||||
#endif
|
||||
}
|
||||
|
||||
GUF_FN_KEYWORDS void GUF_CAT(GUF_CNT_NAME, _free)(GUF_CNT_NAME *dbuf, void *ctx)
|
||||
GUF_DBUF_KWRDS void GUF_CAT(GUF_DBUF_NAME, _free)(GUF_DBUF_NAME *dbuf, void *ctx)
|
||||
{
|
||||
(void)ctx;
|
||||
GUF_ASSERT_RELEASE(GUF_CAT(GUF_CNT_NAME, _valid)(dbuf));
|
||||
GUF_ASSERT_RELEASE(GUF_CAT(GUF_DBUF_NAME, _valid)(dbuf));
|
||||
if (dbuf->capacity == 0) {
|
||||
GUF_ASSERT_RELEASE(!dbuf->data);
|
||||
GUF_ASSERT_RELEASE(dbuf->size == 0);
|
||||
@ -322,7 +321,7 @@ GUF_FN_KEYWORDS void GUF_CAT(GUF_CNT_NAME, _free)(GUF_CNT_NAME *dbuf, void *ctx)
|
||||
|
||||
#ifdef GUF_T_FREE
|
||||
for (ptrdiff_t idx = 0; idx < dbuf->size; ++idx) {
|
||||
GUF_T_FREE(dbuf->data + idx, GUF_CAT(GUF_CNT_NAME, _get_elem_ctx)(dbuf));
|
||||
GUF_T_FREE(dbuf->data + idx, GUF_CAT(GUF_DBUF_NAME, _get_elem_ctx)(dbuf));
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -335,10 +334,10 @@ GUF_FN_KEYWORDS void GUF_CAT(GUF_CNT_NAME, _free)(GUF_CNT_NAME *dbuf, void *ctx)
|
||||
#endif
|
||||
}
|
||||
|
||||
GUF_FN_KEYWORDS GUF_CNT_NAME *GUF_CAT(GUF_CNT_NAME, _copy)(GUF_CNT_NAME *dst, const GUF_CNT_NAME *src, void *ctx)
|
||||
GUF_DBUF_KWRDS GUF_DBUF_NAME *GUF_CAT(GUF_DBUF_NAME, _copy)(GUF_DBUF_NAME *dst, const GUF_DBUF_NAME *src, void *ctx)
|
||||
{
|
||||
(void)ctx;
|
||||
if (!dst || !src || GUF_CAT(GUF_CNT_NAME, _valid)(src)) {
|
||||
if (!dst || !src || GUF_CAT(GUF_DBUF_NAME, _valid)(src)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -376,7 +375,7 @@ GUF_FN_KEYWORDS GUF_CNT_NAME *GUF_CAT(GUF_CNT_NAME, _copy)(GUF_CNT_NAME *dst, co
|
||||
|
||||
for (ptrdiff_t i = 0; i < src->size; ++i) {
|
||||
#ifdef GUF_T_COPY
|
||||
GUF_T *cpy_success = GUF_T_COPY(dst->data + i, src->data + i, GUF_CAT(GUF_CNT_NAME, _get_elem_ctx)(src));
|
||||
GUF_T *cpy_success = GUF_T_COPY(dst->data + i, src->data + i, GUF_CAT(GUF_DBUF_NAME, _get_elem_ctx)(src));
|
||||
if (!cpy_success) {
|
||||
dst->size = i;
|
||||
return NULL;
|
||||
@ -389,7 +388,7 @@ GUF_FN_KEYWORDS GUF_CNT_NAME *GUF_CAT(GUF_CNT_NAME, _copy)(GUF_CNT_NAME *dst, co
|
||||
}
|
||||
}
|
||||
|
||||
GUF_FN_KEYWORDS GUF_CNT_NAME *GUF_CAT(GUF_CNT_NAME, _move)(GUF_CNT_NAME *dst, GUF_CNT_NAME *src, void *ctx)
|
||||
GUF_DBUF_KWRDS GUF_DBUF_NAME *GUF_CAT(GUF_DBUF_NAME, _move)(GUF_DBUF_NAME *dst, GUF_DBUF_NAME *src, void *ctx)
|
||||
{
|
||||
(void)ctx;
|
||||
if (!dst || !src) {
|
||||
@ -409,7 +408,7 @@ GUF_FN_KEYWORDS GUF_CNT_NAME *GUF_CAT(GUF_CNT_NAME, _move)(GUF_CNT_NAME *dst, GU
|
||||
return dst;
|
||||
}
|
||||
|
||||
GUF_FN_KEYWORDS ptrdiff_t GUF_CAT(GUF_CNT_NAME, _try_get_next_capacity)(ptrdiff_t old_cap, guf_err *err)
|
||||
GUF_DBUF_KWRDS ptrdiff_t GUF_CAT(GUF_DBUF_NAME, _try_get_next_capacity)(ptrdiff_t old_cap, guf_err *err)
|
||||
{
|
||||
GUF_ASSERT_RELEASE(old_cap >= 0);
|
||||
size_t new_cap = 0;
|
||||
@ -436,18 +435,18 @@ GUF_FN_KEYWORDS ptrdiff_t GUF_CAT(GUF_CNT_NAME, _try_get_next_capacity)(ptrdiff_
|
||||
}
|
||||
}
|
||||
|
||||
GUF_FN_KEYWORDS void GUF_CAT(GUF_CNT_NAME, _try_grow_if_full)(GUF_CNT_NAME *dbuf, guf_err *err)
|
||||
GUF_DBUF_KWRDS void GUF_CAT(GUF_DBUF_NAME, _try_grow_if_full)(GUF_DBUF_NAME *dbuf, guf_err *err)
|
||||
{
|
||||
GUF_ASSERT_RELEASE(GUF_CAT(GUF_CNT_NAME, _valid)(dbuf));
|
||||
GUF_ASSERT_RELEASE(GUF_CAT(GUF_DBUF_NAME, _valid)(dbuf));
|
||||
GUF_ASSERT_RELEASE(dbuf->capacity >= 0 && dbuf->size >= 0);
|
||||
|
||||
if (dbuf->size == dbuf->capacity) {
|
||||
ptrdiff_t next_cap = GUF_CAT(GUF_CNT_NAME, _try_get_next_capacity)(dbuf->capacity, err);
|
||||
ptrdiff_t next_cap = GUF_CAT(GUF_DBUF_NAME, _try_get_next_capacity)(dbuf->capacity, err);
|
||||
if (err && *err != GUF_ERR_NONE) {
|
||||
return;
|
||||
}
|
||||
GUF_ASSERT(next_cap > 0);
|
||||
GUF_CAT(GUF_CNT_NAME, _try_reserve)(dbuf, next_cap, err);
|
||||
GUF_CAT(GUF_DBUF_NAME, _try_reserve)(dbuf, next_cap, err);
|
||||
if (err && *err != GUF_ERR_NONE) {
|
||||
return;
|
||||
}
|
||||
@ -457,7 +456,7 @@ GUF_FN_KEYWORDS void GUF_CAT(GUF_CNT_NAME, _try_grow_if_full)(GUF_CNT_NAME *dbuf
|
||||
guf_err_set_if_not_null(err, GUF_ERR_NONE);
|
||||
}
|
||||
|
||||
static inline bool GUF_CAT(GUF_CNT_NAME, _copy_opt_available)(guf_cpy_opt cpy_opt)
|
||||
static inline bool GUF_CAT(GUF_DBUF_NAME, _copy_opt_available)(guf_cpy_opt cpy_opt)
|
||||
{
|
||||
if (cpy_opt == GUF_CPY_DEEP) {
|
||||
#ifdef GUF_T_COPY
|
||||
@ -478,16 +477,16 @@ static inline bool GUF_CAT(GUF_CNT_NAME, _copy_opt_available)(guf_cpy_opt cpy_op
|
||||
}
|
||||
}
|
||||
|
||||
GUF_FN_KEYWORDS GUF_T *GUF_CAT(GUF_CNT_NAME, _try_insert)(GUF_CNT_NAME *dbuf, GUF_T *elem, ptrdiff_t idx, guf_cpy_opt cpy_opt, guf_err *err)
|
||||
GUF_DBUF_KWRDS GUF_T *GUF_CAT(GUF_DBUF_NAME, _try_insert)(GUF_DBUF_NAME *dbuf, GUF_T *elem, ptrdiff_t idx, guf_cpy_opt cpy_opt, guf_err *err)
|
||||
{
|
||||
GUF_ASSERT(GUF_CAT(GUF_CNT_NAME,_valid)(dbuf));
|
||||
GUF_ASSERT(GUF_CAT(GUF_DBUF_NAME,_valid)(dbuf));
|
||||
|
||||
if (idx < 0 || idx > dbuf->size) {
|
||||
guf_err_set_or_panic(err, GUF_ERR_IDX_RANGE, GUF_ERR_MSG("in function dbuf_try_insert"));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
GUF_CAT(GUF_CNT_NAME, _try_grow_if_full)(dbuf, err);
|
||||
GUF_CAT(GUF_DBUF_NAME, _try_grow_if_full)(dbuf, err);
|
||||
if (err && *err != GUF_ERR_NONE) {
|
||||
return NULL;
|
||||
}
|
||||
@ -499,18 +498,18 @@ GUF_FN_KEYWORDS GUF_T *GUF_CAT(GUF_CNT_NAME, _try_insert)(GUF_CNT_NAME *dbuf, GU
|
||||
|
||||
GUF_T *dst = dbuf->data + idx;
|
||||
|
||||
if (!GUF_CAT(GUF_CNT_NAME, _copy_opt_available)(cpy_opt)) {
|
||||
guf_err_set_or_panic(err, GUF_ERR_INVALID_ARG, GUF_ERR_MSG("in function " GUF_STRINGIFY(GUF_CAT(GUF_CNT_NAME, _copy_opt_available)) ": cpy_opt unavailable"));
|
||||
if (!GUF_CAT(GUF_DBUF_NAME, _copy_opt_available)(cpy_opt)) {
|
||||
guf_err_set_or_panic(err, GUF_ERR_INVALID_ARG, GUF_ERR_MSG("in function " GUF_STRINGIFY(GUF_CAT(GUF_DBUF_NAME, _copy_opt_available)) ": cpy_opt unavailable"));
|
||||
return NULL;
|
||||
} else if (cpy_opt == GUF_CPY_DEEP) {
|
||||
#ifdef GUF_T_COPY
|
||||
dst = GUF_T_COPY(dst, elem, GUF_CAT(GUF_CNT_NAME, _get_elem_ctx)(dbuf));
|
||||
dst = GUF_T_COPY(dst, elem, GUF_CAT(GUF_DBUF_NAME, _get_elem_ctx)(dbuf));
|
||||
#else
|
||||
GUF_ASSERT_RELEASE(false);
|
||||
#endif
|
||||
} else if (cpy_opt == GUF_CPY_MOVE) {
|
||||
#ifdef GUF_T_MOVE
|
||||
dst = GUF_T_MOVE(dst, elem, GUF_CAT(GUF_CNT_NAME, _get_elem_ctx)(dbuf));
|
||||
dst = GUF_T_MOVE(dst, elem, GUF_CAT(GUF_DBUF_NAME, _get_elem_ctx)(dbuf));
|
||||
#else
|
||||
GUF_ASSERT_RELEASE(false);
|
||||
#endif
|
||||
@ -533,71 +532,71 @@ GUF_FN_KEYWORDS GUF_T *GUF_CAT(GUF_CNT_NAME, _try_insert)(GUF_CNT_NAME *dbuf, GU
|
||||
}
|
||||
}
|
||||
|
||||
GUF_FN_KEYWORDS GUF_T *GUF_CAT(GUF_CNT_NAME, _insert)(GUF_CNT_NAME *dbuf, GUF_T *elem, ptrdiff_t idx, guf_cpy_opt cpy_opt)
|
||||
GUF_DBUF_KWRDS GUF_T *GUF_CAT(GUF_DBUF_NAME, _insert)(GUF_DBUF_NAME *dbuf, GUF_T *elem, ptrdiff_t idx, guf_cpy_opt cpy_opt)
|
||||
{
|
||||
return GUF_CAT(GUF_CNT_NAME, _try_insert)(dbuf, elem, idx, cpy_opt, NULL);
|
||||
return GUF_CAT(GUF_DBUF_NAME, _try_insert)(dbuf, elem, idx, cpy_opt, NULL);
|
||||
}
|
||||
|
||||
GUF_FN_KEYWORDS GUF_T *GUF_CAT(GUF_CNT_NAME, _try_insert_val)(GUF_CNT_NAME *dbuf, GUF_T elem, ptrdiff_t idx, guf_err *err)
|
||||
GUF_DBUF_KWRDS GUF_T *GUF_CAT(GUF_DBUF_NAME, _try_insert_val)(GUF_DBUF_NAME *dbuf, GUF_T elem, ptrdiff_t idx, guf_err *err)
|
||||
{
|
||||
return GUF_CAT(GUF_CNT_NAME, _try_insert)(dbuf, &elem, idx, GUF_CPY_VALUE, err);
|
||||
return GUF_CAT(GUF_DBUF_NAME, _try_insert)(dbuf, &elem, idx, GUF_CPY_VALUE, err);
|
||||
}
|
||||
|
||||
GUF_FN_KEYWORDS GUF_T *GUF_CAT(GUF_CNT_NAME, _insert_val)(GUF_CNT_NAME *dbuf, GUF_T elem, ptrdiff_t idx)
|
||||
GUF_DBUF_KWRDS GUF_T *GUF_CAT(GUF_DBUF_NAME, _insert_val)(GUF_DBUF_NAME *dbuf, GUF_T elem, ptrdiff_t idx)
|
||||
{
|
||||
return GUF_CAT(GUF_CNT_NAME, _try_insert_val)(dbuf, elem, idx, NULL);
|
||||
return GUF_CAT(GUF_DBUF_NAME, _try_insert_val)(dbuf, elem, idx, NULL);
|
||||
}
|
||||
|
||||
|
||||
#ifdef GUF_T_COPY
|
||||
GUF_FN_KEYWORDS GUF_T *GUF_CAT(GUF_CNT_NAME, _try_insert_val_cpy)(GUF_CNT_NAME *dbuf, GUF_T elem, ptrdiff_t idx, guf_err *err)
|
||||
GUF_DBUF_KWRDS GUF_T *GUF_CAT(GUF_DBUF_NAME, _try_insert_val_cpy)(GUF_DBUF_NAME *dbuf, GUF_T elem, ptrdiff_t idx, guf_err *err)
|
||||
{
|
||||
return GUF_CAT(GUF_CNT_NAME, _try_insert)(dbuf, &elem, idx, GUF_CPY_DEEP, err);
|
||||
return GUF_CAT(GUF_DBUF_NAME, _try_insert)(dbuf, &elem, idx, GUF_CPY_DEEP, err);
|
||||
}
|
||||
|
||||
GUF_FN_KEYWORDS GUF_T *GUF_CAT(GUF_CNT_NAME, _insert_val_cpy)(GUF_CNT_NAME *dbuf, GUF_T elem, ptrdiff_t idx)
|
||||
GUF_DBUF_KWRDS GUF_T *GUF_CAT(GUF_DBUF_NAME, _insert_val_cpy)(GUF_DBUF_NAME *dbuf, GUF_T elem, ptrdiff_t idx)
|
||||
{
|
||||
return GUF_CAT(GUF_CNT_NAME, _try_insert_val_cpy)(dbuf, elem, idx, NULL);
|
||||
return GUF_CAT(GUF_DBUF_NAME, _try_insert_val_cpy)(dbuf, elem, idx, NULL);
|
||||
}
|
||||
#endif
|
||||
|
||||
GUF_FN_KEYWORDS GUF_T *GUF_CAT(GUF_CNT_NAME, _try_push)(GUF_CNT_NAME *dbuf, GUF_T *elem, guf_cpy_opt cpy_opt, guf_err *err)
|
||||
GUF_DBUF_KWRDS GUF_T *GUF_CAT(GUF_DBUF_NAME, _try_push)(GUF_DBUF_NAME *dbuf, GUF_T *elem, guf_cpy_opt cpy_opt, guf_err *err)
|
||||
{
|
||||
GUF_ASSERT(GUF_CAT(GUF_CNT_NAME, _valid)(dbuf));
|
||||
return GUF_CAT(GUF_CNT_NAME, _try_insert)(dbuf, elem, dbuf->size, cpy_opt, err);
|
||||
GUF_ASSERT(GUF_CAT(GUF_DBUF_NAME, _valid)(dbuf));
|
||||
return GUF_CAT(GUF_DBUF_NAME, _try_insert)(dbuf, elem, dbuf->size, cpy_opt, err);
|
||||
}
|
||||
|
||||
GUF_FN_KEYWORDS GUF_T *GUF_CAT(GUF_CNT_NAME, _push)(GUF_CNT_NAME *dbuf, GUF_T *elem, guf_cpy_opt cpy_opt)
|
||||
GUF_DBUF_KWRDS GUF_T *GUF_CAT(GUF_DBUF_NAME, _push)(GUF_DBUF_NAME *dbuf, GUF_T *elem, guf_cpy_opt cpy_opt)
|
||||
{
|
||||
return GUF_CAT(GUF_CNT_NAME, _try_push)(dbuf, elem, cpy_opt, NULL);
|
||||
return GUF_CAT(GUF_DBUF_NAME, _try_push)(dbuf, elem, cpy_opt, NULL);
|
||||
}
|
||||
|
||||
GUF_FN_KEYWORDS GUF_T *GUF_CAT(GUF_CNT_NAME, _try_push_val)(GUF_CNT_NAME *dbuf, GUF_T elem, guf_err *err)
|
||||
GUF_DBUF_KWRDS GUF_T *GUF_CAT(GUF_DBUF_NAME, _try_push_val)(GUF_DBUF_NAME *dbuf, GUF_T elem, guf_err *err)
|
||||
{
|
||||
return GUF_CAT(GUF_CNT_NAME, _try_push)(dbuf, &elem, GUF_CPY_VALUE, err);
|
||||
return GUF_CAT(GUF_DBUF_NAME, _try_push)(dbuf, &elem, GUF_CPY_VALUE, err);
|
||||
}
|
||||
|
||||
GUF_FN_KEYWORDS GUF_T *GUF_CAT(GUF_CNT_NAME, _push_val)(GUF_CNT_NAME *dbuf, GUF_T elem)
|
||||
GUF_DBUF_KWRDS GUF_T *GUF_CAT(GUF_DBUF_NAME, _push_val)(GUF_DBUF_NAME *dbuf, GUF_T elem)
|
||||
{
|
||||
return GUF_CAT(GUF_CNT_NAME, _try_push_val)(dbuf, elem, NULL);
|
||||
return GUF_CAT(GUF_DBUF_NAME, _try_push_val)(dbuf, elem, NULL);
|
||||
}
|
||||
|
||||
#ifdef GUF_T_COPY
|
||||
GUF_FN_KEYWORDS GUF_T *GUF_CAT(GUF_CNT_NAME, _try_push_val_cpy)(GUF_CNT_NAME *dbuf, GUF_T elem, guf_err *err)
|
||||
GUF_DBUF_KWRDS GUF_T *GUF_CAT(GUF_DBUF_NAME, _try_push_val_cpy)(GUF_DBUF_NAME *dbuf, GUF_T elem, guf_err *err)
|
||||
{
|
||||
return GUF_CAT(GUF_CNT_NAME, _try_push)(dbuf, &elem, GUF_CPY_DEEP, err);
|
||||
return GUF_CAT(GUF_DBUF_NAME, _try_push)(dbuf, &elem, GUF_CPY_DEEP, err);
|
||||
}
|
||||
|
||||
GUF_FN_KEYWORDS GUF_T *GUF_CAT(GUF_CNT_NAME, _push_val_cpy)(GUF_CNT_NAME *dbuf, GUF_T elem)
|
||||
GUF_DBUF_KWRDS GUF_T *GUF_CAT(GUF_DBUF_NAME, _push_val_cpy)(GUF_DBUF_NAME *dbuf, GUF_T elem)
|
||||
{
|
||||
return GUF_CAT(GUF_CNT_NAME, _try_push_val_cpy)(dbuf, elem, NULL);
|
||||
return GUF_CAT(GUF_DBUF_NAME, _try_push_val_cpy)(dbuf, elem, NULL);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
GUF_FN_KEYWORDS bool GUF_CAT(GUF_CNT_NAME, _try_erase)(GUF_CNT_NAME *dbuf, ptrdiff_t idx, guf_err *err)
|
||||
GUF_DBUF_KWRDS bool GUF_CAT(GUF_DBUF_NAME, _try_erase)(GUF_DBUF_NAME *dbuf, ptrdiff_t idx, guf_err *err)
|
||||
{
|
||||
GUF_ASSERT_RELEASE(GUF_CAT(GUF_CNT_NAME, _valid)(dbuf));
|
||||
GUF_ASSERT_RELEASE(GUF_CAT(GUF_DBUF_NAME, _valid)(dbuf));
|
||||
|
||||
if (dbuf->size == 0) {
|
||||
guf_err_set_or_panic(err, GUF_ERR_IDX_RANGE, GUF_ERR_MSG("in function dbuf_try_erase: cannot erase from empty buffer"));
|
||||
@ -609,7 +608,7 @@ GUF_FN_KEYWORDS bool GUF_CAT(GUF_CNT_NAME, _try_erase)(GUF_CNT_NAME *dbuf, ptrdi
|
||||
}
|
||||
|
||||
#ifdef GUF_T_FREE
|
||||
GUF_T_FREE(dbuf->data + idx, GUF_CAT(GUF_CNT_NAME, _get_elem_ctx)(dbuf));
|
||||
GUF_T_FREE(dbuf->data + idx, GUF_CAT(GUF_DBUF_NAME, _get_elem_ctx)(dbuf));
|
||||
#endif
|
||||
|
||||
for (ptrdiff_t free_idx = idx; free_idx < dbuf->size - 1; ++free_idx) { // Make space by moving elements to the left if necessary.
|
||||
@ -621,14 +620,14 @@ GUF_FN_KEYWORDS bool GUF_CAT(GUF_CNT_NAME, _try_erase)(GUF_CNT_NAME *dbuf, ptrdi
|
||||
return true;
|
||||
}
|
||||
|
||||
GUF_FN_KEYWORDS void GUF_CAT(GUF_CNT_NAME, _erase)(GUF_CNT_NAME *dbuf, ptrdiff_t idx)
|
||||
GUF_DBUF_KWRDS void GUF_CAT(GUF_DBUF_NAME, _erase)(GUF_DBUF_NAME *dbuf, ptrdiff_t idx)
|
||||
{
|
||||
GUF_CAT(GUF_CNT_NAME, _try_erase)(dbuf, idx, NULL);
|
||||
GUF_CAT(GUF_DBUF_NAME, _try_erase)(dbuf, idx, NULL);
|
||||
}
|
||||
|
||||
GUF_FN_KEYWORDS bool GUF_CAT(GUF_CNT_NAME, _try_pop)(GUF_CNT_NAME *dbuf, guf_err *err)
|
||||
GUF_DBUF_KWRDS bool GUF_CAT(GUF_DBUF_NAME, _try_pop)(GUF_DBUF_NAME *dbuf, guf_err *err)
|
||||
{
|
||||
GUF_ASSERT_RELEASE(GUF_CAT(GUF_CNT_NAME, _valid)(dbuf));
|
||||
GUF_ASSERT_RELEASE(GUF_CAT(GUF_DBUF_NAME, _valid)(dbuf));
|
||||
|
||||
if (dbuf->size == 0) {
|
||||
guf_err_set_or_panic(err, GUF_ERR_IDX_RANGE, GUF_ERR_MSG("in function dbuf_try_pop: Cannot pop from empty dbuf"));
|
||||
@ -637,7 +636,7 @@ GUF_FN_KEYWORDS bool GUF_CAT(GUF_CNT_NAME, _try_pop)(GUF_CNT_NAME *dbuf, guf_err
|
||||
|
||||
#ifdef GUF_T_FREE
|
||||
GUF_T *popped = dbuf->data + --dbuf->size;
|
||||
GUF_T_FREE(popped, GUF_CAT(GUF_CNT_NAME, _get_elem_ctx)(dbuf));
|
||||
GUF_T_FREE(popped, GUF_CAT(GUF_DBUF_NAME, _get_elem_ctx)(dbuf));
|
||||
#else
|
||||
--dbuf->size;
|
||||
#endif
|
||||
@ -646,14 +645,14 @@ GUF_FN_KEYWORDS bool GUF_CAT(GUF_CNT_NAME, _try_pop)(GUF_CNT_NAME *dbuf, guf_err
|
||||
return true;
|
||||
}
|
||||
|
||||
GUF_FN_KEYWORDS void GUF_CAT(GUF_CNT_NAME, _pop)(GUF_CNT_NAME *dbuf)
|
||||
GUF_DBUF_KWRDS void GUF_CAT(GUF_DBUF_NAME, _pop)(GUF_DBUF_NAME *dbuf)
|
||||
{
|
||||
GUF_CAT(GUF_CNT_NAME, _try_pop)(dbuf, NULL);
|
||||
GUF_CAT(GUF_DBUF_NAME, _try_pop)(dbuf, NULL);
|
||||
}
|
||||
|
||||
GUF_FN_KEYWORDS GUF_T GUF_CAT(GUF_CNT_NAME, _try_pop_move)(GUF_CNT_NAME *dbuf, guf_err *err)
|
||||
GUF_DBUF_KWRDS GUF_T GUF_CAT(GUF_DBUF_NAME, _try_pop_move)(GUF_DBUF_NAME *dbuf, guf_err *err)
|
||||
{
|
||||
GUF_ASSERT_RELEASE(GUF_CAT(GUF_CNT_NAME, _valid)(dbuf));
|
||||
GUF_ASSERT_RELEASE(GUF_CAT(GUF_DBUF_NAME, _valid)(dbuf));
|
||||
|
||||
if (dbuf->size == 0) {
|
||||
guf_err_set_or_panic(err, GUF_ERR_IDX_RANGE, GUF_ERR_MSG("in function dbuf_try_pop_move: Cannot pop from empty dbuf"));
|
||||
@ -666,7 +665,7 @@ GUF_FN_KEYWORDS GUF_T GUF_CAT(GUF_CNT_NAME, _try_pop_move)(GUF_CNT_NAME *dbuf, g
|
||||
GUF_T popped_val;
|
||||
GUF_T *dst = &popped_val;
|
||||
#if defined(GUF_T_MOVE)
|
||||
dst = GUF_T_MOVE(dst, popped, GUF_CAT(GUF_CNT_NAME, _get_elem_ctx)(dbuf));
|
||||
dst = GUF_T_MOVE(dst, popped, GUF_CAT(GUF_DBUF_NAME, _get_elem_ctx)(dbuf));
|
||||
#else
|
||||
*dst = *popped;
|
||||
memset(popped, 0, sizeof(GUF_T));
|
||||
@ -683,15 +682,15 @@ GUF_FN_KEYWORDS GUF_T GUF_CAT(GUF_CNT_NAME, _try_pop_move)(GUF_CNT_NAME *dbuf, g
|
||||
}
|
||||
}
|
||||
|
||||
GUF_FN_KEYWORDS GUF_T GUF_CAT(GUF_CNT_NAME, _pop_move)(GUF_CNT_NAME *dbuf)
|
||||
GUF_DBUF_KWRDS GUF_T GUF_CAT(GUF_DBUF_NAME, _pop_move)(GUF_DBUF_NAME *dbuf)
|
||||
{
|
||||
return GUF_CAT(GUF_CNT_NAME, _try_pop_move)(dbuf, NULL);
|
||||
return GUF_CAT(GUF_DBUF_NAME, _try_pop_move)(dbuf, NULL);
|
||||
}
|
||||
|
||||
|
||||
GUF_FN_KEYWORDS GUF_T *GUF_CAT(GUF_CNT_NAME, _try_at)(GUF_CNT_NAME *dbuf, ptrdiff_t idx, guf_err *err)
|
||||
GUF_DBUF_KWRDS GUF_T *GUF_CAT(GUF_DBUF_NAME, _try_at)(GUF_DBUF_NAME *dbuf, ptrdiff_t idx, guf_err *err)
|
||||
{
|
||||
GUF_ASSERT_RELEASE(GUF_CAT(GUF_CNT_NAME, _valid)(dbuf));
|
||||
GUF_ASSERT_RELEASE(GUF_CAT(GUF_DBUF_NAME, _valid)(dbuf));
|
||||
|
||||
if (dbuf->size == 0) {
|
||||
guf_err_set_or_panic(err, GUF_ERR_IDX_RANGE, GUF_ERR_MSG("in function dbuf_try_at: dbuf is empty"));
|
||||
@ -706,15 +705,15 @@ GUF_FN_KEYWORDS GUF_T *GUF_CAT(GUF_CNT_NAME, _try_at)(GUF_CNT_NAME *dbuf, ptrdif
|
||||
return dbuf->data + idx;
|
||||
}
|
||||
|
||||
GUF_FN_KEYWORDS GUF_T *GUF_CAT(GUF_CNT_NAME, _at)(GUF_CNT_NAME *dbuf, ptrdiff_t idx)
|
||||
GUF_DBUF_KWRDS GUF_T *GUF_CAT(GUF_DBUF_NAME, _at)(GUF_DBUF_NAME *dbuf, ptrdiff_t idx)
|
||||
{
|
||||
return GUF_CAT(GUF_CNT_NAME, _try_at)(dbuf, idx, NULL);
|
||||
return GUF_CAT(GUF_DBUF_NAME, _try_at)(dbuf, idx, NULL);
|
||||
}
|
||||
|
||||
|
||||
GUF_FN_KEYWORDS GUF_T *GUF_CAT(GUF_CNT_NAME, _try_front)(GUF_CNT_NAME *dbuf, guf_err *err)
|
||||
GUF_DBUF_KWRDS GUF_T *GUF_CAT(GUF_DBUF_NAME, _try_front)(GUF_DBUF_NAME *dbuf, guf_err *err)
|
||||
{
|
||||
GUF_ASSERT_RELEASE(GUF_CAT(GUF_CNT_NAME, _valid)(dbuf));
|
||||
GUF_ASSERT_RELEASE(GUF_CAT(GUF_DBUF_NAME, _valid)(dbuf));
|
||||
|
||||
if (dbuf->size == 0) {
|
||||
guf_err_set_or_panic(err, GUF_ERR_IDX_RANGE, GUF_ERR_MSG("in function dbuf_front: dbuf is empty"));
|
||||
@ -723,15 +722,15 @@ GUF_FN_KEYWORDS GUF_T *GUF_CAT(GUF_CNT_NAME, _try_front)(GUF_CNT_NAME *dbuf, guf
|
||||
return dbuf->data + 0;
|
||||
}
|
||||
|
||||
GUF_FN_KEYWORDS GUF_T *GUF_CAT(GUF_CNT_NAME, _front)(GUF_CNT_NAME *dbuf)
|
||||
GUF_DBUF_KWRDS GUF_T *GUF_CAT(GUF_DBUF_NAME, _front)(GUF_DBUF_NAME *dbuf)
|
||||
{
|
||||
return GUF_CAT(GUF_CNT_NAME, _try_front)(dbuf, NULL);
|
||||
return GUF_CAT(GUF_DBUF_NAME, _try_front)(dbuf, NULL);
|
||||
}
|
||||
|
||||
|
||||
GUF_FN_KEYWORDS GUF_T *GUF_CAT(GUF_CNT_NAME, _try_back)(GUF_CNT_NAME *dbuf, guf_err *err)
|
||||
GUF_DBUF_KWRDS GUF_T *GUF_CAT(GUF_DBUF_NAME, _try_back)(GUF_DBUF_NAME *dbuf, guf_err *err)
|
||||
{
|
||||
GUF_ASSERT_RELEASE(GUF_CAT(GUF_CNT_NAME, _valid)(dbuf));
|
||||
GUF_ASSERT_RELEASE(GUF_CAT(GUF_DBUF_NAME, _valid)(dbuf));
|
||||
|
||||
if (dbuf->size == 0) {
|
||||
guf_err_set_or_panic(err, GUF_ERR_IDX_RANGE, GUF_ERR_MSG("in function dbuf_try_back: dbuf is empty"));
|
||||
@ -741,14 +740,14 @@ GUF_FN_KEYWORDS GUF_T *GUF_CAT(GUF_CNT_NAME, _try_back)(GUF_CNT_NAME *dbuf, guf_
|
||||
return dbuf->data + (dbuf->size - 1);
|
||||
}
|
||||
|
||||
GUF_FN_KEYWORDS GUF_T *GUF_CAT(GUF_CNT_NAME, _back)(GUF_CNT_NAME *dbuf)
|
||||
GUF_DBUF_KWRDS GUF_T *GUF_CAT(GUF_DBUF_NAME, _back)(GUF_DBUF_NAME *dbuf)
|
||||
{
|
||||
return GUF_CAT(GUF_CNT_NAME, _try_back)(dbuf, NULL);
|
||||
return GUF_CAT(GUF_DBUF_NAME, _try_back)(dbuf, NULL);
|
||||
}
|
||||
|
||||
GUF_FN_KEYWORDS void GUF_CAT(GUF_CNT_NAME, _try_shrink_to_fit)(GUF_CNT_NAME *dbuf, guf_err *err)
|
||||
GUF_DBUF_KWRDS void GUF_CAT(GUF_DBUF_NAME, _try_shrink_to_fit)(GUF_DBUF_NAME *dbuf, guf_err *err)
|
||||
{
|
||||
GUF_ASSERT_RELEASE(GUF_CAT(GUF_CNT_NAME, _valid)(dbuf));
|
||||
GUF_ASSERT_RELEASE(GUF_CAT(GUF_DBUF_NAME, _valid)(dbuf));
|
||||
const ptrdiff_t new_capacity = dbuf->size;
|
||||
if (new_capacity == dbuf->capacity || (!dbuf->data && !dbuf->capacity)) {
|
||||
guf_err_set_if_not_null(err, GUF_ERR_NONE);
|
||||
@ -774,55 +773,55 @@ GUF_FN_KEYWORDS void GUF_CAT(GUF_CNT_NAME, _try_shrink_to_fit)(GUF_CNT_NAME *dbu
|
||||
|
||||
/* Iterator functions */
|
||||
|
||||
GUF_FN_KEYWORDS GUF_CAT(GUF_CNT_NAME, _iter) GUF_CAT(GUF_CNT_NAME, _begin)(const GUF_CNT_NAME* dbuf)
|
||||
GUF_DBUF_KWRDS GUF_CAT(GUF_DBUF_NAME, _iter) GUF_CAT(GUF_DBUF_NAME, _begin)(const GUF_DBUF_NAME* dbuf)
|
||||
{
|
||||
GUF_ASSERT_RELEASE(GUF_CAT(GUF_CNT_NAME, _valid)(dbuf));
|
||||
GUF_ASSERT_RELEASE(GUF_CAT(GUF_DBUF_NAME, _valid)(dbuf));
|
||||
|
||||
return (GUF_CAT(GUF_CNT_NAME, _iter)) {
|
||||
return (GUF_CAT(GUF_DBUF_NAME, _iter)) {
|
||||
.ptr = dbuf->data && dbuf->size ? dbuf->data : NULL,
|
||||
.base = NULL
|
||||
};
|
||||
}
|
||||
|
||||
GUF_FN_KEYWORDS GUF_CAT(GUF_CNT_NAME, _iter) GUF_CAT(GUF_CNT_NAME, _end)(const GUF_CNT_NAME* dbuf)
|
||||
GUF_DBUF_KWRDS GUF_CAT(GUF_DBUF_NAME, _iter) GUF_CAT(GUF_DBUF_NAME, _end)(const GUF_DBUF_NAME* dbuf)
|
||||
{
|
||||
GUF_ASSERT_RELEASE(GUF_CAT(GUF_CNT_NAME, _valid)(dbuf));
|
||||
return (GUF_CAT(GUF_CNT_NAME, _iter)) {
|
||||
GUF_ASSERT_RELEASE(GUF_CAT(GUF_DBUF_NAME, _valid)(dbuf));
|
||||
return (GUF_CAT(GUF_DBUF_NAME, _iter)) {
|
||||
.ptr = dbuf->data && dbuf->size ? dbuf->data + dbuf->size : NULL,
|
||||
.base = NULL
|
||||
};
|
||||
}
|
||||
|
||||
GUF_FN_KEYWORDS GUF_CAT(GUF_CNT_NAME, _iter) GUF_CAT(GUF_CNT_NAME, _rbegin)(const GUF_CNT_NAME* dbuf)
|
||||
GUF_DBUF_KWRDS GUF_CAT(GUF_DBUF_NAME, _iter) GUF_CAT(GUF_DBUF_NAME, _rbegin)(const GUF_DBUF_NAME* dbuf)
|
||||
{
|
||||
GUF_ASSERT_RELEASE(GUF_CAT(GUF_CNT_NAME, _valid)(dbuf));
|
||||
return (GUF_CAT(GUF_CNT_NAME, _iter)) {
|
||||
GUF_ASSERT_RELEASE(GUF_CAT(GUF_DBUF_NAME, _valid)(dbuf));
|
||||
return (GUF_CAT(GUF_DBUF_NAME, _iter)) {
|
||||
.base = dbuf->data && dbuf->size ? dbuf->data + dbuf->size : NULL,
|
||||
.ptr = dbuf->data && dbuf->size ? dbuf->data + (dbuf->size - 1) : NULL
|
||||
};
|
||||
}
|
||||
|
||||
GUF_FN_KEYWORDS GUF_CAT(GUF_CNT_NAME, _iter) GUF_CAT(GUF_CNT_NAME, _rend)(const GUF_CNT_NAME* dbuf)
|
||||
GUF_DBUF_KWRDS GUF_CAT(GUF_DBUF_NAME, _iter) GUF_CAT(GUF_DBUF_NAME, _rend)(const GUF_DBUF_NAME* dbuf)
|
||||
{
|
||||
GUF_ASSERT_RELEASE(GUF_CAT(GUF_CNT_NAME, _valid)(dbuf));
|
||||
return (GUF_CAT(GUF_CNT_NAME, _iter)) {
|
||||
GUF_ASSERT_RELEASE(GUF_CAT(GUF_DBUF_NAME, _valid)(dbuf));
|
||||
return (GUF_CAT(GUF_DBUF_NAME, _iter)) {
|
||||
.base = dbuf->data && dbuf->size ? dbuf->data : NULL,
|
||||
.ptr = NULL
|
||||
};
|
||||
}
|
||||
|
||||
GUF_FN_KEYWORDS bool GUF_CAT(GUF_CNT_NAME, _iter_is_end)(const GUF_CNT_NAME* dbuf, GUF_CAT(GUF_CNT_NAME, _iter) it)
|
||||
GUF_DBUF_KWRDS bool GUF_CAT(GUF_DBUF_NAME, _iter_is_end)(const GUF_DBUF_NAME* dbuf, GUF_CAT(GUF_DBUF_NAME, _iter) it)
|
||||
{
|
||||
const bool is_reverse_it = it.base != NULL;
|
||||
const GUF_CAT(GUF_CNT_NAME, _iter) dbuf_end_it = is_reverse_it ? GUF_CAT(GUF_CNT_NAME, _rend)(dbuf) : GUF_CAT(GUF_CNT_NAME, _end)(dbuf);
|
||||
const GUF_CAT(GUF_DBUF_NAME, _iter) dbuf_end_it = is_reverse_it ? GUF_CAT(GUF_DBUF_NAME, _rend)(dbuf) : GUF_CAT(GUF_DBUF_NAME, _end)(dbuf);
|
||||
return it.ptr == dbuf_end_it.ptr;
|
||||
}
|
||||
|
||||
GUF_FN_KEYWORDS GUF_CAT(GUF_CNT_NAME, _iter) GUF_CAT(GUF_CNT_NAME, _iter_at_idx)(const GUF_CNT_NAME* dbuf, ptrdiff_t idx)
|
||||
GUF_DBUF_KWRDS GUF_CAT(GUF_DBUF_NAME, _iter) GUF_CAT(GUF_DBUF_NAME, _iter_at_idx)(const GUF_DBUF_NAME* dbuf, ptrdiff_t idx)
|
||||
{
|
||||
GUF_ASSERT(GUF_CAT(GUF_CNT_NAME, _valid)(dbuf));
|
||||
GUF_ASSERT(GUF_CAT(GUF_DBUF_NAME, _valid)(dbuf));
|
||||
|
||||
GUF_CAT(GUF_CNT_NAME, _iter) it;
|
||||
GUF_CAT(GUF_DBUF_NAME, _iter) it;
|
||||
it.base = NULL;
|
||||
|
||||
if (!dbuf->data || !dbuf->size) {
|
||||
@ -841,9 +840,9 @@ GUF_FN_KEYWORDS GUF_CAT(GUF_CNT_NAME, _iter) GUF_CAT(GUF_CNT_NAME, _iter_at_idx
|
||||
return it;
|
||||
}
|
||||
|
||||
GUF_FN_KEYWORDS GUF_CAT(GUF_CNT_NAME, _iter) GUF_CAT(GUF_CNT_NAME, _reverse_iter_at_idx)(const GUF_CNT_NAME* dbuf, ptrdiff_t idx)
|
||||
GUF_DBUF_KWRDS GUF_CAT(GUF_DBUF_NAME, _iter) GUF_CAT(GUF_DBUF_NAME, _reverse_iter_at_idx)(const GUF_DBUF_NAME* dbuf, ptrdiff_t idx)
|
||||
{
|
||||
GUF_CAT(GUF_CNT_NAME, _iter) it = GUF_CAT(GUF_CNT_NAME, _iter_at_idx)(dbuf, idx);
|
||||
GUF_CAT(GUF_DBUF_NAME, _iter) it = GUF_CAT(GUF_DBUF_NAME, _iter_at_idx)(dbuf, idx);
|
||||
|
||||
if (!dbuf->data || !dbuf->size) {
|
||||
it.base = NULL;
|
||||
@ -864,16 +863,16 @@ GUF_FN_KEYWORDS GUF_CAT(GUF_CNT_NAME, _iter) GUF_CAT(GUF_CNT_NAME, _reverse_ite
|
||||
return it;
|
||||
}
|
||||
|
||||
GUF_FN_KEYWORDS ptrdiff_t GUF_CAT(GUF_CNT_NAME, _iter_to_idx)(const GUF_CNT_NAME* dbuf, GUF_CAT(GUF_CNT_NAME, _iter) it)
|
||||
GUF_DBUF_KWRDS ptrdiff_t GUF_CAT(GUF_DBUF_NAME, _iter_to_idx)(const GUF_DBUF_NAME* dbuf, GUF_CAT(GUF_DBUF_NAME, _iter) it)
|
||||
{
|
||||
GUF_ASSERT(GUF_CAT(GUF_CNT_NAME, _valid)(dbuf));
|
||||
GUF_ASSERT(GUF_CAT(GUF_DBUF_NAME, _valid)(dbuf));
|
||||
|
||||
if ((!it.ptr && !it.base) || !dbuf->data || !dbuf->size) {
|
||||
return GUF_CNT_NPOS;
|
||||
}
|
||||
|
||||
const bool is_reverse_it = it.base != NULL;
|
||||
const GUF_CAT(GUF_CNT_NAME, _iter) end_it = is_reverse_it ? GUF_CAT(GUF_CNT_NAME, _rend)(dbuf) : GUF_CAT(GUF_CNT_NAME, _end)(dbuf);
|
||||
const GUF_CAT(GUF_DBUF_NAME, _iter) end_it = is_reverse_it ? GUF_CAT(GUF_DBUF_NAME, _rend)(dbuf) : GUF_CAT(GUF_DBUF_NAME, _end)(dbuf);
|
||||
|
||||
if (it.ptr == end_it.ptr) {
|
||||
return is_reverse_it ? -1 : dbuf->size;
|
||||
@ -886,9 +885,9 @@ GUF_FN_KEYWORDS ptrdiff_t GUF_CAT(GUF_CNT_NAME, _iter_to_idx)(const GUF_CNT_NAME
|
||||
}
|
||||
}
|
||||
|
||||
GUF_FN_KEYWORDS GUF_CAT(GUF_CNT_NAME, _iter) GUF_CAT(GUF_CNT_NAME, _iter_next)(const GUF_CNT_NAME *dbuf, GUF_CAT(GUF_CNT_NAME, _iter) it, ptrdiff_t step)
|
||||
GUF_DBUF_KWRDS GUF_CAT(GUF_DBUF_NAME, _iter) GUF_CAT(GUF_DBUF_NAME, _iter_next)(const GUF_DBUF_NAME *dbuf, GUF_CAT(GUF_DBUF_NAME, _iter) it, ptrdiff_t step)
|
||||
{
|
||||
GUF_ASSERT(GUF_CAT(GUF_CNT_NAME, _valid)(dbuf));
|
||||
GUF_ASSERT(GUF_CAT(GUF_DBUF_NAME, _valid)(dbuf));
|
||||
|
||||
if (!dbuf->size || !dbuf->data || (!it.base && !it.ptr)) {
|
||||
it.ptr = NULL;
|
||||
@ -921,14 +920,14 @@ GUF_FN_KEYWORDS GUF_CAT(GUF_CNT_NAME, _iter) GUF_CAT(GUF_CNT_NAME, _iter_next)(c
|
||||
}
|
||||
|
||||
#if defined(GUF_T_IS_INTEGRAL_TYPE) || defined(GUF_T_EQ)
|
||||
GUF_FN_KEYWORDS GUF_CAT(GUF_CNT_NAME, _iter) GUF_CAT(GUF_CNT_NAME, _find)(GUF_CNT_NAME *dbuf, GUF_CAT(GUF_CNT_NAME, _iter) begin, GUF_CAT(GUF_CNT_NAME, _iter) end, const GUF_T *needle)
|
||||
GUF_DBUF_KWRDS GUF_CAT(GUF_DBUF_NAME, _iter) GUF_CAT(GUF_DBUF_NAME, _find)(GUF_DBUF_NAME *dbuf, GUF_CAT(GUF_DBUF_NAME, _iter) begin, GUF_CAT(GUF_DBUF_NAME, _iter) end, const GUF_T *needle)
|
||||
{
|
||||
GUF_ASSERT_RELEASE(GUF_CAT(GUF_CNT_NAME, _valid)(dbuf));
|
||||
GUF_ASSERT_RELEASE(GUF_CAT(GUF_DBUF_NAME, _valid)(dbuf));
|
||||
GUF_ASSERT_RELEASE(needle);
|
||||
|
||||
const bool is_reverse_it = begin.base != NULL;
|
||||
GUF_ASSERT_RELEASE(is_reverse_it == (end.base != NULL)); // begin and end must be the same iterator type.
|
||||
const GUF_CAT(GUF_CNT_NAME, _iter) dbuf_end_it = is_reverse_it ? GUF_CAT(GUF_CNT_NAME, _rend)(dbuf) : GUF_CAT(GUF_CNT_NAME, _end)(dbuf);
|
||||
const GUF_CAT(GUF_DBUF_NAME, _iter) dbuf_end_it = is_reverse_it ? GUF_CAT(GUF_DBUF_NAME, _rend)(dbuf) : GUF_CAT(GUF_DBUF_NAME, _end)(dbuf);
|
||||
|
||||
if (!dbuf->data || !dbuf->size || (!begin.ptr && !begin.base) || (!end.ptr && !end.base)) {
|
||||
return dbuf_end_it;
|
||||
@ -937,7 +936,7 @@ GUF_FN_KEYWORDS GUF_CAT(GUF_CNT_NAME, _iter) GUF_CAT(GUF_CNT_NAME, _find)(GUF_CN
|
||||
return dbuf_end_it;
|
||||
}
|
||||
|
||||
for (GUF_CAT(GUF_CNT_NAME, _iter) it = begin; it.ptr != end.ptr && it.ptr != NULL; it = GUF_CAT(GUF_CNT_NAME, _iter_next)(dbuf, it, 1)) {
|
||||
for (GUF_CAT(GUF_DBUF_NAME, _iter) it = begin; it.ptr != end.ptr && it.ptr != NULL; it = GUF_CAT(GUF_DBUF_NAME, _iter_next)(dbuf, it, 1)) {
|
||||
#ifdef GUF_T_EQ
|
||||
if (GUF_T_EQ(it.ptr, needle)) {
|
||||
return it;
|
||||
@ -951,32 +950,32 @@ GUF_FN_KEYWORDS GUF_CAT(GUF_CNT_NAME, _iter) GUF_CAT(GUF_CNT_NAME, _find)(GUF_CN
|
||||
return dbuf_end_it;
|
||||
}
|
||||
|
||||
GUF_FN_KEYWORDS GUF_CAT(GUF_CNT_NAME, _iter) GUF_CAT(GUF_CNT_NAME, _find_val)(GUF_CNT_NAME *dbuf, GUF_CAT(GUF_CNT_NAME, _iter) begin, GUF_CAT(GUF_CNT_NAME, _iter) end, GUF_T needle_val)
|
||||
GUF_DBUF_KWRDS GUF_CAT(GUF_DBUF_NAME, _iter) GUF_CAT(GUF_DBUF_NAME, _find_val)(GUF_DBUF_NAME *dbuf, GUF_CAT(GUF_DBUF_NAME, _iter) begin, GUF_CAT(GUF_DBUF_NAME, _iter) end, GUF_T needle_val)
|
||||
{
|
||||
return GUF_CAT(GUF_CNT_NAME, _find)(dbuf, begin, end, &needle_val);
|
||||
return GUF_CAT(GUF_DBUF_NAME, _find)(dbuf, begin, end, &needle_val);
|
||||
}
|
||||
|
||||
GUF_FN_KEYWORDS bool GUF_CAT(GUF_CNT_NAME, _contains)(GUF_CNT_NAME *dbuf, const GUF_T *needle)
|
||||
GUF_DBUF_KWRDS bool GUF_CAT(GUF_DBUF_NAME, _contains)(GUF_DBUF_NAME *dbuf, const GUF_T *needle)
|
||||
{
|
||||
GUF_CAT(GUF_CNT_NAME, _iter) beg = GUF_CAT(GUF_CNT_NAME, _begin)(dbuf);
|
||||
GUF_CAT(GUF_CNT_NAME, _iter) end = GUF_CAT(GUF_CNT_NAME, _end)(dbuf);
|
||||
return GUF_CAT(GUF_CNT_NAME, _find)(dbuf, beg, end, needle).ptr != end.ptr;
|
||||
GUF_CAT(GUF_DBUF_NAME, _iter) beg = GUF_CAT(GUF_DBUF_NAME, _begin)(dbuf);
|
||||
GUF_CAT(GUF_DBUF_NAME, _iter) end = GUF_CAT(GUF_DBUF_NAME, _end)(dbuf);
|
||||
return GUF_CAT(GUF_DBUF_NAME, _find)(dbuf, beg, end, needle).ptr != end.ptr;
|
||||
}
|
||||
|
||||
GUF_FN_KEYWORDS bool GUF_CAT(GUF_CNT_NAME, _contains_val)(GUF_CNT_NAME *dbuf, GUF_T needle)
|
||||
GUF_DBUF_KWRDS bool GUF_CAT(GUF_DBUF_NAME, _contains_val)(GUF_DBUF_NAME *dbuf, GUF_T needle)
|
||||
{
|
||||
return GUF_CAT(GUF_CNT_NAME, _contains)(dbuf, &needle);
|
||||
return GUF_CAT(GUF_DBUF_NAME, _contains)(dbuf, &needle);
|
||||
}
|
||||
#endif
|
||||
|
||||
GUF_FN_KEYWORDS GUF_CAT(GUF_CNT_NAME, _iter) GUF_CAT(GUF_CNT_NAME, _find_if)(GUF_CNT_NAME *dbuf, GUF_CAT(GUF_CNT_NAME, _iter) begin, GUF_CAT(GUF_CNT_NAME, _iter) end, bool (*predicate)(const GUF_T *))
|
||||
GUF_DBUF_KWRDS GUF_CAT(GUF_DBUF_NAME, _iter) GUF_CAT(GUF_DBUF_NAME, _find_if)(GUF_DBUF_NAME *dbuf, GUF_CAT(GUF_DBUF_NAME, _iter) begin, GUF_CAT(GUF_DBUF_NAME, _iter) end, bool (*predicate)(const GUF_T *))
|
||||
{
|
||||
GUF_ASSERT_RELEASE(GUF_CAT(GUF_CNT_NAME, _valid)(dbuf));
|
||||
GUF_ASSERT_RELEASE(GUF_CAT(GUF_DBUF_NAME, _valid)(dbuf));
|
||||
GUF_ASSERT_RELEASE(predicate);
|
||||
|
||||
const bool is_reverse_it = begin.base != NULL;
|
||||
GUF_ASSERT_RELEASE(is_reverse_it == (end.base != NULL)); // begin and end must be the same iterator type.
|
||||
const GUF_CAT(GUF_CNT_NAME, _iter) dbuf_end_it = is_reverse_it ? GUF_CAT(GUF_CNT_NAME, _rend)(dbuf) : GUF_CAT(GUF_CNT_NAME, _end)(dbuf);
|
||||
const GUF_CAT(GUF_DBUF_NAME, _iter) dbuf_end_it = is_reverse_it ? GUF_CAT(GUF_DBUF_NAME, _rend)(dbuf) : GUF_CAT(GUF_DBUF_NAME, _end)(dbuf);
|
||||
|
||||
if (!dbuf->data || !dbuf->size || (!begin.ptr && !begin.base) || (!end.ptr && !end.base)) {
|
||||
return dbuf_end_it;
|
||||
@ -985,22 +984,22 @@ GUF_FN_KEYWORDS GUF_CAT(GUF_CNT_NAME, _iter) GUF_CAT(GUF_CNT_NAME, _find_if)(GUF
|
||||
return dbuf_end_it;
|
||||
}
|
||||
|
||||
for (GUF_CAT(GUF_CNT_NAME, _iter) it = begin; it.ptr != end.ptr && it.ptr != NULL; GUF_CAT(GUF_CNT_NAME, _iter_next)(dbuf, it, 1)) {
|
||||
for (GUF_CAT(GUF_DBUF_NAME, _iter) it = begin; it.ptr != end.ptr && it.ptr != NULL; GUF_CAT(GUF_DBUF_NAME, _iter_next)(dbuf, it, 1)) {
|
||||
if (predicate(it.ptr)) {
|
||||
return it;
|
||||
}
|
||||
}
|
||||
return GUF_CAT(GUF_CNT_NAME, _end)(dbuf);
|
||||
return GUF_CAT(GUF_DBUF_NAME, _end)(dbuf);
|
||||
}
|
||||
|
||||
#endif /* end #ifdef GUF_IMPL */
|
||||
|
||||
#endif /* end GUF_ONLY_TYPES */
|
||||
#endif /* end GUF_DBUF_ONLY_TYPES */
|
||||
|
||||
#undef GUF_DBUF_INITIAL_CAP
|
||||
#undef GUF_DBUF_USE_GROWTH_FAC_ONE_POINT_FIVE
|
||||
|
||||
#undef GUF_CNT_NAME
|
||||
#undef GUF_DBUF_NAME
|
||||
#undef GUF_CNT_WITH_ELEM_CTX
|
||||
|
||||
#undef GUF_T
|
||||
@ -1010,7 +1009,9 @@ GUF_FN_KEYWORDS GUF_CAT(GUF_CNT_NAME, _iter) GUF_CAT(GUF_CNT_NAME, _find_if)(GUF
|
||||
#undef GUF_T_EQ
|
||||
#undef GUF_T_IS_INTEGRAL_TYPE
|
||||
|
||||
#undef GUF_FN_KEYWORDS
|
||||
#undef GUF_IMPL
|
||||
#undef GUF_IMPL_STATIC
|
||||
#undef GUF_STATIC
|
||||
#undef GUF_DBUF_KWRDS
|
||||
#undef GUF_DBUF_IMPL
|
||||
#undef GUF_DBUF_IMPL_STATIC
|
||||
|
||||
#undef GUF_DBUF_WITHOUT_TYPES
|
||||
#undef GUF_DBUF_ONLY_TYPES
|
||||
|
||||
161
src/guf_dict.h
161
src/guf_dict.h
@ -1,28 +1,14 @@
|
||||
#ifdef GUF_STATIC
|
||||
#define GUF_DICT_STATIC
|
||||
#undef GUF_STATIC
|
||||
#endif
|
||||
|
||||
#ifdef GUF_IMPL
|
||||
#define GUF_DICT_IMPL
|
||||
#undef GUF_IMPL
|
||||
#endif
|
||||
|
||||
#ifdef GUF_IMPL_STATIC
|
||||
#define GUF_DICT_IMPL_STATIC
|
||||
#undef GUF_IMPL_STATIC
|
||||
#endif
|
||||
|
||||
#if defined(GUF_DICT_STATIC) || defined(GUF_DICT_IMPL_STATIC)
|
||||
#define GUF_DICT_FN_KEYWORDS static
|
||||
#if defined(GUF_DICT_IMPL_STATIC)
|
||||
#define GUF_DICT_KWRDS static
|
||||
#else
|
||||
#define GUF_DICT_FN_KEYWORDS
|
||||
#define GUF_DICT_KWRDS
|
||||
#endif
|
||||
|
||||
#ifndef GUF_DICT_H
|
||||
#define GUF_DICT_H
|
||||
#include "guf_common.h"
|
||||
#include "guf_alloc.h"
|
||||
#include "guf_hash.h"
|
||||
|
||||
typedef struct guf_dict_kv_meta_32 {
|
||||
uint32_t kv_idx; // Index into the kv_elems dbuf.
|
||||
@ -33,6 +19,11 @@
|
||||
uint64_t kv_idx; // Index into the kv_elems dbuf.
|
||||
uint64_t key_hash;
|
||||
} guf_dict_kv_meta_64;
|
||||
|
||||
typedef struct guf_dict_kv_meta {
|
||||
guf_hash_size_t kv_idx; // Index into the kv_elems dbuf.
|
||||
guf_hash_size_t key_hash;
|
||||
} guf_dict_kv_meta;
|
||||
#endif
|
||||
|
||||
#ifndef GUF_DICT_KEY_T
|
||||
@ -51,18 +42,23 @@
|
||||
#define GUF_DICT_IS_SET
|
||||
#endif
|
||||
|
||||
#ifdef GUF_DICT_32_BIT
|
||||
#if defined(GUF_DICT_32_BIT)
|
||||
#define GUF_DICT_SIZE_T uint32_t
|
||||
#define GUF_DICT_KV_META_T guf_dict_kv_meta_32
|
||||
#define GUF_DICT_KV_IDX_NULL UINT32_MAX
|
||||
#else
|
||||
#elif defined(GUF_DICT_64_BIT)
|
||||
#define GUF_DICT_SIZE_T uint64_t
|
||||
#define GUF_DICT_KV_META_T guf_dict_kv_meta_64
|
||||
#define GUF_DICT_KV_IDX_NULL UINT64_MAX
|
||||
#else
|
||||
#define GUF_DICT_SIZE_T guf_hash_size_t
|
||||
#define GUF_DICT_KV_META_T guf_dict_kv_meta
|
||||
#define GUF_DICT_KV_IDX_NULL GUF_HASH_MAX
|
||||
#endif
|
||||
|
||||
#define GUF_DICT_KV_IDX_TOMBSTONE (GUF_DICT_KV_IDX_NULL - 1)
|
||||
#define GUF_DICT_MAX_SIZE (GUF_DICT_KV_IDX_TOMBSTONE - 1)
|
||||
// TODO
|
||||
#define GUF_DICT_MAX_SIZE GUF_MIN(GUF_DICT_KV_IDX_TOMBSTONE - 1, PTRDIFF_MAX)
|
||||
|
||||
// #ifndef GUF_DICT_KEY_LOOKUP_T
|
||||
// #define GUF_DICT_KEY_LOOKUP_T GUF_DICT_KEY_T
|
||||
@ -97,8 +93,8 @@ typedef struct GUF_DICT_KV_NAME {
|
||||
} GUF_DICT_KV_NAME;
|
||||
|
||||
#define GUF_T GUF_DICT_KV_NAME
|
||||
#define GUF_CNT_NAME GUF_DICT_KV_DBUF
|
||||
#define GUF_ONLY_TYPES
|
||||
#define GUF_DBUF_NAME GUF_DICT_KV_DBUF
|
||||
#define GUF_DBUF_ONLY_TYPES
|
||||
#include "guf_dbuf.h"
|
||||
|
||||
typedef struct GUF_DICT_NAME {
|
||||
@ -112,48 +108,48 @@ typedef GUF_CAT(GUF_DICT_KV_DBUF, _iter) GUF_CAT(GUF_DICT_NAME, _iter);
|
||||
|
||||
#endif
|
||||
|
||||
GUF_DICT_FN_KEYWORDS GUF_DICT_NAME *GUF_CAT(GUF_DICT_NAME, _try_init)(GUF_DICT_NAME *ht, guf_allocator *alloc, guf_err *err);
|
||||
GUF_DICT_FN_KEYWORDS GUF_DICT_NAME *GUF_CAT(GUF_DICT_NAME, _init)(GUF_DICT_NAME *ht, guf_allocator *alloc);
|
||||
GUF_DICT_KWRDS GUF_DICT_NAME *GUF_CAT(GUF_DICT_NAME, _try_init)(GUF_DICT_NAME *ht, guf_allocator *alloc, guf_err *err);
|
||||
GUF_DICT_KWRDS GUF_DICT_NAME *GUF_CAT(GUF_DICT_NAME, _init)(GUF_DICT_NAME *ht, guf_allocator *alloc);
|
||||
|
||||
GUF_DICT_FN_KEYWORDS void GUF_CAT(GUF_DICT_NAME, _free)(GUF_DICT_NAME *ht, void *ctx);
|
||||
GUF_DICT_KWRDS void GUF_CAT(GUF_DICT_NAME, _free)(GUF_DICT_NAME *ht, void *ctx);
|
||||
|
||||
GUF_DICT_FN_KEYWORDS void GUF_CAT(GUF_DICT_NAME, _try_insert)(GUF_DICT_NAME *ht, GUF_DICT_KEY_T *key, GUF_DICT_VAL_T *val, guf_cpy_opt key_opt, guf_cpy_opt val_opt, guf_err *err);
|
||||
GUF_DICT_FN_KEYWORDS void GUF_CAT(GUF_DICT_NAME, _insert)(GUF_DICT_NAME *ht, GUF_DICT_KEY_T *key, GUF_DICT_VAL_T *val, guf_cpy_opt key_opt, guf_cpy_opt val_opt);
|
||||
GUF_DICT_FN_KEYWORDS void GUF_CAT(GUF_DICT_NAME, _try_insert_val_arg)(GUF_DICT_NAME *ht, GUF_DICT_KEY_T key, GUF_DICT_VAL_T val, guf_cpy_opt key_opt, guf_cpy_opt val_opt, guf_err *err);
|
||||
GUF_DICT_FN_KEYWORDS void GUF_CAT(GUF_DICT_NAME, _insert_val_arg)(GUF_DICT_NAME *ht, GUF_DICT_KEY_T key, GUF_DICT_VAL_T val, guf_cpy_opt key_opt, guf_cpy_opt val_opt);
|
||||
GUF_DICT_KWRDS void GUF_CAT(GUF_DICT_NAME, _try_insert)(GUF_DICT_NAME *ht, GUF_DICT_KEY_T *key, GUF_DICT_VAL_T *val, guf_cpy_opt key_opt, guf_cpy_opt val_opt, guf_err *err);
|
||||
GUF_DICT_KWRDS void GUF_CAT(GUF_DICT_NAME, _insert)(GUF_DICT_NAME *ht, GUF_DICT_KEY_T *key, GUF_DICT_VAL_T *val, guf_cpy_opt key_opt, guf_cpy_opt val_opt);
|
||||
GUF_DICT_KWRDS void GUF_CAT(GUF_DICT_NAME, _try_insert_val_arg)(GUF_DICT_NAME *ht, GUF_DICT_KEY_T key, GUF_DICT_VAL_T val, guf_cpy_opt key_opt, guf_cpy_opt val_opt, guf_err *err);
|
||||
GUF_DICT_KWRDS void GUF_CAT(GUF_DICT_NAME, _insert_val_arg)(GUF_DICT_NAME *ht, GUF_DICT_KEY_T key, GUF_DICT_VAL_T val, guf_cpy_opt key_opt, guf_cpy_opt val_opt);
|
||||
|
||||
GUF_DICT_FN_KEYWORDS bool GUF_CAT(GUF_DICT_NAME, _erase)(GUF_DICT_NAME *ht, const GUF_DICT_KEY_T *key);
|
||||
GUF_DICT_FN_KEYWORDS bool GUF_CAT(GUF_DICT_NAME, _erase_val_arg)(GUF_DICT_NAME *ht, GUF_DICT_KEY_T key);
|
||||
GUF_DICT_KWRDS bool GUF_CAT(GUF_DICT_NAME, _erase)(GUF_DICT_NAME *ht, const GUF_DICT_KEY_T *key);
|
||||
GUF_DICT_KWRDS bool GUF_CAT(GUF_DICT_NAME, _erase_val_arg)(GUF_DICT_NAME *ht, GUF_DICT_KEY_T key);
|
||||
|
||||
#ifdef GUF_DICT_VAL_T
|
||||
GUF_DICT_FN_KEYWORDS GUF_DICT_VAL_T *GUF_CAT(GUF_DICT_NAME, _at)(GUF_DICT_NAME *ht, const GUF_DICT_KEY_T *key);
|
||||
GUF_DICT_FN_KEYWORDS GUF_DICT_VAL_T *GUF_CAT(GUF_DICT_NAME, _at_val_arg)(GUF_DICT_NAME *ht, GUF_DICT_KEY_T key);
|
||||
GUF_DICT_KWRDS GUF_DICT_VAL_T *GUF_CAT(GUF_DICT_NAME, _at)(GUF_DICT_NAME *ht, const GUF_DICT_KEY_T *key);
|
||||
GUF_DICT_KWRDS GUF_DICT_VAL_T *GUF_CAT(GUF_DICT_NAME, _at_val_arg)(GUF_DICT_NAME *ht, GUF_DICT_KEY_T key);
|
||||
#endif
|
||||
|
||||
GUF_DICT_FN_KEYWORDS bool GUF_CAT(GUF_DICT_NAME, _contains)(GUF_DICT_NAME *ht, const GUF_DICT_KEY_T *key);
|
||||
GUF_DICT_FN_KEYWORDS bool GUF_CAT(GUF_DICT_NAME, _contains_val_arg)(GUF_DICT_NAME *ht, GUF_DICT_KEY_T key);
|
||||
GUF_DICT_KWRDS bool GUF_CAT(GUF_DICT_NAME, _contains)(GUF_DICT_NAME *ht, const GUF_DICT_KEY_T *key);
|
||||
GUF_DICT_KWRDS bool GUF_CAT(GUF_DICT_NAME, _contains_val_arg)(GUF_DICT_NAME *ht, GUF_DICT_KEY_T key);
|
||||
|
||||
GUF_DICT_FN_KEYWORDS ptrdiff_t GUF_CAT(GUF_DICT_NAME, _size)(const GUF_DICT_NAME *ht);
|
||||
GUF_DICT_FN_KEYWORDS double GUF_CAT(GUF_DICT_NAME, _load_factor)(const GUF_DICT_NAME *ht);
|
||||
GUF_DICT_KWRDS ptrdiff_t GUF_CAT(GUF_DICT_NAME, _size)(const GUF_DICT_NAME *ht);
|
||||
GUF_DICT_KWRDS double GUF_CAT(GUF_DICT_NAME, _load_factor)(const GUF_DICT_NAME *ht);
|
||||
|
||||
/* Iterator functions */
|
||||
GUF_DICT_FN_KEYWORDS GUF_CAT(GUF_DICT_NAME, _iter) GUF_CAT(GUF_DICT_NAME, _begin)(const GUF_DICT_NAME* ht);
|
||||
GUF_DICT_FN_KEYWORDS GUF_CAT(GUF_DICT_NAME, _iter) GUF_CAT(GUF_DICT_NAME, _end)(const GUF_DICT_NAME* ht);
|
||||
GUF_DICT_FN_KEYWORDS GUF_CAT(GUF_DICT_NAME, _iter) GUF_CAT(GUF_DICT_NAME, _rbegin)(const GUF_DICT_NAME* ht);
|
||||
GUF_DICT_FN_KEYWORDS GUF_CAT(GUF_DICT_NAME, _iter) GUF_CAT(GUF_DICT_NAME, _rend)(const GUF_DICT_NAME* ht);
|
||||
GUF_DICT_FN_KEYWORDS bool GUF_CAT(GUF_DICT_NAME, _iter_is_end)(const GUF_DICT_NAME* ht, GUF_CAT(GUF_DICT_NAME, _iter) it);
|
||||
GUF_DICT_KWRDS GUF_CAT(GUF_DICT_NAME, _iter) GUF_CAT(GUF_DICT_NAME, _begin)(const GUF_DICT_NAME* ht);
|
||||
GUF_DICT_KWRDS GUF_CAT(GUF_DICT_NAME, _iter) GUF_CAT(GUF_DICT_NAME, _end)(const GUF_DICT_NAME* ht);
|
||||
GUF_DICT_KWRDS GUF_CAT(GUF_DICT_NAME, _iter) GUF_CAT(GUF_DICT_NAME, _rbegin)(const GUF_DICT_NAME* ht);
|
||||
GUF_DICT_KWRDS GUF_CAT(GUF_DICT_NAME, _iter) GUF_CAT(GUF_DICT_NAME, _rend)(const GUF_DICT_NAME* ht);
|
||||
GUF_DICT_KWRDS bool GUF_CAT(GUF_DICT_NAME, _iter_is_end)(const GUF_DICT_NAME* ht, GUF_CAT(GUF_DICT_NAME, _iter) it);
|
||||
|
||||
GUF_DICT_FN_KEYWORDS GUF_CAT(GUF_DICT_NAME, _iter) GUF_CAT(GUF_DICT_NAME, _iter_next)(const GUF_DICT_NAME *ht, GUF_CAT(GUF_DICT_NAME, _iter) it, ptrdiff_t step);
|
||||
GUF_DICT_FN_KEYWORDS GUF_CAT(GUF_DICT_NAME, _iter) GUF_CAT(GUF_DICT_NAME, _iter_at_idx)(const GUF_DICT_NAME *ht, ptrdiff_t idx);
|
||||
GUF_DICT_FN_KEYWORDS GUF_CAT(GUF_DICT_NAME, _iter) GUF_CAT(GUF_DICT_NAME, _reverse_iter_at_idx)(const GUF_DICT_NAME *ht, ptrdiff_t idx);
|
||||
GUF_DICT_FN_KEYWORDS ptrdiff_t GUF_CAT(GUF_DICT_NAME, _iter_to_idx)(const GUF_DICT_NAME *ht, GUF_CAT(GUF_DICT_NAME, _iter) it);
|
||||
GUF_DICT_KWRDS GUF_CAT(GUF_DICT_NAME, _iter) GUF_CAT(GUF_DICT_NAME, _iter_next)(const GUF_DICT_NAME *ht, GUF_CAT(GUF_DICT_NAME, _iter) it, ptrdiff_t step);
|
||||
GUF_DICT_KWRDS GUF_CAT(GUF_DICT_NAME, _iter) GUF_CAT(GUF_DICT_NAME, _iter_at_idx)(const GUF_DICT_NAME *ht, ptrdiff_t idx);
|
||||
GUF_DICT_KWRDS GUF_CAT(GUF_DICT_NAME, _iter) GUF_CAT(GUF_DICT_NAME, _reverse_iter_at_idx)(const GUF_DICT_NAME *ht, ptrdiff_t idx);
|
||||
GUF_DICT_KWRDS ptrdiff_t GUF_CAT(GUF_DICT_NAME, _iter_to_idx)(const GUF_DICT_NAME *ht, GUF_CAT(GUF_DICT_NAME, _iter) it);
|
||||
|
||||
#if defined(GUF_DICT_VAL_T) && (defined(GUF_DICT_VAL_T_EQ) || defined(GUF_DICT_VAL_T_IS_INTEGRAL_TYPE))
|
||||
GUF_DICT_FN_KEYWORDS GUF_CAT(GUF_DICT_NAME, _iter) GUF_CAT(GUF_DICT_NAME, _find_val)(GUF_DICT_NAME *ht, GUF_CAT(GUF_DICT_NAME, _iter) begin, GUF_CAT(GUF_DICT_NAME, _iter) end, const GUF_DICT_VAL_T *needle_val);
|
||||
GUF_DICT_FN_KEYWORDS GUF_CAT(GUF_DICT_NAME, _iter) GUF_CAT(GUF_DICT_NAME, _find_val_val_arg)(GUF_DICT_NAME *ht, GUF_CAT(GUF_DICT_NAME, _iter) begin, GUF_CAT(GUF_DICT_NAME, _iter) end, GUF_DICT_VAL_T needle_val);
|
||||
GUF_DICT_KWRDS GUF_CAT(GUF_DICT_NAME, _iter) GUF_CAT(GUF_DICT_NAME, _find_val)(GUF_DICT_NAME *ht, GUF_CAT(GUF_DICT_NAME, _iter) begin, GUF_CAT(GUF_DICT_NAME, _iter) end, const GUF_DICT_VAL_T *needle_val);
|
||||
GUF_DICT_KWRDS GUF_CAT(GUF_DICT_NAME, _iter) GUF_CAT(GUF_DICT_NAME, _find_val_val_arg)(GUF_DICT_NAME *ht, GUF_CAT(GUF_DICT_NAME, _iter) begin, GUF_CAT(GUF_DICT_NAME, _iter) end, GUF_DICT_VAL_T needle_val);
|
||||
#endif
|
||||
#if defined(GUF_DICT_VAL_T)
|
||||
GUF_DICT_FN_KEYWORDS GUF_CAT(GUF_DICT_NAME, _iter) GUF_CAT(GUF_DICT_NAME, _find_val_if)(GUF_DICT_NAME *ht, GUF_CAT(GUF_DICT_NAME, _iter) begin, GUF_CAT(GUF_DICT_NAME, _iter) end, bool (*predicate)(const GUF_DICT_VAL_T *));
|
||||
GUF_DICT_KWRDS GUF_CAT(GUF_DICT_NAME, _iter) GUF_CAT(GUF_DICT_NAME, _find_val_if)(GUF_DICT_NAME *ht, GUF_CAT(GUF_DICT_NAME, _iter) begin, GUF_CAT(GUF_DICT_NAME, _iter) end, bool (*predicate)(const GUF_DICT_VAL_T *));
|
||||
#endif
|
||||
|
||||
|
||||
@ -178,12 +174,12 @@ static inline void GUF_CAT(GUF_DICT_KV_NAME, _free)(GUF_DICT_KV_NAME *kv, void *
|
||||
}
|
||||
#define GUF_T GUF_DICT_KV_NAME
|
||||
#define GUF_T_FREE GUF_CAT(GUF_DICT_KV_NAME, _free)
|
||||
#define GUF_CNT_NAME GUF_DICT_KV_DBUF
|
||||
#define GUF_STATIC
|
||||
#define GUF_IMPL
|
||||
#define GUF_DBUF_NAME GUF_DICT_KV_DBUF
|
||||
#define GUF_DBUF_WITHOUT_TYPES
|
||||
#define GUF_DBUF_IMPL_STATIC
|
||||
#include "guf_dbuf.h"
|
||||
|
||||
GUF_DICT_FN_KEYWORDS double GUF_CAT(GUF_DICT_NAME, _load_factor)(const GUF_DICT_NAME *ht)
|
||||
GUF_DICT_KWRDS double GUF_CAT(GUF_DICT_NAME, _load_factor)(const GUF_DICT_NAME *ht)
|
||||
{
|
||||
if (ht->kv_indices_cap == 0) {
|
||||
return 1;
|
||||
@ -193,7 +189,7 @@ GUF_DICT_FN_KEYWORDS double GUF_CAT(GUF_DICT_NAME, _load_factor)(const GUF_DICT_
|
||||
return (double)occupied_count / (double)ht->kv_indices_cap;
|
||||
}
|
||||
|
||||
GUF_DICT_FN_KEYWORDS GUF_DICT_NAME *GUF_CAT(GUF_DICT_NAME, _try_init)(GUF_DICT_NAME *ht, guf_allocator *alloc, guf_err *err)
|
||||
GUF_DICT_KWRDS GUF_DICT_NAME *GUF_CAT(GUF_DICT_NAME, _try_init)(GUF_DICT_NAME *ht, guf_allocator *alloc, guf_err *err)
|
||||
{
|
||||
if (!ht || !alloc) {
|
||||
guf_err_set_or_panic(err, GUF_ERR_INVALID_ARG, GUF_ERR_MSG("in dict_try_init: ht or alloc NULL"));
|
||||
@ -214,12 +210,12 @@ GUF_DICT_FN_KEYWORDS GUF_DICT_NAME *GUF_CAT(GUF_DICT_NAME, _try_init)(GUF_DICT_N
|
||||
return ht;
|
||||
}
|
||||
|
||||
GUF_DICT_FN_KEYWORDS GUF_DICT_NAME *GUF_CAT(GUF_DICT_NAME, _init)(GUF_DICT_NAME *ht, guf_allocator *alloc)
|
||||
GUF_DICT_KWRDS GUF_DICT_NAME *GUF_CAT(GUF_DICT_NAME, _init)(GUF_DICT_NAME *ht, guf_allocator *alloc)
|
||||
{
|
||||
return GUF_CAT(GUF_DICT_NAME, _try_init)(ht, alloc, NULL);
|
||||
}
|
||||
|
||||
GUF_DICT_FN_KEYWORDS bool GUF_CAT(GUF_DICT_NAME, _valid)(const GUF_DICT_NAME *ht)
|
||||
GUF_DICT_KWRDS bool GUF_CAT(GUF_DICT_NAME, _valid)(const GUF_DICT_NAME *ht)
|
||||
{
|
||||
if (!ht) {
|
||||
return false;
|
||||
@ -230,7 +226,7 @@ GUF_DICT_FN_KEYWORDS bool GUF_CAT(GUF_DICT_NAME, _valid)(const GUF_DICT_NAME *ht
|
||||
return kv_dbuf_valid && kv_meta_buf_valid && count_valid;
|
||||
}
|
||||
|
||||
GUF_DICT_FN_KEYWORDS void GUF_CAT(GUF_DICT_NAME, _free)(GUF_DICT_NAME *ht, void *ctx)
|
||||
GUF_DICT_KWRDS void GUF_CAT(GUF_DICT_NAME, _free)(GUF_DICT_NAME *ht, void *ctx)
|
||||
{
|
||||
(void)ctx;
|
||||
GUF_ASSERT_RELEASE(GUF_CAT(GUF_DICT_NAME, _valid)(ht));
|
||||
@ -248,7 +244,7 @@ GUF_DICT_FN_KEYWORDS void GUF_CAT(GUF_DICT_NAME, _free)(GUF_DICT_NAME *ht, void
|
||||
ht->max_probelen = 0;
|
||||
}
|
||||
|
||||
GUF_DICT_FN_KEYWORDS ptrdiff_t GUF_CAT(GUF_DICT_NAME, _size)(const GUF_DICT_NAME *ht)
|
||||
GUF_DICT_KWRDS ptrdiff_t GUF_CAT(GUF_DICT_NAME, _size)(const GUF_DICT_NAME *ht)
|
||||
{
|
||||
GUF_ASSERT_RELEASE(GUF_CAT(GUF_DICT_NAME, _valid)(ht));
|
||||
return ht->kv_elems.size;
|
||||
@ -319,7 +315,7 @@ static size_t GUF_CAT(GUF_DICT_NAME, _find_idx)(GUF_DICT_NAME *ht, const GUF_DIC
|
||||
#undef GUF_MOD_CAP
|
||||
}
|
||||
|
||||
GUF_DICT_FN_KEYWORDS void GUF_CAT(GUF_DICT_NAME, _try_insert)(GUF_DICT_NAME *ht, GUF_DICT_KEY_T *key, GUF_DICT_VAL_T *val, guf_cpy_opt key_opt, guf_cpy_opt val_opt, guf_err *err)
|
||||
GUF_DICT_KWRDS void GUF_CAT(GUF_DICT_NAME, _try_insert)(GUF_DICT_NAME *ht, GUF_DICT_KEY_T *key, GUF_DICT_VAL_T *val, guf_cpy_opt key_opt, guf_cpy_opt val_opt, guf_err *err)
|
||||
{
|
||||
GUF_ASSERT_RELEASE(GUF_CAT(GUF_DICT_NAME, _valid)(ht));
|
||||
|
||||
@ -469,24 +465,24 @@ GUF_DICT_FN_KEYWORDS void GUF_CAT(GUF_DICT_NAME, _try_insert)(GUF_DICT_NAME *ht,
|
||||
GUF_CAT(GUF_DICT_KV_DBUF, _try_push_val)(&ht->kv_elems, kv, err);
|
||||
}
|
||||
|
||||
GUF_DICT_FN_KEYWORDS void GUF_CAT(GUF_DICT_NAME, _insert)(GUF_DICT_NAME *ht, GUF_DICT_KEY_T *key, GUF_DICT_VAL_T *val, guf_cpy_opt key_opt, guf_cpy_opt val_opt)
|
||||
GUF_DICT_KWRDS void GUF_CAT(GUF_DICT_NAME, _insert)(GUF_DICT_NAME *ht, GUF_DICT_KEY_T *key, GUF_DICT_VAL_T *val, guf_cpy_opt key_opt, guf_cpy_opt val_opt)
|
||||
{
|
||||
GUF_CAT(GUF_DICT_NAME, _try_insert)(ht, key, val, key_opt, val_opt, NULL);
|
||||
}
|
||||
|
||||
GUF_DICT_FN_KEYWORDS void GUF_CAT(GUF_DICT_NAME, _try_insert_val_arg)(GUF_DICT_NAME *ht, GUF_DICT_KEY_T key, GUF_DICT_VAL_T val, guf_cpy_opt key_opt, guf_cpy_opt val_opt, guf_err *err)
|
||||
GUF_DICT_KWRDS void GUF_CAT(GUF_DICT_NAME, _try_insert_val_arg)(GUF_DICT_NAME *ht, GUF_DICT_KEY_T key, GUF_DICT_VAL_T val, guf_cpy_opt key_opt, guf_cpy_opt val_opt, guf_err *err)
|
||||
{
|
||||
GUF_CAT(GUF_DICT_NAME, _try_insert)(ht, &key, &val, key_opt, val_opt, err);
|
||||
}
|
||||
|
||||
GUF_DICT_FN_KEYWORDS void GUF_CAT(GUF_DICT_NAME, _insert_val_arg)(GUF_DICT_NAME *ht, GUF_DICT_KEY_T key, GUF_DICT_VAL_T val, guf_cpy_opt key_opt, guf_cpy_opt val_opt)
|
||||
GUF_DICT_KWRDS void GUF_CAT(GUF_DICT_NAME, _insert_val_arg)(GUF_DICT_NAME *ht, GUF_DICT_KEY_T key, GUF_DICT_VAL_T val, guf_cpy_opt key_opt, guf_cpy_opt val_opt)
|
||||
{
|
||||
GUF_CAT(GUF_DICT_NAME, _insert)(ht, &key, &val, key_opt, val_opt);
|
||||
}
|
||||
|
||||
|
||||
#ifdef GUF_DICT_VAL_T
|
||||
GUF_DICT_FN_KEYWORDS GUF_DICT_VAL_T *GUF_CAT(GUF_DICT_NAME, _at)(GUF_DICT_NAME *ht, const GUF_DICT_KEY_T *key)
|
||||
GUF_DICT_KWRDS GUF_DICT_VAL_T *GUF_CAT(GUF_DICT_NAME, _at)(GUF_DICT_NAME *ht, const GUF_DICT_KEY_T *key)
|
||||
{
|
||||
GUF_ASSERT_RELEASE(GUF_CAT(GUF_DICT_NAME, _valid)(ht));
|
||||
if (!key) {
|
||||
@ -506,14 +502,14 @@ GUF_DICT_FN_KEYWORDS void GUF_CAT(GUF_DICT_NAME, _insert_val_arg)(GUF_DICT_NAME
|
||||
}
|
||||
}
|
||||
|
||||
GUF_DICT_FN_KEYWORDS GUF_DICT_VAL_T *GUF_CAT(GUF_DICT_NAME, _at_val_arg)(GUF_DICT_NAME *ht, GUF_DICT_KEY_T key)
|
||||
GUF_DICT_KWRDS GUF_DICT_VAL_T *GUF_CAT(GUF_DICT_NAME, _at_val_arg)(GUF_DICT_NAME *ht, GUF_DICT_KEY_T key)
|
||||
{
|
||||
return GUF_CAT(GUF_DICT_NAME, _at)(ht, &key);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
GUF_DICT_FN_KEYWORDS bool GUF_CAT(GUF_DICT_NAME, _contains)(GUF_DICT_NAME *ht, const GUF_DICT_KEY_T *key)
|
||||
GUF_DICT_KWRDS bool GUF_CAT(GUF_DICT_NAME, _contains)(GUF_DICT_NAME *ht, const GUF_DICT_KEY_T *key)
|
||||
{
|
||||
GUF_ASSERT_RELEASE(GUF_CAT(GUF_DICT_NAME, _valid)(ht));
|
||||
if (!key) {
|
||||
@ -525,13 +521,13 @@ GUF_DICT_FN_KEYWORDS bool GUF_CAT(GUF_DICT_NAME, _contains)(GUF_DICT_NAME *ht, c
|
||||
return key_exists;
|
||||
}
|
||||
|
||||
GUF_DICT_FN_KEYWORDS bool GUF_CAT(GUF_DICT_NAME, _contains_val_arg)(GUF_DICT_NAME *ht, GUF_DICT_KEY_T key)
|
||||
GUF_DICT_KWRDS bool GUF_CAT(GUF_DICT_NAME, _contains_val_arg)(GUF_DICT_NAME *ht, GUF_DICT_KEY_T key)
|
||||
{
|
||||
return GUF_CAT(GUF_DICT_NAME, _contains)(ht, &key);
|
||||
}
|
||||
|
||||
|
||||
GUF_DICT_FN_KEYWORDS bool GUF_CAT(GUF_DICT_NAME, _erase)(GUF_DICT_NAME *ht, const GUF_DICT_KEY_T *key)
|
||||
GUF_DICT_KWRDS bool GUF_CAT(GUF_DICT_NAME, _erase)(GUF_DICT_NAME *ht, const GUF_DICT_KEY_T *key)
|
||||
{
|
||||
GUF_ASSERT_RELEASE(GUF_CAT(GUF_DICT_NAME, _valid)(ht));
|
||||
|
||||
@ -573,7 +569,7 @@ GUF_DICT_FN_KEYWORDS bool GUF_CAT(GUF_DICT_NAME, _erase)(GUF_DICT_NAME *ht, cons
|
||||
return true;
|
||||
}
|
||||
|
||||
GUF_DICT_FN_KEYWORDS bool GUF_CAT(GUF_DICT_NAME, _erase_val_arg)(GUF_DICT_NAME *ht, GUF_DICT_KEY_T key)
|
||||
GUF_DICT_KWRDS bool GUF_CAT(GUF_DICT_NAME, _erase_val_arg)(GUF_DICT_NAME *ht, GUF_DICT_KEY_T key)
|
||||
{
|
||||
return GUF_CAT(GUF_DICT_NAME, _erase)(ht, &key);
|
||||
}
|
||||
@ -581,65 +577,65 @@ GUF_DICT_FN_KEYWORDS bool GUF_CAT(GUF_DICT_NAME, _erase_val_arg)(GUF_DICT_NAME *
|
||||
|
||||
/* Iterator functions */
|
||||
|
||||
GUF_DICT_FN_KEYWORDS GUF_CAT(GUF_DICT_NAME, _iter) GUF_CAT(GUF_DICT_NAME, _begin)(const GUF_DICT_NAME* ht)
|
||||
GUF_DICT_KWRDS GUF_CAT(GUF_DICT_NAME, _iter) GUF_CAT(GUF_DICT_NAME, _begin)(const GUF_DICT_NAME* ht)
|
||||
{
|
||||
GUF_ASSERT_RELEASE(GUF_CAT(GUF_DICT_NAME, _valid)(ht));
|
||||
GUF_CAT(GUF_DICT_KV_DBUF, _iter) kv_it = GUF_CAT(GUF_DICT_KV_DBUF, _begin)(&ht->kv_elems);
|
||||
return (GUF_CAT(GUF_DICT_NAME, _iter)){.ptr = kv_it.ptr, .base = kv_it.base};
|
||||
}
|
||||
|
||||
GUF_DICT_FN_KEYWORDS GUF_CAT(GUF_DICT_NAME, _iter) GUF_CAT(GUF_DICT_NAME, _end)(const GUF_DICT_NAME* ht)
|
||||
GUF_DICT_KWRDS GUF_CAT(GUF_DICT_NAME, _iter) GUF_CAT(GUF_DICT_NAME, _end)(const GUF_DICT_NAME* ht)
|
||||
{
|
||||
GUF_ASSERT_RELEASE(GUF_CAT(GUF_DICT_NAME, _valid)(ht));
|
||||
GUF_CAT(GUF_DICT_KV_DBUF, _iter) kv_it = GUF_CAT(GUF_DICT_KV_DBUF, _end)(&ht->kv_elems);
|
||||
return (GUF_CAT(GUF_DICT_NAME, _iter)){.ptr = kv_it.ptr, .base = kv_it.base};
|
||||
}
|
||||
|
||||
GUF_DICT_FN_KEYWORDS GUF_CAT(GUF_DICT_NAME, _iter) GUF_CAT(GUF_DICT_NAME, _rbegin)(const GUF_DICT_NAME* ht)
|
||||
GUF_DICT_KWRDS GUF_CAT(GUF_DICT_NAME, _iter) GUF_CAT(GUF_DICT_NAME, _rbegin)(const GUF_DICT_NAME* ht)
|
||||
{
|
||||
GUF_ASSERT_RELEASE(GUF_CAT(GUF_DICT_NAME, _valid)(ht));
|
||||
GUF_CAT(GUF_DICT_KV_DBUF, _iter) kv_it = GUF_CAT(GUF_DICT_KV_DBUF, _rbegin)(&ht->kv_elems);
|
||||
return (GUF_CAT(GUF_DICT_NAME, _iter)){.ptr = kv_it.ptr, .base = kv_it.base};
|
||||
}
|
||||
|
||||
GUF_DICT_FN_KEYWORDS GUF_CAT(GUF_DICT_NAME, _iter) GUF_CAT(GUF_DICT_NAME, _rend)(const GUF_DICT_NAME* ht)
|
||||
GUF_DICT_KWRDS GUF_CAT(GUF_DICT_NAME, _iter) GUF_CAT(GUF_DICT_NAME, _rend)(const GUF_DICT_NAME* ht)
|
||||
{
|
||||
GUF_ASSERT_RELEASE(GUF_CAT(GUF_DICT_NAME, _valid)(ht));
|
||||
GUF_CAT(GUF_DICT_KV_DBUF, _iter) kv_it = GUF_CAT(GUF_DICT_KV_DBUF, _rend)(&ht->kv_elems);
|
||||
return (GUF_CAT(GUF_DICT_NAME, _iter)){.ptr = kv_it.ptr, .base = kv_it.base};
|
||||
}
|
||||
|
||||
GUF_DICT_FN_KEYWORDS bool GUF_CAT(GUF_DICT_NAME, _iter_is_end)(const GUF_DICT_NAME* ht, GUF_CAT(GUF_DICT_NAME, _iter) it)
|
||||
GUF_DICT_KWRDS bool GUF_CAT(GUF_DICT_NAME, _iter_is_end)(const GUF_DICT_NAME* ht, GUF_CAT(GUF_DICT_NAME, _iter) it)
|
||||
{
|
||||
const bool is_reverse_it = it.base != NULL;
|
||||
const GUF_CAT(GUF_DICT_NAME, _iter) dbuf_end_it = is_reverse_it ? GUF_CAT(GUF_DICT_NAME, _rend)(ht) : GUF_CAT(GUF_DICT_NAME, _end)(ht);
|
||||
return it.ptr == dbuf_end_it.ptr;
|
||||
}
|
||||
|
||||
GUF_DICT_FN_KEYWORDS GUF_CAT(GUF_DICT_NAME, _iter) GUF_CAT(GUF_DICT_NAME, _iter_next)(const GUF_DICT_NAME *ht, GUF_CAT(GUF_DICT_NAME, _iter) it, ptrdiff_t step)
|
||||
GUF_DICT_KWRDS GUF_CAT(GUF_DICT_NAME, _iter) GUF_CAT(GUF_DICT_NAME, _iter_next)(const GUF_DICT_NAME *ht, GUF_CAT(GUF_DICT_NAME, _iter) it, ptrdiff_t step)
|
||||
{
|
||||
GUF_CAT(GUF_DICT_KV_DBUF, _iter) kv_it = GUF_CAT(GUF_DICT_KV_DBUF, _iter_next)(&ht->kv_elems, it, step);
|
||||
return (GUF_CAT(GUF_DICT_NAME, _iter)){.ptr = kv_it.ptr, .base = kv_it.base};
|
||||
}
|
||||
GUF_DICT_FN_KEYWORDS GUF_CAT(GUF_DICT_NAME, _iter) GUF_CAT(GUF_DICT_NAME, _iter_at_idx)(const GUF_DICT_NAME *ht, ptrdiff_t idx)
|
||||
GUF_DICT_KWRDS GUF_CAT(GUF_DICT_NAME, _iter) GUF_CAT(GUF_DICT_NAME, _iter_at_idx)(const GUF_DICT_NAME *ht, ptrdiff_t idx)
|
||||
{
|
||||
GUF_CAT(GUF_DICT_KV_DBUF, _iter) kv_it = GUF_CAT(GUF_DICT_KV_DBUF, _iter_at_idx)(&ht->kv_elems, idx);
|
||||
return (GUF_CAT(GUF_DICT_NAME, _iter)){.ptr = kv_it.ptr, .base = kv_it.base};
|
||||
}
|
||||
|
||||
GUF_DICT_FN_KEYWORDS GUF_CAT(GUF_DICT_NAME, _iter) GUF_CAT(GUF_DICT_NAME, _reverse_iter_at_idx)(const GUF_DICT_NAME *ht, ptrdiff_t idx)
|
||||
GUF_DICT_KWRDS GUF_CAT(GUF_DICT_NAME, _iter) GUF_CAT(GUF_DICT_NAME, _reverse_iter_at_idx)(const GUF_DICT_NAME *ht, ptrdiff_t idx)
|
||||
{
|
||||
GUF_CAT(GUF_DICT_KV_DBUF, _iter) kv_it = GUF_CAT(GUF_DICT_KV_DBUF, _reverse_iter_at_idx)(&ht->kv_elems, idx);
|
||||
return (GUF_CAT(GUF_DICT_NAME, _iter)){.ptr = kv_it.ptr, .base = kv_it.base};
|
||||
}
|
||||
|
||||
GUF_DICT_FN_KEYWORDS ptrdiff_t GUF_CAT(GUF_DICT_NAME, _iter_to_idx)(const GUF_DICT_NAME *ht, GUF_CAT(GUF_DICT_NAME, _iter) it)
|
||||
GUF_DICT_KWRDS ptrdiff_t GUF_CAT(GUF_DICT_NAME, _iter_to_idx)(const GUF_DICT_NAME *ht, GUF_CAT(GUF_DICT_NAME, _iter) it)
|
||||
{
|
||||
return GUF_CAT(GUF_DICT_KV_DBUF, _iter_to_idx)(&ht->kv_elems, it);
|
||||
}
|
||||
|
||||
#if defined(GUF_DICT_VAL_T) && (defined(GUF_DICT_VAL_T_EQ) || defined(GUF_DICT_VAL_T_IS_INTEGRAL_TYPE))
|
||||
GUF_DICT_FN_KEYWORDS GUF_CAT(GUF_DICT_NAME, _iter) GUF_CAT(GUF_DICT_NAME, _find_val)(GUF_DICT_NAME *ht, GUF_CAT(GUF_DICT_NAME, _iter) begin, GUF_CAT(GUF_DICT_NAME, _iter) end, const GUF_DICT_VAL_T *needle)
|
||||
GUF_DICT_KWRDS GUF_CAT(GUF_DICT_NAME, _iter) GUF_CAT(GUF_DICT_NAME, _find_val)(GUF_DICT_NAME *ht, GUF_CAT(GUF_DICT_NAME, _iter) begin, GUF_CAT(GUF_DICT_NAME, _iter) end, const GUF_DICT_VAL_T *needle)
|
||||
{
|
||||
GUF_ASSERT_RELEASE(GUF_CAT(GUF_DICT_NAME, _valid)(ht));
|
||||
GUF_ASSERT_RELEASE(needle);
|
||||
@ -669,14 +665,14 @@ GUF_DICT_FN_KEYWORDS GUF_CAT(GUF_DICT_NAME, _iter) GUF_CAT(GUF_DICT_NAME, _find_
|
||||
return dbuf_end_it;
|
||||
}
|
||||
|
||||
GUF_DICT_FN_KEYWORDS GUF_CAT(GUF_DICT_NAME, _iter) GUF_CAT(GUF_DICT_NAME, _find_val_val_arg)(GUF_DICT_NAME *ht, GUF_CAT(GUF_DICT_NAME, _iter) begin, GUF_CAT(GUF_DICT_NAME, _iter) end, GUF_DICT_VAL_T needle)
|
||||
GUF_DICT_KWRDS GUF_CAT(GUF_DICT_NAME, _iter) GUF_CAT(GUF_DICT_NAME, _find_val_val_arg)(GUF_DICT_NAME *ht, GUF_CAT(GUF_DICT_NAME, _iter) begin, GUF_CAT(GUF_DICT_NAME, _iter) end, GUF_DICT_VAL_T needle)
|
||||
{
|
||||
return GUF_CAT(GUF_DICT_NAME, _find_val)(ht, begin, end, &needle);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(GUF_DICT_VAL_T)
|
||||
GUF_DICT_FN_KEYWORDS GUF_CAT(GUF_DICT_NAME, _iter) GUF_CAT(GUF_DICT_NAME, _find_val_if)(GUF_DICT_NAME *ht, GUF_CAT(GUF_DICT_NAME, _iter) begin, GUF_CAT(GUF_DICT_NAME, _iter) end, bool (*predicate)(const GUF_DICT_VAL_T *))
|
||||
GUF_DICT_KWRDS GUF_CAT(GUF_DICT_NAME, _iter) GUF_CAT(GUF_DICT_NAME, _find_val_if)(GUF_DICT_NAME *ht, GUF_CAT(GUF_DICT_NAME, _iter) begin, GUF_CAT(GUF_DICT_NAME, _iter) end, bool (*predicate)(const GUF_DICT_VAL_T *))
|
||||
{
|
||||
GUF_ASSERT_RELEASE(GUF_CAT(GUF_DICT_NAME, _valid)(ht));
|
||||
GUF_ASSERT_RELEASE(predicate);
|
||||
@ -740,5 +736,4 @@ GUF_DICT_FN_KEYWORDS GUF_CAT(GUF_DICT_NAME, _iter) GUF_CAT(GUF_DICT_NAME, _find_
|
||||
|
||||
#undef GUF_DICT_IMPL_STATIC
|
||||
#undef GUF_DICT_IMPL
|
||||
#undef GUF_DICT_STATIC
|
||||
#undef GUF_DICT_FN_KEYWORDS
|
||||
#undef GUF_DICT_KWRDS
|
||||
|
||||
@ -1,3 +1,9 @@
|
||||
#if defined(GUF_HASH_IMPL_STATIC)
|
||||
#define GUF_HASH_KWRDS static
|
||||
#else
|
||||
#define GUF_HASH_KWRDS
|
||||
#endif
|
||||
|
||||
#ifndef GUF_HASH_H
|
||||
#define GUF_HASH_H
|
||||
#include "guf_common.h"
|
||||
@ -8,17 +14,12 @@
|
||||
cf. http://www.isthe.com/chongo/tech/comp/fnv/ (last retrieved: 2023-11-30)
|
||||
*/
|
||||
|
||||
#if defined(GUF_IMPL_STATIC) || defined(GUF_STATIC)
|
||||
#define GUF_FN_KEYWORDS static
|
||||
#else
|
||||
#define GUF_FN_KEYWORDS
|
||||
#endif
|
||||
|
||||
#define GUF_HASH32_INIT UINT32_C(2166136261)
|
||||
#define GUF_HASH64_INIT UINT64_C(14695981039346656037)
|
||||
|
||||
GUF_FN_KEYWORDS uint32_t guf_hash32(const void *data, ptrdiff_t num_bytes, uint32_t hash); // FNV-1a (32 bit)
|
||||
GUF_FN_KEYWORDS uint64_t guf_hash64(const void *data, ptrdiff_t num_bytes, uint64_t hash); // FNV-1a (64 bit)
|
||||
GUF_HASH_KWRDS uint32_t guf_hash32(const void *data, ptrdiff_t num_bytes, uint32_t hash); // FNV-1a (32 bit)
|
||||
GUF_HASH_KWRDS uint64_t guf_hash64(const void *data, ptrdiff_t num_bytes, uint64_t hash); // FNV-1a (64 bit)
|
||||
|
||||
#ifdef GUF_HASH_32_BIT
|
||||
typedef uint32_t guf_hash_size_t;
|
||||
@ -43,11 +44,11 @@ static inline guf_hash_size_t guf_mod_pow2_hash(guf_hash_size_t a, guf_hash_size
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(GUF_IMPL) || defined(GUF_IMPL_STATIC)
|
||||
#if defined(GUF_HASH_IMPL) || defined(GUF_HASH_IMPL_STATIC)
|
||||
|
||||
#include "guf_assert.h"
|
||||
|
||||
GUF_FN_KEYWORDS uint32_t guf_hash32(const void *data, ptrdiff_t num_bytes, uint32_t hash)
|
||||
GUF_HASH_KWRDS uint32_t guf_hash32(const void *data, ptrdiff_t num_bytes, uint32_t hash)
|
||||
{
|
||||
GUF_ASSERT_RELEASE(data);
|
||||
GUF_ASSERT_RELEASE(num_bytes >= 0);
|
||||
@ -60,7 +61,7 @@ GUF_FN_KEYWORDS uint32_t guf_hash32(const void *data, ptrdiff_t num_bytes, uint3
|
||||
return hash;
|
||||
}
|
||||
|
||||
GUF_FN_KEYWORDS uint64_t guf_hash64(const void *data, ptrdiff_t num_bytes, uint64_t hash)
|
||||
GUF_HASH_KWRDS uint64_t guf_hash64(const void *data, ptrdiff_t num_bytes, uint64_t hash)
|
||||
{
|
||||
GUF_ASSERT_RELEASE(data);
|
||||
GUF_ASSERT_RELEASE(num_bytes >= 0);
|
||||
@ -73,9 +74,8 @@ GUF_FN_KEYWORDS uint64_t guf_hash64(const void *data, ptrdiff_t num_bytes, uint6
|
||||
return hash;
|
||||
}
|
||||
|
||||
#undef GUF_IMPL
|
||||
#undef GUF_IMPL_STATIC
|
||||
#undef GUF_HASH_IMPL
|
||||
#undef GUF_HASH_IMPL_STATIC
|
||||
#endif /* endif GUF_IMPL/GUF_IMPL_STATIC */
|
||||
|
||||
#undef GUF_FN_KEYWORDS
|
||||
#undef GUF_STATIC
|
||||
#undef GUF_HASH_KWRDS
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
#define GUF_INIT
|
||||
#include "guf_assert.h"
|
||||
|
||||
#define GUF_IMPL
|
||||
#define GUF_HASH_IMPL
|
||||
#include "guf_hash.h"
|
||||
|
||||
// static inline bool guf_init(void)
|
||||
|
||||
@ -3,6 +3,7 @@
|
||||
#include "guf_assert.h"
|
||||
|
||||
#define GUF_PI 3.14159265358979323846264338327950288
|
||||
#define GUF_PI_F32 3.14159265358979323846264338327950288f
|
||||
|
||||
// Rotate left.
|
||||
static inline uint64_t guf_rotl_u64(uint64_t x, int k) {return (x << k) | (x >> (64 - k));}
|
||||
|
||||
@ -1,14 +1,14 @@
|
||||
#if defined(GUF_RAND_IMPL_STATIC)
|
||||
#define GUF_RAND_KWRDS static
|
||||
#else
|
||||
#define GUF_RAND_KWRDS
|
||||
#endif
|
||||
|
||||
#ifndef GUF_RAND_H
|
||||
#define GUF_RAND_H
|
||||
|
||||
#include "guf_common.h"
|
||||
|
||||
#if defined(GUF_IMPL_STATIC) || defined(GUF_STATIC)
|
||||
#define GUF_FN_KEYWORDS static
|
||||
#else
|
||||
#define GUF_FN_KEYWORDS
|
||||
#endif
|
||||
|
||||
#ifdef GUF_RAND_32_BIT
|
||||
#define GUF_RAND_MAX UINT32_MAX
|
||||
typedef struct guf_randstate { // State for xoshiro128** 1.1
|
||||
@ -21,38 +21,38 @@
|
||||
} guf_randstate;
|
||||
#endif
|
||||
|
||||
GUF_FN_KEYWORDS uint64_t guf_rand_splitmix64(uint64_t *state);
|
||||
GUF_RAND_KWRDS uint64_t guf_rand_splitmix64(uint64_t *state);
|
||||
|
||||
GUF_FN_KEYWORDS void guf_randstate_init(guf_randstate *state, uint64_t seed);
|
||||
void guf_randstate_jump(guf_randstate *state); // Advance the state; equivalent to 2^128 calls to guf_rand_u64(state)
|
||||
GUF_RAND_KWRDS void guf_randstate_init(guf_randstate *state, uint64_t seed);
|
||||
GUF_RAND_KWRDS void guf_randstate_jump(guf_randstate *state); // Advance the state; equivalent to 2^128 calls to guf_rand_u64(state)
|
||||
|
||||
// uniform distributions
|
||||
GUF_FN_KEYWORDS uint32_t guf_rand_u32(guf_randstate *state); // [0, UINT32_MAX]
|
||||
GUF_FN_KEYWORDS uint64_t guf_rand_u64(guf_randstate *state); // [0, UINT64_MAX]
|
||||
GUF_FN_KEYWORDS double guf_rand_f64(guf_randstate *state); // [0.0, 1.0)
|
||||
GUF_FN_KEYWORDS float guf_rand_f32(guf_randstate *state); // [0.f, 1.f)
|
||||
GUF_RAND_KWRDS uint32_t guf_rand_u32(guf_randstate *state); // [0, UINT32_MAX]
|
||||
GUF_RAND_KWRDS uint64_t guf_rand_u64(guf_randstate *state); // [0, UINT64_MAX]
|
||||
GUF_RAND_KWRDS double guf_rand_f64(guf_randstate *state); // [0.0, 1.0)
|
||||
GUF_RAND_KWRDS float guf_rand_f32(guf_randstate *state); // [0.f, 1.f)
|
||||
|
||||
// return true with a probability of p, false with a probability of (1 - p)
|
||||
GUF_FN_KEYWORDS bool guf_rand_bernoulli_trial_f32(guf_randstate *state, float p);
|
||||
GUF_FN_KEYWORDS bool guf_rand_bernoulli_trial_f64(guf_randstate *state, double p);
|
||||
GUF_FN_KEYWORDS bool guf_rand_flip(guf_randstate *state); // Fair coin flip (bernoulli trial with p == 0.5)
|
||||
GUF_RAND_KWRDS bool guf_rand_bernoulli_trial_f32(guf_randstate *state, float p);
|
||||
GUF_RAND_KWRDS bool guf_rand_bernoulli_trial_f64(guf_randstate *state, double p);
|
||||
GUF_RAND_KWRDS bool guf_rand_flip(guf_randstate *state); // Fair coin flip (bernoulli trial with p == 0.5)
|
||||
|
||||
GUF_FN_KEYWORDS double guf_randrange_f64(guf_randstate *state, double min, double end); // [min, end)
|
||||
GUF_FN_KEYWORDS float guf_randrange_f32(guf_randstate *state, float min, float end); // [min, end)
|
||||
GUF_RAND_KWRDS double guf_randrange_f64(guf_randstate *state, double min, double end); // [min, end)
|
||||
GUF_RAND_KWRDS float guf_randrange_f32(guf_randstate *state, float min, float end); // [min, end)
|
||||
|
||||
GUF_FN_KEYWORDS int32_t guf_randrange_i32(guf_randstate *state, int32_t min, int32_t max); // [min, max]
|
||||
GUF_FN_KEYWORDS uint32_t guf_randrange_u32(guf_randstate *state, uint32_t min, uint32_t max); // [min, max]
|
||||
GUF_FN_KEYWORDS int64_t guf_randrange_i64(guf_randstate *state, int64_t min, int64_t max); // [min, max]
|
||||
GUF_RAND_KWRDS int32_t guf_randrange_i32(guf_randstate *state, int32_t min, int32_t max); // [min, max]
|
||||
GUF_RAND_KWRDS uint32_t guf_randrange_u32(guf_randstate *state, uint32_t min, uint32_t max); // [min, max]
|
||||
GUF_RAND_KWRDS int64_t guf_randrange_i64(guf_randstate *state, int64_t min, int64_t max); // [min, max]
|
||||
|
||||
// normal distributions
|
||||
GUF_FN_KEYWORDS void guf_rand_normal_sample_f64(guf_randstate *state, double mean, double std_dev, double *result, ptrdiff_t n);
|
||||
GUF_FN_KEYWORDS void guf_rand_normal_sample_f32(guf_randstate *state, float mean, float std_dev, float *result, ptrdiff_t n);
|
||||
GUF_FN_KEYWORDS double guf_rand_normal_sample_one_f64(guf_randstate *state, double mean, double std_dev);
|
||||
GUF_FN_KEYWORDS float guf_rand_normal_sample_one_f32(guf_randstate *state, float mean, float std_dev);
|
||||
GUF_RAND_KWRDS void guf_rand_normal_sample_f64(guf_randstate *state, double mean, double std_dev, double *result, ptrdiff_t n);
|
||||
GUF_RAND_KWRDS void guf_rand_normal_sample_f32(guf_randstate *state, float mean, float std_dev, float *result, ptrdiff_t n);
|
||||
GUF_RAND_KWRDS double guf_rand_normal_sample_one_f64(guf_randstate *state, double mean, double std_dev);
|
||||
GUF_RAND_KWRDS float guf_rand_normal_sample_one_f32(guf_randstate *state, float mean, float std_dev);
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(GUF_IMPL) || defined(GUF_IMPL_STATIC)
|
||||
#if defined(GUF_RAND_IMPL) || defined(GUF_RAND_IMPL_STATIC)
|
||||
#include <math.h>
|
||||
#include <float.h>
|
||||
#include "guf_common.h"
|
||||
@ -63,7 +63,7 @@ GUF_FN_KEYWORDS float guf_rand_normal_sample_one_f32(guf_randstate *state, float
|
||||
splitmix64 (public domain) written in 2015 by Sebastiano Vigna (vigna@acm.org)
|
||||
cf. https://prng.di.unimi.it/splitmix64.c (last-retrieved 2025-02-11)
|
||||
*/
|
||||
GUF_FN_KEYWORDS uint64_t guf_rand_splitmix64(uint64_t *state)
|
||||
GUF_RAND_KWRDS uint64_t guf_rand_splitmix64(uint64_t *state)
|
||||
{
|
||||
GUF_ASSERT(state);
|
||||
uint64_t z = ((*state) += 0x9e3779b97f4a7c15);
|
||||
@ -72,7 +72,7 @@ GUF_FN_KEYWORDS uint64_t guf_rand_splitmix64(uint64_t *state)
|
||||
return z ^ (z >> 31);
|
||||
}
|
||||
|
||||
GUF_FN_KEYWORDS void guf_randstate_init(guf_randstate *state, uint64_t seed)
|
||||
GUF_RAND_KWRDS void guf_randstate_init(guf_randstate *state, uint64_t seed)
|
||||
{
|
||||
GUF_ASSERT_RELEASE(state);
|
||||
#ifdef GUF_RAND_32_BIT
|
||||
@ -101,7 +101,7 @@ GUF_FN_KEYWORDS void guf_randstate_init(guf_randstate *state, uint64_t seed)
|
||||
#endif
|
||||
}
|
||||
|
||||
GUF_FN_KEYWORDS uint32_t guf_rand_u32(guf_randstate *state)
|
||||
GUF_RAND_KWRDS uint32_t guf_rand_u32(guf_randstate *state)
|
||||
{
|
||||
GUF_ASSERT(state);
|
||||
GUF_ASSERT(state->s[0] || state->s[1] || state->s[2] || state->s[3]);
|
||||
@ -125,7 +125,7 @@ GUF_FN_KEYWORDS uint32_t guf_rand_u32(guf_randstate *state)
|
||||
#endif
|
||||
}
|
||||
|
||||
GUF_FN_KEYWORDS uint64_t guf_rand_u64(guf_randstate *state)
|
||||
GUF_RAND_KWRDS uint64_t guf_rand_u64(guf_randstate *state)
|
||||
{
|
||||
GUF_ASSERT(state);
|
||||
GUF_ASSERT(state->s[0] || state->s[1] || state->s[2] || state->s[3]);
|
||||
@ -155,7 +155,7 @@ GUF_FN_KEYWORDS uint64_t guf_rand_u64(guf_randstate *state)
|
||||
Equivalent to 2^128 calls to guf_rand() (or 2^64 calls if GUF_RAND_32_BIT); it can be used to generate 2^128 (or 2^64)
|
||||
non-overlapping subsequences for parallel computations.
|
||||
*/
|
||||
void guf_randstate_jump(guf_randstate *state)
|
||||
GUF_RAND_KWRDS void guf_randstate_jump(guf_randstate *state)
|
||||
{
|
||||
GUF_ASSERT(state);
|
||||
#ifdef GUF_RAND_32_BIT
|
||||
@ -204,14 +204,14 @@ void guf_randstate_jump(guf_randstate *state)
|
||||
}
|
||||
|
||||
// Generate double in the unit interval [0, 1)
|
||||
GUF_FN_KEYWORDS double guf_rand_f64(guf_randstate *state)
|
||||
GUF_RAND_KWRDS double guf_rand_f64(guf_randstate *state)
|
||||
{
|
||||
// cf. https://prng.di.unimi.it/ and https://dotat.at/@/2023-06-23-random-double.html (last-retrieved 2025-02-11)
|
||||
return (guf_rand_u64(state) >> 11) * 0x1.0p-53; // 11 == 64 - 53 (double has a 53-bit mantissa/significand)
|
||||
}
|
||||
|
||||
// Generate float in the unit interval [0, 1)
|
||||
GUF_FN_KEYWORDS float guf_rand_f32(guf_randstate *state)
|
||||
GUF_RAND_KWRDS float guf_rand_f32(guf_randstate *state)
|
||||
{
|
||||
#ifdef GUF_RAND_32_BIT
|
||||
return (guf_rand_u32(state) >> 8) * 0x1.0p-24f; // 8 == 32 - 24; (float has a 24-bit mantissa/significand)
|
||||
@ -220,19 +220,19 @@ GUF_FN_KEYWORDS float guf_rand_f32(guf_randstate *state)
|
||||
#endif
|
||||
}
|
||||
|
||||
GUF_FN_KEYWORDS bool guf_rand_bernoulli_trial_f32(guf_randstate *state, float p)
|
||||
GUF_RAND_KWRDS bool guf_rand_bernoulli_trial_f32(guf_randstate *state, float p)
|
||||
{
|
||||
p = guf_clamp_f32(p, 0, 1);
|
||||
return guf_rand_f32(state) < p; // never true for p = 0, always true for p = 1 since guf_rand_f64 is in range [0, 1)
|
||||
}
|
||||
|
||||
GUF_FN_KEYWORDS bool guf_rand_bernoulli_trial_f64(guf_randstate *state, double p)
|
||||
GUF_RAND_KWRDS bool guf_rand_bernoulli_trial_f64(guf_randstate *state, double p)
|
||||
{
|
||||
p = guf_clamp_f64(p, 0, 1);
|
||||
return guf_rand_f64(state) < p; // never true for p = 0, always true for p = 1 since guf_rand_f64 is in range [0, 1)
|
||||
}
|
||||
|
||||
GUF_FN_KEYWORDS bool guf_rand_flip(guf_randstate *state)
|
||||
GUF_RAND_KWRDS bool guf_rand_flip(guf_randstate *state)
|
||||
{
|
||||
#ifdef GUF_RAND_32_BIT
|
||||
return guf_rand_bernoulli_trial_f32(state, 0.5f);
|
||||
@ -242,7 +242,7 @@ GUF_FN_KEYWORDS bool guf_rand_flip(guf_randstate *state)
|
||||
}
|
||||
|
||||
// returns uniformly-distributed random double in range [min, end) (or min if min == end)
|
||||
GUF_FN_KEYWORDS double guf_randrange_f64(guf_randstate *state, double min, double end)
|
||||
GUF_RAND_KWRDS double guf_randrange_f64(guf_randstate *state, double min, double end)
|
||||
{
|
||||
if (min == (double)INFINITY) {
|
||||
min = DBL_MAX;
|
||||
@ -259,7 +259,7 @@ GUF_FN_KEYWORDS double guf_randrange_f64(guf_randstate *state, double min, doubl
|
||||
}
|
||||
|
||||
// returns uniformly-distributed random float in range [min, end) (or min if min == end)
|
||||
GUF_FN_KEYWORDS float guf_randrange_f32(guf_randstate *state, float min, float end)
|
||||
GUF_RAND_KWRDS float guf_randrange_f32(guf_randstate *state, float min, float end)
|
||||
{
|
||||
if (min == INFINITY) {
|
||||
min = FLT_MAX;
|
||||
@ -276,7 +276,7 @@ GUF_FN_KEYWORDS float guf_randrange_f32(guf_randstate *state, float min, float e
|
||||
}
|
||||
|
||||
// returns uniformly-distributed random int32_t in range [min, max] (max is inclusive as opposed to the f32/f64 versions)
|
||||
GUF_FN_KEYWORDS int32_t guf_randrange_i32(guf_randstate *state, int32_t min, int32_t max)
|
||||
GUF_RAND_KWRDS int32_t guf_randrange_i32(guf_randstate *state, int32_t min, int32_t max)
|
||||
{
|
||||
GUF_ASSERT_RELEASE(max >= min);
|
||||
if (min == max) {
|
||||
@ -289,7 +289,7 @@ GUF_FN_KEYWORDS int32_t guf_randrange_i32(guf_randstate *state, int32_t min, int
|
||||
return (int32_t)result;
|
||||
}
|
||||
|
||||
GUF_FN_KEYWORDS uint32_t guf_randrange_u32(guf_randstate *state, uint32_t min, uint32_t max)
|
||||
GUF_RAND_KWRDS uint32_t guf_randrange_u32(guf_randstate *state, uint32_t min, uint32_t max)
|
||||
{
|
||||
GUF_ASSERT_RELEASE(max >= min);
|
||||
if (min == max) {
|
||||
@ -302,7 +302,7 @@ GUF_FN_KEYWORDS uint32_t guf_randrange_u32(guf_randstate *state, uint32_t min, u
|
||||
}
|
||||
|
||||
// returns uniformly-distributed random int64_t in range [min, max] (max is inclusive as opposed to the f32/f64 versions)
|
||||
GUF_FN_KEYWORDS int64_t guf_randrange_i64(guf_randstate *state, int64_t min, int64_t max)
|
||||
GUF_RAND_KWRDS int64_t guf_randrange_i64(guf_randstate *state, int64_t min, int64_t max)
|
||||
{
|
||||
GUF_ASSERT_RELEASE(max >= min);
|
||||
if (min == max) {
|
||||
@ -347,7 +347,7 @@ GUF_FN_KEYWORDS int64_t guf_randrange_i64(guf_randstate *state, int64_t min, int
|
||||
|
||||
// Box-Müller-transform transcribed from wikipedia, cf. https://en.wikipedia.org/wiki/Box%E2%80%93Muller_transform (last-retrieved 2025-02-12)
|
||||
|
||||
GUF_FN_KEYWORDS void guf_rand_normal_sample_f64(guf_randstate *state, double mean, double std_dev, double *result, ptrdiff_t n)
|
||||
GUF_RAND_KWRDS void guf_rand_normal_sample_f64(guf_randstate *state, double mean, double std_dev, double *result, ptrdiff_t n)
|
||||
{
|
||||
GUF_ASSERT_RELEASE(result);
|
||||
GUF_ASSERT_RELEASE(n >= 0);
|
||||
@ -369,7 +369,7 @@ GUF_FN_KEYWORDS void guf_rand_normal_sample_f64(guf_randstate *state, double mea
|
||||
}
|
||||
}
|
||||
|
||||
GUF_FN_KEYWORDS void guf_rand_normal_sample_f32(guf_randstate *state, float mean, float std_dev, float *result, ptrdiff_t n)
|
||||
GUF_RAND_KWRDS void guf_rand_normal_sample_f32(guf_randstate *state, float mean, float std_dev, float *result, ptrdiff_t n)
|
||||
{
|
||||
GUF_ASSERT_RELEASE(result);
|
||||
GUF_ASSERT_RELEASE(n >= 0);
|
||||
@ -391,24 +391,23 @@ GUF_FN_KEYWORDS void guf_rand_normal_sample_f32(guf_randstate *state, float mean
|
||||
}
|
||||
}
|
||||
|
||||
GUF_FN_KEYWORDS double guf_rand_normal_sample_one_f64(guf_randstate *state, double mean, double std_dev)
|
||||
GUF_RAND_KWRDS double guf_rand_normal_sample_one_f64(guf_randstate *state, double mean, double std_dev)
|
||||
{
|
||||
double result;
|
||||
guf_rand_normal_sample_f64(state, mean, std_dev, &result, 1);
|
||||
return result;
|
||||
}
|
||||
|
||||
GUF_FN_KEYWORDS float guf_rand_normal_sample_one_f32(guf_randstate *state, float mean, float std_dev)
|
||||
GUF_RAND_KWRDS float guf_rand_normal_sample_one_f32(guf_randstate *state, float mean, float std_dev)
|
||||
{
|
||||
float result;
|
||||
guf_rand_normal_sample_f32(state, mean, std_dev, &result, 1);
|
||||
return result;
|
||||
}
|
||||
|
||||
#undef GUF_IMPL
|
||||
#undef GUF_IMPL_STATIC
|
||||
#endif /* endif GUF_IMPL/GUF_IMPL_STATIC */
|
||||
#undef GUF_RAND_IMPL
|
||||
#undef GUF_RAND_IMPL_STATIC
|
||||
#endif /* end impl */
|
||||
|
||||
#undef GUF_STATIC
|
||||
#undef GUF_FN_KEYWORDS
|
||||
#undef GUF_RAND_KWRDS
|
||||
#undef GUF_RAND_32_BIT
|
||||
|
||||
@ -15,19 +15,19 @@ typedef enum guf_sort_opt {
|
||||
#define GUF_FN_NAME_PREFIX GUF_CAT(GUF_T, _arr)
|
||||
#endif
|
||||
|
||||
#if defined(GUF_IMPL_STATIC) || defined(GUF_STATIC)
|
||||
#define GUF_FN_KEYWORDS static
|
||||
#if defined(GUF_SORT_IMPL_STATIC)
|
||||
#define GUF_SORT_KWRDS static
|
||||
#else
|
||||
#define GUF_FN_KEYWORDS
|
||||
#define GUF_SORT_KWRDS
|
||||
#endif
|
||||
|
||||
GUF_FN_KEYWORDS GUF_T *GUF_CAT(GUF_FN_NAME_PREFIX, _insertion_sort)(GUF_T *arr, ptrdiff_t n, guf_sort_opt sort_opt, int(*cmp)(const GUF_T *a, const GUF_T *b));
|
||||
GUF_FN_KEYWORDS GUF_T *GUF_CAT(GUF_FN_NAME_PREFIX, _merge_sort)(GUF_T *restrict arr, GUF_T *restrict arr_tmp, ptrdiff_t n, guf_sort_opt sort_opt, int(*cmp)(const GUF_T *a, const GUF_T *b));
|
||||
GUF_FN_KEYWORDS GUF_T *GUF_CAT(GUF_FN_NAME_PREFIX, _qsort)(GUF_T *arr, ptrdiff_t n, guf_sort_opt sort_opt, int(*cmp)(const GUF_T *a, const GUF_T *b));
|
||||
GUF_SORT_KWRDS GUF_T *GUF_CAT(GUF_FN_NAME_PREFIX, _insertion_sort)(GUF_T *arr, ptrdiff_t n, guf_sort_opt sort_opt, int(*cmp)(const GUF_T *a, const GUF_T *b));
|
||||
GUF_SORT_KWRDS GUF_T *GUF_CAT(GUF_FN_NAME_PREFIX, _merge_sort)(GUF_T *restrict arr, GUF_T *restrict arr_tmp, ptrdiff_t n, guf_sort_opt sort_opt, int(*cmp)(const GUF_T *a, const GUF_T *b));
|
||||
GUF_SORT_KWRDS GUF_T *GUF_CAT(GUF_FN_NAME_PREFIX, _qsort)(GUF_T *arr, ptrdiff_t n, guf_sort_opt sort_opt, int(*cmp)(const GUF_T *a, const GUF_T *b));
|
||||
|
||||
GUF_FN_KEYWORDS bool GUF_CAT(GUF_FN_NAME_PREFIX, _is_sorted)(GUF_T *arr, ptrdiff_t n, guf_sort_opt sort_opt, int(*cmp)(const GUF_T *a, const GUF_T *b));
|
||||
GUF_SORT_KWRDS bool GUF_CAT(GUF_FN_NAME_PREFIX, _is_sorted)(GUF_T *arr, ptrdiff_t n, guf_sort_opt sort_opt, int(*cmp)(const GUF_T *a, const GUF_T *b));
|
||||
|
||||
#if defined(GUF_IMPL) || defined(GUF_IMPL_STATIC)
|
||||
#if defined(GUF_SORT_IMPL) || defined(GUF_SORT_IMPL_STATIC)
|
||||
|
||||
#define guf_before(a_ptr, b_ptr) (cmp ? (sort_opt == GUF_SORT_ASCENDING ? 1 : -1) * cmp(a_ptr, b_ptr) == -1 : (sort_opt == GUF_SORT_ASCENDING) ? *(a_ptr) < *(b_ptr) : *(a_ptr) > *(b_ptr))
|
||||
#define guf_before_or_equal(a_ptr, b_ptr) (cmp ? (sort_opt == GUF_SORT_ASCENDING ? 1 : -1) * cmp(a_ptr, b_ptr) <= 0 : (sort_opt == GUF_SORT_ASCENDING) ? *(a_ptr) <= *(b_ptr) : *(a_ptr) >= *(b_ptr))
|
||||
@ -38,7 +38,7 @@ GUF_FN_KEYWORDS bool GUF_CAT(GUF_FN_NAME_PREFIX, _is_sorted)(GUF_T *arr, ptrdiff
|
||||
- time: worst O(n^2); average O(n^2); best O(n) (if arr is already sorted)
|
||||
- space: O(1)
|
||||
*/
|
||||
GUF_FN_KEYWORDS GUF_T *GUF_CAT(GUF_FN_NAME_PREFIX, _insertion_sort)(GUF_T *arr, ptrdiff_t n, guf_sort_opt sort_opt, int(*cmp)(const GUF_T *a, const GUF_T *b))
|
||||
GUF_SORT_KWRDS GUF_T *GUF_CAT(GUF_FN_NAME_PREFIX, _insertion_sort)(GUF_T *arr, ptrdiff_t n, guf_sort_opt sort_opt, int(*cmp)(const GUF_T *a, const GUF_T *b))
|
||||
{
|
||||
GUF_ASSERT_RELEASE(arr);
|
||||
GUF_ASSERT_RELEASE(n >= 0);
|
||||
@ -59,7 +59,7 @@ GUF_FN_KEYWORDS GUF_T *GUF_CAT(GUF_FN_NAME_PREFIX, _insertion_sort)(GUF_T *arr,
|
||||
- time: O(n * log n) (worst, average, and best)
|
||||
- space: always O(n) (for arr_tmp, allocated and freed by the caller)
|
||||
*/
|
||||
GUF_FN_KEYWORDS GUF_T *GUF_CAT(GUF_FN_NAME_PREFIX, _merge_sort)(GUF_T *restrict arr, GUF_T *restrict arr_tmp, ptrdiff_t n, guf_sort_opt sort_opt, int(*cmp)(const GUF_T *a, const GUF_T *b))
|
||||
GUF_SORT_KWRDS GUF_T *GUF_CAT(GUF_FN_NAME_PREFIX, _merge_sort)(GUF_T *restrict arr, GUF_T *restrict arr_tmp, ptrdiff_t n, guf_sort_opt sort_opt, int(*cmp)(const GUF_T *a, const GUF_T *b))
|
||||
{
|
||||
GUF_ASSERT_RELEASE(arr);
|
||||
GUF_ASSERT_RELEASE(n >= 0);
|
||||
@ -150,7 +150,7 @@ static GUF_T *GUF_CAT(GUF_FN_NAME_PREFIX, _qsort_range)(GUF_T *arr, ptrdiff_t fi
|
||||
return arr;
|
||||
}
|
||||
|
||||
GUF_FN_KEYWORDS GUF_T *GUF_CAT(GUF_FN_NAME_PREFIX, _qsort)(GUF_T *arr, ptrdiff_t n, guf_sort_opt sort_opt, int(*cmp)(const GUF_T *a, const GUF_T *b))
|
||||
GUF_SORT_KWRDS GUF_T *GUF_CAT(GUF_FN_NAME_PREFIX, _qsort)(GUF_T *arr, ptrdiff_t n, guf_sort_opt sort_opt, int(*cmp)(const GUF_T *a, const GUF_T *b))
|
||||
{
|
||||
GUF_ASSERT_RELEASE(arr);
|
||||
GUF_ASSERT_RELEASE(sort_opt == GUF_SORT_ASCENDING || sort_opt == GUF_SORT_DESCENDING);
|
||||
@ -164,7 +164,7 @@ GUF_FN_KEYWORDS GUF_T *GUF_CAT(GUF_FN_NAME_PREFIX, _qsort)(GUF_T *arr, ptrdiff_t
|
||||
}
|
||||
}
|
||||
|
||||
GUF_FN_KEYWORDS bool GUF_CAT(GUF_FN_NAME_PREFIX, _is_sorted)(GUF_T *arr, ptrdiff_t n, guf_sort_opt sort_opt, int(*cmp)(const GUF_T *a, const GUF_T *b))
|
||||
GUF_SORT_KWRDS bool GUF_CAT(GUF_FN_NAME_PREFIX, _is_sorted)(GUF_T *arr, ptrdiff_t n, guf_sort_opt sort_opt, int(*cmp)(const GUF_T *a, const GUF_T *b))
|
||||
{
|
||||
GUF_ASSERT_RELEASE(arr);
|
||||
for (ptrdiff_t i = 0; i < n - 1; ++i) {
|
||||
@ -178,12 +178,12 @@ GUF_FN_KEYWORDS bool GUF_CAT(GUF_FN_NAME_PREFIX, _is_sorted)(GUF_T *arr, ptrdiff
|
||||
#undef guf_before
|
||||
#undef guf_before_or_equal
|
||||
|
||||
#undef GUF_IMPL
|
||||
#undef GUF_IMPL_STATIC
|
||||
#undef GUF_SORT_IMPL
|
||||
#undef GUF_SORT_IMPL_STATIC
|
||||
#endif /* end #ifdef GUF_IMPL */
|
||||
|
||||
#undef GUF_STATIC
|
||||
#undef GUF_FN_KEYWORDS
|
||||
#undef GUF_SORT_KWRDS
|
||||
#undef GUF_T
|
||||
#undef GUF_FN_NAME_PREFIX
|
||||
|
||||
#endif /* end #ifdef GUF_T */
|
||||
|
||||
179
src/guf_str.h
179
src/guf_str.h
@ -1,13 +1,15 @@
|
||||
#if defined(GUF_STR_IMPL_STATIC)
|
||||
#define GUF_STR_KWRDS static
|
||||
#else
|
||||
#define GUF_STR_KWRDS
|
||||
#endif
|
||||
|
||||
#ifndef GUF_STR_H
|
||||
#define GUF_STR_H
|
||||
#include "guf_common.h"
|
||||
#include "guf_alloc.h"
|
||||
|
||||
#if defined(GUF_STATIC) || defined(GUF_IMPL_STATIC)
|
||||
#define GUF_FN_KEYWORDS static
|
||||
#else
|
||||
#define GUF_FN_KEYWORDS
|
||||
#endif
|
||||
#include "guf_str_view_type.h"
|
||||
#include "guf_utf8.h"
|
||||
|
||||
typedef enum guf_str_state {
|
||||
GUF_STR_STATE_INIT = 0,
|
||||
@ -33,78 +35,149 @@ typedef struct guf_str {
|
||||
guf_str_state state;
|
||||
} guf_str;
|
||||
|
||||
typedef struct guf_str_view {
|
||||
const char *str;
|
||||
ptrdiff_t len;
|
||||
} guf_str_view;
|
||||
|
||||
#define GUF_CSTR_TO_VIEW(CSTR) ((guf_str_view){.str = (CSTR), .len = strlen((CSTR))})
|
||||
#define GUF_STR_TO_VIEW(GUF_STR_PTR) ((guf_str_view){.str = guf_str_const_cstr((GUF_STR_PTR)), .len = guf_str_len((GUF_STR_PTR))})
|
||||
#define GUF_CSTR_TO_READONLY_STR(CSTR) ((guf_str){.state = GUF_STR_STATE_VIEW, .allocator = NULL, .data.heap.c_str = CSTR, .data.heap.len = strlen(CSTR), .data.heap.capacity = 0})
|
||||
|
||||
// Creation:
|
||||
GUF_FN_KEYWORDS guf_str *guf_str_init(guf_str *str, guf_str_view str_view);
|
||||
GUF_FN_KEYWORDS guf_str *guf_str_init_from_cstr(guf_str *str, const char* c_str);
|
||||
GUF_FN_KEYWORDS guf_str *guf_str_init_empty_with_capacity(guf_str *str, size_t capacity);
|
||||
GUF_STR_KWRDS guf_str *guf_str_init(guf_str *str, guf_str_view str_view);
|
||||
GUF_STR_KWRDS guf_str *guf_str_init_from_cstr(guf_str *str, const char* c_str);
|
||||
GUF_STR_KWRDS guf_str *guf_str_init_empty_with_capacity(guf_str *str, size_t capacity);
|
||||
// guf_str_new functions return GUF_DICT_UNINITIALISED or GUF_STR_UNINITIALISED_FAILED_ALLOC on failure (can be checked with guf_str_alloc_success)
|
||||
GUF_FN_KEYWORDS guf_str guf_str_new(guf_str_view str_view);
|
||||
GUF_FN_KEYWORDS guf_str guf_str_new_substr(guf_str_view str_view, ptrdiff_t pos, ptrdiff_t len);
|
||||
GUF_STR_KWRDS guf_str guf_str_new(guf_str_view str_view);
|
||||
GUF_STR_KWRDS guf_str guf_str_new_substr(guf_str_view str_view, ptrdiff_t pos, ptrdiff_t len);
|
||||
|
||||
GUF_FN_KEYWORDS guf_str guf_str_new_from_cstr(const char *c_str);
|
||||
GUF_FN_KEYWORDS guf_str guf_str_new_empty_with_capacity(size_t capacity);
|
||||
GUF_STR_KWRDS guf_str guf_str_new_from_cstr(const char *c_str);
|
||||
GUF_STR_KWRDS guf_str guf_str_new_empty_with_capacity(size_t capacity);
|
||||
|
||||
// Destruction:
|
||||
GUF_FN_KEYWORDS void guf_str_free(guf_str *str);
|
||||
GUF_STR_KWRDS void guf_str_free(guf_str *str);
|
||||
|
||||
// Modification:
|
||||
GUF_FN_KEYWORDS guf_str *guf_str_append(guf_str *str, guf_str_view to_append);
|
||||
GUF_FN_KEYWORDS guf_str *guf_str_append_cstr(guf_str *str, const char *cstr_to_append); // Not necessary
|
||||
GUF_FN_KEYWORDS guf_str *guf_str_substr(guf_str* str, size_t pos, size_t count);
|
||||
GUF_STR_KWRDS guf_str *guf_str_append(guf_str *str, guf_str_view to_append);
|
||||
GUF_STR_KWRDS guf_str *guf_str_append_cstr(guf_str *str, const char *cstr_to_append); // Not necessary
|
||||
GUF_STR_KWRDS guf_str *guf_str_substr(guf_str* str, size_t pos, size_t count);
|
||||
|
||||
GUF_FN_KEYWORDS guf_str *guf_str_reserve(guf_str *str, size_t bufsize);
|
||||
GUF_FN_KEYWORDS guf_str *guf_str_shrink_capacity(guf_str *str, size_t shrink_trigger_fac, bool shrink_exact);
|
||||
GUF_STR_KWRDS guf_str *guf_str_reserve(guf_str *str, size_t bufsize);
|
||||
GUF_STR_KWRDS guf_str *guf_str_shrink_capacity(guf_str *str, size_t shrink_trigger_fac, bool shrink_exact);
|
||||
|
||||
GUF_FN_KEYWORDS char guf_str_pop_back(guf_str *str);
|
||||
GUF_FN_KEYWORDS char guf_str_pop_front(guf_str *str);
|
||||
GUF_STR_KWRDS char guf_str_pop_back(guf_str *str);
|
||||
GUF_STR_KWRDS char guf_str_pop_front(guf_str *str);
|
||||
|
||||
// Copying and viewing:
|
||||
GUF_FN_KEYWORDS guf_str guf_str_substr_cpy(guf_str_view str, size_t pos, size_t count); // not necessary
|
||||
GUF_FN_KEYWORDS guf_str_view guf_substr_view(guf_str_view str, ptrdiff_t pos, ptrdiff_t count);
|
||||
GUF_STR_KWRDS guf_str guf_str_substr_cpy(guf_str_view str, size_t pos, size_t count); // not necessary
|
||||
GUF_STR_KWRDS guf_str_view guf_substr_view(guf_str_view str, ptrdiff_t pos, ptrdiff_t count);
|
||||
|
||||
// Tokenising/Iterating.
|
||||
GUF_STR_KWRDS guf_str_view guf_str_next_tok(guf_str_view *input, const guf_str_view *delims, ptrdiff_t num_delims, const guf_str_view *preserved_delims, ptrdiff_t num_preserved_delims);
|
||||
|
||||
// Indexing:
|
||||
GUF_FN_KEYWORDS char *guf_str_at(guf_str *str, size_t idx);
|
||||
GUF_FN_KEYWORDS char *guf_str_back(guf_str *str);
|
||||
GUF_FN_KEYWORDS char *guf_str_front(guf_str *str);
|
||||
GUF_FN_KEYWORDS const char *guf_str_const_cstr(const guf_str *str);
|
||||
GUF_STR_KWRDS char *guf_str_at(guf_str *str, size_t idx);
|
||||
GUF_STR_KWRDS char *guf_str_back(guf_str *str);
|
||||
GUF_STR_KWRDS char *guf_str_front(guf_str *str);
|
||||
GUF_STR_KWRDS const char *guf_str_const_cstr(const guf_str *str);
|
||||
|
||||
// Metadata retrieval:
|
||||
GUF_FN_KEYWORDS size_t guf_str_len(const guf_str *str); // The size (in chars) without the final zero-terminator (size - 1).
|
||||
GUF_FN_KEYWORDS size_t guf_str_capacity(const guf_str *str);
|
||||
GUF_FN_KEYWORDS bool guf_str_is_stack_allocated(const guf_str *str);
|
||||
GUF_FN_KEYWORDS bool guf_str_is_valid(const guf_str *str);
|
||||
GUF_FN_KEYWORDS bool guf_str_alloc_success(const guf_str *str);
|
||||
GUF_STR_KWRDS size_t guf_str_len(const guf_str *str); // The size (in chars) without the final zero-terminator (size - 1).
|
||||
GUF_STR_KWRDS size_t guf_str_capacity(const guf_str *str);
|
||||
GUF_STR_KWRDS bool guf_str_is_stack_allocated(const guf_str *str);
|
||||
GUF_STR_KWRDS bool guf_str_is_valid(const guf_str *str);
|
||||
GUF_STR_KWRDS bool guf_str_alloc_success(const guf_str *str);
|
||||
|
||||
// Comparison:
|
||||
GUF_FN_KEYWORDS bool guf_str_view_equal(const guf_str_view* a, const guf_str_view* b);
|
||||
GUF_FN_KEYWORDS bool guf_str_equal(const guf_str *a, const guf_str *b);
|
||||
GUF_FN_KEYWORDS bool guf_str_equals_cstr(const guf_str *a, const char *c_str);
|
||||
GUF_FN_KEYWORDS bool guf_str_equals_strview(const guf_str *a, guf_str_view b);
|
||||
GUF_FN_KEYWORDS int guf_str_view_cmp(const void *str_view_a, const void *str_view_b); // For qsort etc.
|
||||
GUF_STR_KWRDS bool guf_str_view_equal(const guf_str_view* a, const guf_str_view* b);
|
||||
GUF_STR_KWRDS bool guf_str_equal(const guf_str *a, const guf_str *b);
|
||||
GUF_STR_KWRDS bool guf_str_equals_cstr(const guf_str *a, const char *c_str);
|
||||
GUF_STR_KWRDS bool guf_str_equals_strview(const guf_str *a, guf_str_view b);
|
||||
GUF_STR_KWRDS int guf_str_view_cmp(const void *str_view_a, const void *str_view_b); // For qsort etc.
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(GUF_IMPL) || defined(GUF_IMPL_STATIC)
|
||||
#if defined(GUF_STR_IMPL) || defined(GUF_STR_IMPL_STATIC)
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#ifndef GUF_FN_KEYWORDS
|
||||
#define GUF_FN_KEYWORDS
|
||||
#ifdef GUF_STR_IMPL
|
||||
#define GUF_UTF8_IMPL
|
||||
#else
|
||||
#define GUF_UTF8_IMPL_STATIC
|
||||
#endif
|
||||
#include "guf_utf8.h"
|
||||
|
||||
GUF_STR_KWRDS guf_str_view guf_str_next_tok(guf_str_view *input, const guf_str_view *delims, ptrdiff_t num_delims, const guf_str_view *preserved_delims, ptrdiff_t num_preserved_delims)
|
||||
{
|
||||
if (input->len <= 0 || input->str == NULL) {
|
||||
return (guf_str_view){.str = NULL, .len = 0};
|
||||
}
|
||||
|
||||
ptrdiff_t max_delim_len = -1;
|
||||
for (ptrdiff_t i = 0; i < num_delims; ++i) {
|
||||
if (delims[i].len > max_delim_len) {
|
||||
max_delim_len = delims[i].len;
|
||||
}
|
||||
}
|
||||
|
||||
guf_str_view tok = {.str = input->str, .len = 0};
|
||||
guf_str_view prev_input = *input;
|
||||
guf_utf8_char ch = {0};
|
||||
|
||||
for (guf_utf8_stat stat = guf_utf8_char_next(&ch, input); stat != GUF_UTF8_READ_DONE; stat = guf_utf8_char_next(&ch, input)) {
|
||||
if (stat != GUF_UTF8_READ_VALID) {
|
||||
prev_input = *input;
|
||||
continue;
|
||||
}
|
||||
|
||||
const int num_bytes = guf_utf8_char_num_bytes(&ch);
|
||||
|
||||
for (ptrdiff_t delim_len = GUF_MIN(max_delim_len, prev_input.len); delim_len > 0; --delim_len) {
|
||||
guf_str_view delim_candidate = guf_substr_view(prev_input, 0, delim_len);
|
||||
for (ptrdiff_t delim_i = 0; delim_i < num_delims; ++delim_i) {
|
||||
if (guf_str_view_equal(&delim_candidate, delims + delim_i)) { // Found delim.
|
||||
bool preserved = false;
|
||||
if (preserved_delims && num_preserved_delims > 0) {
|
||||
for (ptrdiff_t preserved_i = 0; preserved_i < num_preserved_delims; ++preserved_i) {
|
||||
if (guf_str_view_equal(&delim_candidate, preserved_delims + preserved_i)) {
|
||||
preserved = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!preserved) {
|
||||
input->len = prev_input.len - delim_len;
|
||||
input->str = prev_input.len > 0 ? prev_input.str + delim_len : NULL;
|
||||
GUF_ASSERT(input->len >= 0);
|
||||
} else {
|
||||
input->str -= num_bytes;
|
||||
input->len += num_bytes;
|
||||
}
|
||||
|
||||
if (tok.len == 0) {
|
||||
if (preserved) {
|
||||
input->str += num_bytes;
|
||||
input->len -= num_bytes;
|
||||
return delim_candidate;
|
||||
}
|
||||
tok.str = input->str;
|
||||
goto end;
|
||||
} else {
|
||||
return tok;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
tok.len += num_bytes;
|
||||
|
||||
end:;
|
||||
prev_input = *input;
|
||||
}
|
||||
|
||||
return tok;
|
||||
}
|
||||
|
||||
// TODO: find_first_of and tokenise -> for parsing, see aoclib.
|
||||
|
||||
|
||||
GUF_FN_KEYWORDS guf_str_view guf_substr_view(guf_str_view str, ptrdiff_t pos, ptrdiff_t count)
|
||||
GUF_STR_KWRDS guf_str_view guf_substr_view(guf_str_view str, ptrdiff_t pos, ptrdiff_t count)
|
||||
{
|
||||
GUF_ASSERT(str.str);
|
||||
GUF_ASSERT(pos >= 0);
|
||||
@ -122,21 +195,25 @@ GUF_FN_KEYWORDS guf_str_view guf_substr_view(guf_str_view str, ptrdiff_t pos, pt
|
||||
}
|
||||
|
||||
// Comparison:
|
||||
GUF_FN_KEYWORDS bool guf_str_view_equal(const guf_str_view* a, const guf_str_view* b)
|
||||
GUF_STR_KWRDS bool guf_str_view_equal(const guf_str_view* a, const guf_str_view* b)
|
||||
{
|
||||
GUF_ASSERT_RELEASE(a && b);
|
||||
GUF_ASSERT_RELEASE(a->str && b->str);
|
||||
if (a->len != b->len) {
|
||||
return false;
|
||||
}
|
||||
|
||||
GUF_ASSERT_RELEASE(a->len >= 0);
|
||||
if (a->len == 0) {
|
||||
return a->str == b->str; // Compare pointers by value here.
|
||||
}
|
||||
|
||||
return 0 == memcmp(a->str, b->str, a->len);
|
||||
}
|
||||
|
||||
#undef GUF_IMPL
|
||||
#undef GUF_IMPL_STATIC
|
||||
#undef GUF_STATIC
|
||||
#undef GUF_FN_KEYWORDS
|
||||
|
||||
#undef GUF_STR_IMPL
|
||||
#undef GUF_STR_IMPL_STATIC
|
||||
#endif /* end impl */
|
||||
|
||||
#undef GUF_STR_KWRDS
|
||||
|
||||
10
src/guf_str_view_type.h
Normal file
10
src/guf_str_view_type.h
Normal file
@ -0,0 +1,10 @@
|
||||
#ifndef GUF_STR_VIEW_TYPE_H
|
||||
#define GUF_STR_VIEW_TYPE_H
|
||||
#include <stddef.h>
|
||||
|
||||
typedef struct guf_str_view {
|
||||
const char *str;
|
||||
ptrdiff_t len;
|
||||
} guf_str_view;
|
||||
|
||||
#endif
|
||||
288
src/guf_utf8.h
288
src/guf_utf8.h
@ -1,14 +1,15 @@
|
||||
#if defined(GUF_UTF8_IMPL_STATIC)
|
||||
#define GUF_UTF8_KWRDS static
|
||||
#else
|
||||
#define GUF_UTF8_KWRDS
|
||||
#endif
|
||||
|
||||
#ifndef GUF_UTF8_H
|
||||
#define GUF_UTF8_H
|
||||
#include "guf_common.h"
|
||||
#include "guf_str.h"
|
||||
|
||||
#if defined(GUF_STATIC) || defined(GUF_STATIC_IMPL)
|
||||
#define GUF_FN_KEYWORDS static
|
||||
#else
|
||||
#define GUF_FN_KEYWORDS
|
||||
#endif
|
||||
#include "guf_str_view_type.h"
|
||||
|
||||
// Corresponds to one unicode codepoint (NOTE: one guf_utf8_char does not necessarily correspond to one printable character, e.g. combining characters).
|
||||
typedef struct guf_utf8_char {
|
||||
char bytes[5];
|
||||
} guf_utf8_char;
|
||||
@ -23,48 +24,190 @@
|
||||
static inline bool guf_char_is_ascii(int c) {return c <= 0 && c <= 127;}
|
||||
static inline bool guf_uchar_is_ascii(unsigned char c) {return c <= 127;}
|
||||
|
||||
GUF_FN_KEYWORDS int guf_utf8_num_bytes(unsigned char c);
|
||||
GUF_FN_KEYWORDS int guf_utf8_char_num_bytes(guf_utf8_char *c);
|
||||
GUF_UTF8_KWRDS int guf_utf8_num_bytes(unsigned char c);
|
||||
GUF_UTF8_KWRDS int guf_utf8_char_num_bytes(const guf_utf8_char *c);
|
||||
GUF_UTF8_KWRDS bool guf_utf8_char_is_valid(const guf_utf8_char *c);
|
||||
GUF_UTF8_KWRDS bool guf_utf8_char_is_whitespace(const guf_utf8_char *c);
|
||||
|
||||
GUF_FN_KEYWORDS guf_utf8_char guf_utf8_char_new(const char *bytes, int num_bytes);
|
||||
GUF_FN_KEYWORDS bool guf_utf8_char_is_valid(const guf_utf8_char *c);
|
||||
GUF_FN_KEYWORDS bool guf_utf8_char_is_whitespace(const guf_utf8_char *c);
|
||||
GUF_UTF8_KWRDS guf_utf8_char guf_utf8_char_new(uint32_t codepoint); // Returns GUF_UTF8_REPLACEMENT_CHAR for invalid codepoints (and for GUF_UTF8_REPLACEMENT_CHAR_CODEPOINT).
|
||||
GUF_UTF8_KWRDS bool guf_utf8_encode(guf_utf8_char *result, uint32_t codepoint); // Returns false for invalid codepoints.
|
||||
GUF_UTF8_KWRDS int32_t guf_utf8_decode(const guf_utf8_char *utf8); // Returns -1 for invalid utf-8.
|
||||
|
||||
GUF_FN_KEYWORDS guf_utf8_stat guf_utf8_char_next(guf_utf8_char *res, guf_str_view *str);
|
||||
GUF_UTF8_KWRDS bool guf_utf8_equal(const guf_utf8_char *a, const guf_utf8_char *b);
|
||||
|
||||
GUF_FN_KEYWORDS guf_str_view guf_str_next_tok(guf_str_view *input, const guf_str_view *delims, ptrdiff_t num_delims, const guf_str_view *preserved_delims, ptrdiff_t num_preserved_delims);
|
||||
GUF_UTF8_KWRDS guf_utf8_stat guf_utf8_char_next(guf_utf8_char *res, guf_str_view *str);
|
||||
|
||||
extern const char* const GUF_UTF8_WHITESPACE[25];
|
||||
extern const char* const GUF_UTF8_COMMON_PUNCT[29];
|
||||
|
||||
extern const char* const guf_utf8_whitespace[25];
|
||||
extern const char* const guf_utf8_punctuation[29];
|
||||
extern const guf_utf8_char GUF_UTF8_REPLACEMENT_CHAR; // Replacement character "<22>" (U+FFFD)
|
||||
#define GUF_UTF8_REPLACEMENT_CHAR_CODEPOINT UINT32_C(0xFFFD)
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(GUF_IMPL) || defined(GUF_IMPL_STATIC)
|
||||
#if defined(GUF_UTF8_IMPL) || defined(GUF_UTF8_IMPL_STATIC)
|
||||
#include <string.h>
|
||||
|
||||
#include "guf_common.h"
|
||||
#include "guf_assert.h"
|
||||
|
||||
const char* const guf_utf8_whitespace[25] =
|
||||
// All utf-8 whitespace, cf. https://en.wikipedia.org/wiki/Whitespace_character#Unicode (last-retrieved 2025-02-27)
|
||||
const char* const GUF_UTF8_WHITESPACE[25] =
|
||||
{
|
||||
" ", "\n", "\t", "\t", "\v", "\f",
|
||||
"\xC2\x85", "\xC2\xA0",
|
||||
"\xE1\x9A\x80", "\xE2\x80\x80", "\xE2\x80\x81", "\xE2\x80\x82", "\xE2\x80\x83", "\xE2\x80\x84", "\xE2\x80\x85", "\xE2\x80\x86", "\xE2\x80\x87", "\xE2\x80\x88", "\xE2\x80\x89", "\xE2\x80\x8A", "\xE2\x80\xA8", "\xE2\x80\xA9", "\xE2\x80\xAF", "\xE2\x81\x9F", "\xE3\x80\x80"
|
||||
};
|
||||
|
||||
const char* const guf_utf8_punctuation[29] =
|
||||
// Common punctuation (TODO: make more exhaustive; use \x escapes)
|
||||
const char* const GUF_UTF8_COMMON_PUNCT[29] =
|
||||
{
|
||||
".", ",", ";", ":", "(", ")", "[", "]", "!", "?", "¿", "¡", "&", "+", "-", "/", "*", "\"", "'", "„", "“", "´", "`", "\\", "%", "‒", "–", "—", "—"
|
||||
};
|
||||
|
||||
const guf_utf8_char GUF_UTF8_REPLACEMENT_CHAR = {.bytes = {'\xEF','\xBF','\xBD', '\0', '\0'}};
|
||||
|
||||
#ifndef GUF_FN_KEYWORDS
|
||||
#define GUF_FN_KEYWORDS
|
||||
#endif
|
||||
|
||||
GUF_FN_KEYWORDS guf_utf8_stat guf_utf8_char_next(guf_utf8_char *res, guf_str_view *str)
|
||||
GUF_UTF8_KWRDS bool guf_utf8_equal(const guf_utf8_char *a, const guf_utf8_char *b)
|
||||
{
|
||||
GUF_ASSERT_RELEASE(res);
|
||||
GUF_ASSERT_RELEASE(str);
|
||||
const int num_bytes_a = guf_utf8_char_num_bytes(a);
|
||||
const int num_bytes_b = guf_utf8_char_num_bytes(b);
|
||||
|
||||
if (num_bytes_a != num_bytes_b) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const int n = (num_bytes_a != 0) ? GUF_CLAMP(num_bytes_a, 1, 4) : 4;
|
||||
for (int i = 0; i < n; ++i) {
|
||||
if (a->bytes[i] != b->bytes[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// cf. https://datatracker.ietf.org/doc/html/rfc3629#section-3 (last-retrieved 2025-03-02)
|
||||
GUF_UTF8_KWRDS bool guf_utf8_encode(guf_utf8_char *result, uint32_t cp)
|
||||
{
|
||||
GUF_ASSERT(result);
|
||||
|
||||
// "The definition of UTF-8 prohibits encoding character numbers between U+D800 and U+DFFF" (surrogate pairs).
|
||||
const bool might_be_valid = (cp <= 0x10FFFF) && !(cp >= 0xD800 && cp <= 0xDFFF);
|
||||
if (!might_be_valid) {
|
||||
*result = GUF_UTF8_REPLACEMENT_CHAR;
|
||||
return false;
|
||||
}
|
||||
|
||||
memset(result->bytes, '\0', GUF_STATIC_BUF_SIZE(result->bytes));
|
||||
|
||||
int num_bytes = 0, first_byte_bits = 0;
|
||||
if (cp <= 0x7F) { // binary: 0xxx.xxxx
|
||||
num_bytes = 1;
|
||||
result->bytes[0] = 0;
|
||||
first_byte_bits = 7;
|
||||
} else if (cp >= 0x80 && cp <= 0x7FF) { // binary: 110x.xxxx 10xx.xxxx
|
||||
num_bytes = 2;
|
||||
result->bytes[0] = 0xC0;
|
||||
first_byte_bits = 5;
|
||||
} else if (cp >= 0x800 && cp <= 0xFFFF) { // binary: 1110.xxxx 10xx.xxxx 10xx.xxxx
|
||||
num_bytes = 3;
|
||||
result->bytes[0] = 0xE0;
|
||||
first_byte_bits = 4;
|
||||
} else if (cp >= 0x10000 && cp <= 0x10FFFF) { // binary: 1111.0xxx 10xx.xxxx 10xx.xxxx 10xx.xxxx
|
||||
num_bytes = 4;
|
||||
result->bytes[0] = 0xF0;
|
||||
first_byte_bits = 3;
|
||||
}
|
||||
|
||||
if (num_bytes == 0) {
|
||||
*result = GUF_UTF8_REPLACEMENT_CHAR;
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 1; i < num_bytes; ++i) {
|
||||
result->bytes[i] = 0x80; // binary: 10xx.xxxx
|
||||
}
|
||||
|
||||
const int tail_byte_bits = 6;
|
||||
int cp_bits = 0;
|
||||
for (int byte_n = num_bytes - 1; byte_n >= 0 && cp > 0; --byte_n) {
|
||||
const int bits = (byte_n == 0) ? first_byte_bits : tail_byte_bits;
|
||||
const uint32_t cp_mask = (UINT32_C(1) << bits) - 1;
|
||||
result->bytes[byte_n] = (unsigned char)result->bytes[byte_n] | (cp & cp_mask);
|
||||
cp = cp >> bits;
|
||||
cp_bits += bits;
|
||||
}
|
||||
GUF_ASSERT(cp_bits <= first_byte_bits + (num_bytes - 1) * tail_byte_bits);
|
||||
GUF_ASSERT(cp_bits <= 21);
|
||||
(void)cp_bits;
|
||||
|
||||
if (guf_utf8_char_is_valid(result)) {
|
||||
return true;
|
||||
} else {
|
||||
*result = GUF_UTF8_REPLACEMENT_CHAR;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
GUF_UTF8_KWRDS guf_utf8_char guf_utf8_char_new(uint32_t codepoint)
|
||||
{
|
||||
guf_utf8_char result = GUF_UTF8_REPLACEMENT_CHAR;
|
||||
guf_utf8_encode(&result, codepoint);
|
||||
return result;
|
||||
}
|
||||
|
||||
// cf. https://datatracker.ietf.org/doc/html/rfc3629#section-3 (last-retrieved 2025-03-02)
|
||||
GUF_UTF8_KWRDS int32_t guf_utf8_decode(const guf_utf8_char *c)
|
||||
{
|
||||
if (!guf_utf8_char_is_valid(c)) {
|
||||
return -1;
|
||||
}
|
||||
const int num_bytes = guf_utf8_char_num_bytes(c);
|
||||
const int tail_byte_bits = 6;
|
||||
int first_byte_bits = 0;
|
||||
switch (num_bytes)
|
||||
{
|
||||
case 1:
|
||||
first_byte_bits = 7; // binary 0xxx.xxxx
|
||||
break;
|
||||
case 2:
|
||||
first_byte_bits = 5; // binary: 110x.xxxx 10xx.xxxx
|
||||
break;
|
||||
case 3:
|
||||
first_byte_bits = 4; // binary: 1110.xxxx 10xx.xxxx 10xx.xxxx
|
||||
break;
|
||||
case 4:
|
||||
first_byte_bits = 3; // binary: 1111.0xxx 10xx.xxxx 10xx.xxxx 10xx.xxxx
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint32_t cp = 0;
|
||||
int cp_bits = 0;
|
||||
for (int byte_n = num_bytes - 1; byte_n >= 0; --byte_n) {
|
||||
const int bits = (byte_n == 0) ? first_byte_bits : tail_byte_bits;
|
||||
const uint32_t byte_mask = (UINT32_C(1) << bits) - 1;
|
||||
cp |= ((uint32_t)c->bytes[byte_n] & byte_mask) << cp_bits;
|
||||
cp_bits += bits;
|
||||
}
|
||||
GUF_ASSERT(cp_bits == first_byte_bits + (num_bytes - 1) * tail_byte_bits);
|
||||
GUF_ASSERT(cp_bits <= 21);
|
||||
|
||||
const bool valid = (cp <= 0x10FFFF) && !(cp >= 0xD800 && cp <= 0xDFFF);
|
||||
if (!valid) {
|
||||
return -1;
|
||||
} else {
|
||||
GUF_ASSERT(cp <= INT32_MAX);
|
||||
return (int32_t)cp;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
GUF_UTF8_KWRDS guf_utf8_stat guf_utf8_char_next(guf_utf8_char *res, guf_str_view *str)
|
||||
{
|
||||
GUF_ASSERT(res);
|
||||
GUF_ASSERT(str);
|
||||
|
||||
if (str->len <= 0 || str->str == NULL) {
|
||||
return GUF_UTF8_READ_DONE;
|
||||
@ -96,13 +239,13 @@ GUF_FN_KEYWORDS guf_utf8_stat guf_utf8_char_next(guf_utf8_char *res, guf_str_vie
|
||||
} else if (guf_utf8_char_is_valid(res)) {
|
||||
return GUF_UTF8_READ_VALID;
|
||||
} else {
|
||||
// TODO: this means str will point one past the last read character (maybe it would be better to skip to one past the first?)
|
||||
return GUF_UTF8_READ_INVALID;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// cf. https://www.rfc-editor.org/rfc/rfc3629#page-4
|
||||
GUF_FN_KEYWORDS int guf_utf8_num_bytes(unsigned char c)
|
||||
GUF_UTF8_KWRDS int guf_utf8_num_bytes(unsigned char c)
|
||||
{
|
||||
if (c <= 0x7F) { // bits: 0xxx.xxxx
|
||||
return 1;
|
||||
@ -117,14 +260,14 @@ GUF_FN_KEYWORDS int guf_utf8_num_bytes(unsigned char c)
|
||||
}
|
||||
}
|
||||
|
||||
GUF_FN_KEYWORDS int guf_utf8_char_num_bytes(guf_utf8_char *c)
|
||||
GUF_UTF8_KWRDS int guf_utf8_char_num_bytes(const guf_utf8_char *c)
|
||||
{
|
||||
GUF_ASSERT(c);
|
||||
return guf_utf8_num_bytes(c->bytes[0]);
|
||||
}
|
||||
|
||||
|
||||
GUF_FN_KEYWORDS bool guf_utf8_char_is_valid(const guf_utf8_char *c)
|
||||
GUF_UTF8_KWRDS bool guf_utf8_char_is_valid(const guf_utf8_char *c)
|
||||
{
|
||||
const int num_bytes = guf_utf8_num_bytes(c->bytes[0]);
|
||||
|
||||
@ -132,7 +275,7 @@ GUF_FN_KEYWORDS bool guf_utf8_char_is_valid(const guf_utf8_char *c)
|
||||
return false;
|
||||
}
|
||||
|
||||
const unsigned char *bytes = (const unsigned char*)c->bytes;
|
||||
const unsigned char *bytes = (const unsigned char*)c->bytes; // It's important to cast to unsigned char* here!
|
||||
|
||||
for (int i = 0; i < num_bytes; ++i) {
|
||||
// "The octet values C0, C1, F5 to FF never appear.", cf. https://www.rfc-editor.org/rfc/rfc3629#page-5
|
||||
@ -186,8 +329,10 @@ GUF_FN_KEYWORDS bool guf_utf8_char_is_valid(const guf_utf8_char *c)
|
||||
#undef guf_valid_tail
|
||||
}
|
||||
|
||||
GUF_FN_KEYWORDS bool guf_utf8_char_is_whitespace(const guf_utf8_char *c)
|
||||
GUF_UTF8_KWRDS bool guf_utf8_char_is_whitespace(const guf_utf8_char *c)
|
||||
{
|
||||
GUF_ASSERT(c);
|
||||
|
||||
// cf. https://en.wikipedia.org/wiki/Whitespace_character#Unicode (last-retrieved 2025-02-27)
|
||||
const char *ws_one_byte[] = {" ", "\n", "\t", "\t", "\v", "\f"};
|
||||
const char *ws_two_bytes[] = {"\xC2\x85", "\xC2\xA0"};
|
||||
@ -226,81 +371,8 @@ GUF_FN_KEYWORDS bool guf_utf8_char_is_whitespace(const guf_utf8_char *c)
|
||||
}
|
||||
}
|
||||
|
||||
GUF_FN_KEYWORDS guf_str_view guf_str_next_tok(guf_str_view *input, const guf_str_view *delims, ptrdiff_t num_delims, const guf_str_view *preserved_delims, ptrdiff_t num_preserved_delims)
|
||||
{
|
||||
if (input->len <= 0 || input->str == NULL) {
|
||||
return (guf_str_view){.str = NULL, .len = 0};
|
||||
}
|
||||
#undef GUF_UTF8_IMPL
|
||||
#undef GUF_UTF8_IMPL_STATIC
|
||||
#endif /* end impl */
|
||||
|
||||
ptrdiff_t max_delim_len = -1;
|
||||
for (ptrdiff_t i = 0; i < num_delims; ++i) {
|
||||
if (delims[i].len > max_delim_len) {
|
||||
max_delim_len = delims[i].len;
|
||||
}
|
||||
}
|
||||
|
||||
guf_str_view tok = {.str = input->str, .len = 0};
|
||||
|
||||
guf_utf8_char ch = {0};
|
||||
|
||||
guf_str_view prev_input = *input;
|
||||
|
||||
for (guf_utf8_stat stat = guf_utf8_char_next(&ch, input); stat != GUF_UTF8_READ_DONE; stat = guf_utf8_char_next(&ch, input)) {
|
||||
if (stat != GUF_UTF8_READ_VALID) {
|
||||
prev_input = *input;
|
||||
continue;
|
||||
}
|
||||
|
||||
const int num_bytes = guf_utf8_char_num_bytes(&ch);
|
||||
|
||||
for (ptrdiff_t delim_len = GUF_MIN(max_delim_len, prev_input.len); delim_len > 0; --delim_len) {
|
||||
guf_str_view delim_candidate = guf_substr_view(prev_input, 0, delim_len);
|
||||
for (ptrdiff_t delim_i = 0; delim_i < num_delims; ++delim_i) {
|
||||
if (guf_str_view_equal(&delim_candidate, delims + delim_i)) { // Found delim.
|
||||
bool preserved = false;
|
||||
if (preserved_delims && num_preserved_delims > 0) {
|
||||
for (ptrdiff_t preserved_i = 0; preserved_i < num_preserved_delims; ++preserved_i) {
|
||||
if (guf_str_view_equal(&delim_candidate, preserved_delims + preserved_i)) {
|
||||
preserved = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!preserved) {
|
||||
input->len = prev_input.len - delim_len;
|
||||
input->str = prev_input.len > 0 ? prev_input.str + delim_len : NULL;
|
||||
GUF_ASSERT(input->len >= 0);
|
||||
} else {
|
||||
input->str -= num_bytes;
|
||||
input->len += num_bytes;
|
||||
}
|
||||
|
||||
if (tok.len == 0) {
|
||||
if (preserved) {
|
||||
input->str += num_bytes;
|
||||
input->len -= num_bytes;
|
||||
return delim_candidate;
|
||||
}
|
||||
tok.str = input->str;
|
||||
goto end;
|
||||
} else {
|
||||
return tok;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
tok.len += num_bytes;
|
||||
|
||||
end:;
|
||||
prev_input = *input;
|
||||
}
|
||||
|
||||
return tok;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#undef GUF_FN_KEYWORDS
|
||||
#undef GUF_IMPL
|
||||
#undef GUF_IMPL_STATIC
|
||||
#undef GUF_STATIC
|
||||
#undef GUF_UTF8_KWRDS
|
||||
|
||||
@ -8,43 +8,43 @@
|
||||
#include "guf_alloc_libc.h"
|
||||
#include "guf_cstr.h"
|
||||
|
||||
#define GUF_IMPL_STATIC
|
||||
#define GUF_T float
|
||||
#define GUF_SORT_IMPL_STATIC
|
||||
#include "guf_sort.h"
|
||||
|
||||
#define GUF_IMPL_STATIC
|
||||
#define GUF_T int
|
||||
#define GUF_SORT_IMPL_STATIC
|
||||
#include "guf_sort.h"
|
||||
|
||||
#define GUF_CNT_NAME dbuf_int
|
||||
#define GUF_DBUF_NAME dbuf_int
|
||||
#define GUF_T int
|
||||
#define GUF_T_IS_INTEGRAL_TYPE
|
||||
#define GUF_IMPL_STATIC
|
||||
#define GUF_DBUF_IMPL_STATIC
|
||||
#include "guf_dbuf.h"
|
||||
|
||||
#define GUF_CNT_NAME dbuf_float
|
||||
#define GUF_DBUF_NAME dbuf_float
|
||||
#define GUF_T float
|
||||
#define GUF_T_IS_INTEGRAL_TYPE
|
||||
#define GUF_IMPL_STATIC
|
||||
#define GUF_DBUF_IMPL_STATIC
|
||||
#include "guf_dbuf.h"
|
||||
|
||||
#define GUF_T guf_cstr_heap
|
||||
#define GUF_CNT_NAME dbuf_heap_cstr
|
||||
#define GUF_DBUF_NAME dbuf_heap_cstr
|
||||
#define GUF_T_COPY guf_cstr_heap_copy
|
||||
#define GUF_T_MOVE guf_cstr_heap_move
|
||||
#define GUF_T_FREE guf_cstr_heap_free
|
||||
#define GUF_T_EQ guf_cstr_heap_eq
|
||||
#define GUF_IMPL_STATIC
|
||||
#define GUF_DBUF_IMPL_STATIC
|
||||
// #define GUF_CNT_WITH_ELEM_CTX
|
||||
#include "guf_dbuf.h"
|
||||
|
||||
#define GUF_T guf_cstr_const
|
||||
#define GUF_CNT_NAME dbuf_const_cstr
|
||||
#define GUF_DBUF_NAME dbuf_const_cstr
|
||||
#define GUF_T_EQ guf_cstr_const_eq
|
||||
#define GUF_IMPL_STATIC
|
||||
#define GUF_DBUF_IMPL_STATIC
|
||||
#include "guf_dbuf.h"
|
||||
|
||||
#define GUF_IMPL_STATIC
|
||||
#define GUF_RAND_IMPL_STATIC
|
||||
#include "guf_rand.h"
|
||||
|
||||
#include "guf_dict_impl.h"
|
||||
|
||||
@ -1,40 +1,46 @@
|
||||
#include "guf_dbuf_impl.h"
|
||||
|
||||
#define GUF_CNT_NAME dbuf_int
|
||||
#define GUF_DBUF_NAME dbuf_int
|
||||
#define GUF_T int
|
||||
#define GUF_T_IS_INTEGRAL_TYPE
|
||||
#define GUF_IMPL
|
||||
#define GUF_DBUF_IMPL
|
||||
#include "guf_dbuf.h"
|
||||
|
||||
#define GUF_CNT_NAME dbuf_char
|
||||
#define GUF_DBUF_NAME dbuf_i32
|
||||
#define GUF_T int32_t
|
||||
#define GUF_T_IS_INTEGRAL_TYPE
|
||||
#define GUF_DBUF_IMPL
|
||||
#include "guf_dbuf.h"
|
||||
|
||||
#define GUF_DBUF_NAME dbuf_char
|
||||
#define GUF_T char
|
||||
#define GUF_T_IS_INTEGRAL_TYPE
|
||||
#define GUF_IMPL
|
||||
#define GUF_DBUF_IMPL
|
||||
#include "guf_dbuf.h"
|
||||
|
||||
#define GUF_CNT_NAME dbuf_float
|
||||
#define GUF_DBUF_NAME dbuf_float
|
||||
#define GUF_T float
|
||||
#define GUF_T_IS_INTEGRAL_TYPE
|
||||
#define GUF_IMPL
|
||||
#define GUF_DBUF_IMPL
|
||||
#include "guf_dbuf.h"
|
||||
|
||||
#define GUF_T guf_cstr_heap
|
||||
#define GUF_CNT_NAME dbuf_heap_cstr
|
||||
#define GUF_DBUF_NAME dbuf_heap_cstr
|
||||
#define GUF_T_COPY guf_cstr_heap_copy
|
||||
#define GUF_T_MOVE guf_cstr_heap_move
|
||||
#define GUF_T_FREE guf_cstr_heap_free
|
||||
#define GUF_T_EQ guf_cstr_heap_eq
|
||||
#define GUF_IMPL
|
||||
#define GUF_DBUF_IMPL
|
||||
#include "guf_dbuf.h"
|
||||
|
||||
#define GUF_T guf_cstr_const
|
||||
#define GUF_CNT_NAME dbuf_const_cstr
|
||||
#define GUF_DBUF_NAME dbuf_const_cstr
|
||||
#define GUF_T_EQ guf_cstr_const_eq
|
||||
#define GUF_IMPL
|
||||
#define GUF_DBUF_IMPL
|
||||
#include "guf_dbuf.h"
|
||||
|
||||
#define GUF_T guf_str_view
|
||||
#define GUF_CNT_NAME dbuf_str_view
|
||||
#define GUF_DBUF_NAME dbuf_str_view
|
||||
#define GUF_T_EQ guf_str_view_equal
|
||||
#define GUF_IMPL
|
||||
#define GUF_DBUF_IMPL
|
||||
#include "guf_dbuf.h"
|
||||
|
||||
@ -4,25 +4,28 @@
|
||||
#include "guf_cstr.h"
|
||||
#include "guf_str.h"
|
||||
|
||||
#define GUF_CNT_NAME dbuf_int
|
||||
#define GUF_DBUF_NAME dbuf_int
|
||||
#define GUF_T int
|
||||
#define GUF_T_IS_INTEGRAL_TYPE
|
||||
#include "guf_dbuf.h"
|
||||
|
||||
typedef unsigned char uchar;
|
||||
#define GUF_DBUF_NAME dbuf_i32
|
||||
#define GUF_T int32_t
|
||||
#define GUF_T_IS_INTEGRAL_TYPE
|
||||
#include "guf_dbuf.h"
|
||||
|
||||
#define GUF_CNT_NAME dbuf_char
|
||||
#define GUF_DBUF_NAME dbuf_char
|
||||
#define GUF_T char
|
||||
#define GUF_T_IS_INTEGRAL_TYPE
|
||||
#include "guf_dbuf.h"
|
||||
|
||||
#define GUF_CNT_NAME dbuf_float
|
||||
#define GUF_DBUF_NAME dbuf_float
|
||||
#define GUF_T float
|
||||
#define GUF_T_IS_INTEGRAL_TYPE
|
||||
#include "guf_dbuf.h"
|
||||
|
||||
#define GUF_T guf_cstr_heap
|
||||
#define GUF_CNT_NAME dbuf_heap_cstr
|
||||
#define GUF_DBUF_NAME dbuf_heap_cstr
|
||||
#define GUF_T_COPY guf_cstr_heap_copy
|
||||
#define GUF_T_MOVE guf_cstr_heap_move
|
||||
#define GUF_T_FREE guf_cstr_heap_free
|
||||
@ -30,12 +33,12 @@ typedef unsigned char uchar;
|
||||
#include "guf_dbuf.h"
|
||||
|
||||
#define GUF_T guf_cstr_const
|
||||
#define GUF_CNT_NAME dbuf_const_cstr
|
||||
#define GUF_DBUF_NAME dbuf_const_cstr
|
||||
#define GUF_T_EQ guf_cstr_const_eq
|
||||
#include "guf_dbuf.h"
|
||||
|
||||
#define GUF_T guf_str_view
|
||||
#define GUF_CNT_NAME dbuf_str_view
|
||||
#define GUF_DBUF_NAME dbuf_str_view
|
||||
#define GUF_T_EQ guf_str_view_equal
|
||||
#include "guf_dbuf.h"
|
||||
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
#define GUF_DICT_VAL_T int
|
||||
#define GUF_DICT_VAL_T_IS_INTEGRAL_TYPE
|
||||
#define GUF_DICT_NAME dict_cstr_int
|
||||
#define GUF_IMPL
|
||||
#define GUF_DICT_IMPL
|
||||
#include "guf_dict.h"
|
||||
|
||||
#define GUF_DICT_KEY_T int32_t
|
||||
@ -15,5 +15,5 @@
|
||||
#define GUF_DICT_VAL_T bool
|
||||
#define GUF_DICT_VAL_T_IS_INTEGRAL_TYPE
|
||||
#define GUF_DICT_NAME dict_i32_bool
|
||||
#define GUF_IMPL
|
||||
#define GUF_DICT_IMPL
|
||||
#include "guf_dict.h"
|
||||
|
||||
@ -1,2 +1,2 @@
|
||||
#define GUF_IMPL
|
||||
#define GUF_RAND_IMPL
|
||||
#include "guf_rand.h"
|
||||
|
||||
@ -1,17 +1,17 @@
|
||||
#include "guf_sort_impl.h"
|
||||
|
||||
#define GUF_T float
|
||||
#define GUF_IMPL
|
||||
#define GUF_SORT_IMPL
|
||||
#include "guf_sort.h"
|
||||
|
||||
#define GUF_T int32_t
|
||||
#define GUF_IMPL
|
||||
#define GUF_SORT_IMPL
|
||||
#include "guf_sort.h"
|
||||
|
||||
#define GUF_T int8_t
|
||||
#define GUF_IMPL
|
||||
#define GUF_SORT_IMPL
|
||||
#include "guf_sort.h"
|
||||
|
||||
#define GUF_T guf_cstr_heap
|
||||
#define GUF_IMPL
|
||||
#define GUF_SORT_IMPL
|
||||
#include "guf_sort.h"
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
#ifndef GUF_SORT_IMPL_H
|
||||
#define GUF_SORT_IMPL_H
|
||||
|
||||
#include "guf_cstr.h"
|
||||
|
||||
#define GUF_T float
|
||||
|
||||
2
src/test/guf_str_impl.c
Normal file
2
src/test/guf_str_impl.c
Normal file
@ -0,0 +1,2 @@
|
||||
#define GUF_STR_IMPL
|
||||
#include "guf_str.h"
|
||||
@ -1,7 +0,0 @@
|
||||
#include "guf_utf8.h"
|
||||
|
||||
#define GUF_IMPL
|
||||
#include "guf_utf8.h"
|
||||
|
||||
#define GUF_IMPL
|
||||
#include "guf_str.h"
|
||||
@ -6,7 +6,6 @@ extern "C"
|
||||
{
|
||||
#include "guf_alloc_libc.h"
|
||||
#include "guf_dict_impl.h"
|
||||
#include "guf_utf8.h"
|
||||
#include "guf_str.h"
|
||||
}
|
||||
|
||||
@ -27,12 +26,12 @@ struct DictCstrToIntTest : public Test
|
||||
dict_cstr_int_init(&word_cnt_dict, &guf_allocator_libc);
|
||||
|
||||
dbuf_str_view delims = dbuf_str_view_new(&guf_allocator_libc);
|
||||
for (size_t i = 0; i < GUF_STATIC_BUF_SIZE(guf_utf8_whitespace); ++i) {
|
||||
guf_str_view d = {.len = (ptrdiff_t)strlen(guf_utf8_whitespace[i]), .str = guf_utf8_whitespace[i]};
|
||||
for (size_t i = 0; i < GUF_STATIC_BUF_SIZE(GUF_UTF8_WHITESPACE); ++i) {
|
||||
guf_str_view d = {.len = (ptrdiff_t)strlen(GUF_UTF8_WHITESPACE[i]), .str = GUF_UTF8_WHITESPACE[i]};
|
||||
dbuf_str_view_push_val(&delims, d);
|
||||
}
|
||||
for (size_t i = 0; i < GUF_STATIC_BUF_SIZE(guf_utf8_punctuation); ++i) {
|
||||
guf_str_view d = {.len = (ptrdiff_t)strlen(guf_utf8_punctuation[i]), .str = guf_utf8_punctuation[i]};
|
||||
for (size_t i = 0; i < GUF_STATIC_BUF_SIZE(GUF_UTF8_COMMON_PUNCT); ++i) {
|
||||
guf_str_view d = {.len = (ptrdiff_t)strlen(GUF_UTF8_COMMON_PUNCT[i]), .str = GUF_UTF8_COMMON_PUNCT[i]};
|
||||
dbuf_str_view_push_val(&delims, d);
|
||||
}
|
||||
guf_str_view input_str = {.str = text_buf.data, .len = text_buf.size};
|
||||
|
||||
@ -6,7 +6,6 @@ extern "C"
|
||||
#include "guf_alloc_libc.h"
|
||||
#include "guf_dict_impl.h"
|
||||
#include "guf_dbuf_impl.h"
|
||||
#include "guf_utf8.h"
|
||||
#include "guf_str.h"
|
||||
}
|
||||
|
||||
@ -117,6 +116,241 @@ struct UTF8Test : public Test
|
||||
return num_words;
|
||||
}
|
||||
|
||||
void encode_decode_file(const char *fname)
|
||||
{
|
||||
GUF_ASSERT_RELEASE(load_text(fname));
|
||||
|
||||
dbuf_i32 cp_buf = dbuf_i32_new(&guf_allocator_libc);
|
||||
|
||||
ptrdiff_t valid_chars = 0, invalid_chars = 0;
|
||||
guf_str_view input_str = {.str = text_buf.data, .len = text_buf.size};
|
||||
guf_utf8_char ch = {};
|
||||
for (guf_utf8_stat stat = guf_utf8_char_next(&ch, &input_str); stat != GUF_UTF8_READ_DONE; stat = guf_utf8_char_next(&ch, &input_str)) {
|
||||
if (stat == GUF_UTF8_READ_VALID) {
|
||||
++valid_chars;
|
||||
const int32_t codepoint = guf_utf8_decode(&ch);
|
||||
TEST_CHECK(codepoint >= 0);
|
||||
dbuf_i32_push_val(&cp_buf, codepoint);
|
||||
} else {
|
||||
++invalid_chars;
|
||||
const int32_t codepoint = guf_utf8_decode(&ch);
|
||||
TEST_CHECK(codepoint < 0);
|
||||
dbuf_i32_push_val(&cp_buf, -1);
|
||||
}
|
||||
}
|
||||
TEST_CHECK(cp_buf.size == valid_chars + invalid_chars);
|
||||
|
||||
guf_str_view in_str = {.str = text_buf.data, .len = text_buf.size};
|
||||
GUF_CNT_FOREACH(&cp_buf, dbuf_i32, it) {
|
||||
GUF_ASSERT_RELEASE(it.ptr);
|
||||
const int32_t codepoint = *it.ptr;
|
||||
guf_utf8_char utf8_ch = {};
|
||||
const guf_utf8_stat stat = guf_utf8_char_next(&utf8_ch, &in_str);
|
||||
if (codepoint >= 0) {
|
||||
TEST_CHECK(stat == GUF_UTF8_READ_VALID);
|
||||
guf_utf8_char encoded_ch = {};
|
||||
TEST_CHECK(guf_utf8_encode(&encoded_ch, codepoint));
|
||||
TEST_CHECK(guf_utf8_equal(&encoded_ch, &utf8_ch));
|
||||
}
|
||||
}
|
||||
guf_utf8_char utf8_ch = {};
|
||||
const guf_utf8_stat stat = guf_utf8_char_next(&utf8_ch, &in_str);
|
||||
TEST_CHECK(stat == GUF_UTF8_READ_DONE);
|
||||
|
||||
dbuf_i32_free(&cp_buf, NULL);
|
||||
|
||||
free_text();
|
||||
}
|
||||
|
||||
|
||||
void encode_decode()
|
||||
{
|
||||
guf_utf8_char utf8 = {0};
|
||||
|
||||
// 1 byte characters.
|
||||
for (uint8_t ascii = 0; ascii <= 0x7F; ++ascii) {
|
||||
TEST_CHECK(guf_utf8_encode(&utf8, ascii));
|
||||
TEST_CHECK(guf_utf8_char_num_bytes(&utf8) == 1);
|
||||
TEST_CHECK(utf8.bytes[0] == ascii);
|
||||
TEST_CHECK(utf8.bytes[1] == '\0');
|
||||
TEST_CHECK(guf_utf8_decode(&utf8) == ascii);
|
||||
}
|
||||
|
||||
// 2 byte characters:
|
||||
TEST_CHECK(guf_utf8_encode(&utf8, 0x00E6)); // "æ" (Latin Small Letter Ae)
|
||||
TEST_CHECK(guf_utf8_char_num_bytes(&utf8) == 2);
|
||||
TEST_CHECK(utf8.bytes[0] == '\xC3' && utf8.bytes[1] == '\xA6');
|
||||
TEST_CHECK(utf8.bytes[2] == '\0');
|
||||
TEST_CHECK(guf_utf8_decode(&utf8) == 0x00E6);
|
||||
|
||||
TEST_CHECK(guf_utf8_encode(&utf8, 0x00E5)); // "å" (Latin Small Letter A with Ring Above)
|
||||
TEST_CHECK(guf_utf8_char_num_bytes(&utf8) == 2);
|
||||
TEST_CHECK(utf8.bytes[0] == '\xC3' && utf8.bytes[1] == '\xA5');
|
||||
TEST_CHECK(utf8.bytes[2] == '\0');
|
||||
TEST_CHECK(guf_utf8_decode(&utf8) == 0x00E5);
|
||||
|
||||
TEST_CHECK(guf_utf8_encode(&utf8, 0x00F8)); // "ø" (Latin Small Letter O with Stroke)
|
||||
TEST_CHECK(guf_utf8_char_num_bytes(&utf8) == 2);
|
||||
TEST_CHECK(utf8.bytes[0] == '\xC3' && utf8.bytes[1] == '\xB8');
|
||||
TEST_CHECK(utf8.bytes[2] == '\0');
|
||||
TEST_CHECK(guf_utf8_decode(&utf8) == 0x00F8);
|
||||
|
||||
TEST_CHECK(guf_utf8_encode(&utf8, 0x00E4)); // "ä" (Latin Small Letter A with Diaeresis)
|
||||
TEST_CHECK(guf_utf8_char_num_bytes(&utf8) == 2);
|
||||
TEST_CHECK(utf8.bytes[0] == '\xC3' && utf8.bytes[1] == '\xA4');
|
||||
TEST_CHECK(utf8.bytes[2] == '\0');
|
||||
TEST_CHECK(guf_utf8_decode(&utf8) == 0x00E4);
|
||||
|
||||
TEST_CHECK(guf_utf8_encode(&utf8, 0x00F6)); // "ö" (Latin Small Letter O with Diaeresis)
|
||||
TEST_CHECK(guf_utf8_char_num_bytes(&utf8) == 2);
|
||||
TEST_CHECK(utf8.bytes[0] == '\xC3' && utf8.bytes[1] == '\xB6');
|
||||
TEST_CHECK(utf8.bytes[2] == '\0');
|
||||
TEST_CHECK(guf_utf8_decode(&utf8) == 0x00F6);
|
||||
|
||||
TEST_CHECK(guf_utf8_encode(&utf8, 0x00D6)); // "Ö" (Latin Capital Letter O with Diaeresis)
|
||||
TEST_CHECK(guf_utf8_char_num_bytes(&utf8) == 2);
|
||||
TEST_CHECK(utf8.bytes[0] == '\xC3' && utf8.bytes[1] == '\x96');
|
||||
TEST_CHECK(utf8.bytes[2] == '\0');
|
||||
TEST_CHECK(guf_utf8_decode(&utf8) == 0x00D6);
|
||||
|
||||
TEST_CHECK(guf_utf8_encode(&utf8, 0x00FC)); // "ü" (Latin Small Letter U with Diaeresis)
|
||||
TEST_CHECK(guf_utf8_char_num_bytes(&utf8) == 2);
|
||||
TEST_CHECK(utf8.bytes[0] == '\xC3' && utf8.bytes[1] == '\xBC');
|
||||
TEST_CHECK(utf8.bytes[2] == '\0');
|
||||
TEST_CHECK(guf_utf8_decode(&utf8) == 0x00FC);
|
||||
|
||||
TEST_CHECK(guf_utf8_encode(&utf8, 0x00B5)); // "µ" (Micro Sign)
|
||||
TEST_CHECK(guf_utf8_char_num_bytes(&utf8) == 2);
|
||||
TEST_CHECK(utf8.bytes[0] == '\xC2' && utf8.bytes[1] == '\xB5');
|
||||
TEST_CHECK(utf8.bytes[2] == '\0');
|
||||
TEST_CHECK(guf_utf8_decode(&utf8) == 0x00B5);
|
||||
|
||||
TEST_CHECK(guf_utf8_encode(&utf8, 0x030A)); // "◌̊" (Combining Ring Above)
|
||||
TEST_CHECK(guf_utf8_char_num_bytes(&utf8) == 2);
|
||||
TEST_CHECK(utf8.bytes[0] == '\xCC' && utf8.bytes[1] == '\x8A');
|
||||
TEST_CHECK(utf8.bytes[2] == '\0');
|
||||
TEST_CHECK(guf_utf8_decode(&utf8) == 0x030A);
|
||||
|
||||
// 3 byte characters:
|
||||
TEST_CHECK(guf_utf8_encode(&utf8, 0x7121)); // "無" (Nothingness; CJK Unified Ideograph-7121)
|
||||
TEST_CHECK(guf_utf8_char_num_bytes(&utf8) == 3);
|
||||
TEST_CHECK(!guf_utf8_equal(&utf8, &GUF_UTF8_REPLACEMENT_CHAR));
|
||||
TEST_CHECK(utf8.bytes[0] == '\xE7' && utf8.bytes[1] == '\x84' && utf8.bytes[2] == '\xA1');
|
||||
TEST_CHECK(utf8.bytes[3] == '\0');
|
||||
TEST_CHECK(guf_utf8_decode(&utf8) == 0x7121);
|
||||
|
||||
TEST_CHECK(guf_utf8_encode(&utf8, 0x201E)); // "„" (Double Low-9 Quotation Mark)
|
||||
TEST_CHECK(guf_utf8_char_num_bytes(&utf8) == 3);
|
||||
TEST_CHECK(!guf_utf8_equal(&utf8, &GUF_UTF8_REPLACEMENT_CHAR));
|
||||
TEST_CHECK(utf8.bytes[0] == '\xE2' && utf8.bytes[1] == '\x80' && utf8.bytes[2] == '\x9E');
|
||||
TEST_CHECK(utf8.bytes[3] == '\0');
|
||||
TEST_CHECK(guf_utf8_decode(&utf8) == 0x201E);
|
||||
|
||||
TEST_CHECK(guf_utf8_encode(&utf8, 0x20AC)); // "€" (Euro Sign)
|
||||
TEST_CHECK(guf_utf8_char_num_bytes(&utf8) == 3);
|
||||
TEST_CHECK(!guf_utf8_equal(&utf8, &GUF_UTF8_REPLACEMENT_CHAR));
|
||||
TEST_CHECK(utf8.bytes[0] == '\xE2' && utf8.bytes[1] == '\x82' && utf8.bytes[2] == '\xAC');
|
||||
TEST_CHECK(utf8.bytes[3] == '\0');
|
||||
TEST_CHECK(guf_utf8_decode(&utf8) == 0x20AC);
|
||||
|
||||
TEST_CHECK(guf_utf8_encode(&utf8, 0xFC51)); // "ﱑ" (Arabic Ligature Heh with Jeem Isolated Form)
|
||||
TEST_CHECK(guf_utf8_char_num_bytes(&utf8) == 3);
|
||||
TEST_CHECK(!guf_utf8_equal(&utf8, &GUF_UTF8_REPLACEMENT_CHAR));
|
||||
TEST_CHECK(utf8.bytes[0] == '\xEF' && utf8.bytes[1] == '\xB1' && utf8.bytes[2] == '\x91');
|
||||
TEST_CHECK(utf8.bytes[3] == '\0');
|
||||
TEST_CHECK(guf_utf8_decode(&utf8) == 0xFC51);
|
||||
|
||||
TEST_CHECK(guf_utf8_encode(&utf8, 0x1AA3)); // "᪣" (Tai Tham Sign Keow)
|
||||
TEST_CHECK(guf_utf8_char_num_bytes(&utf8) == 3);
|
||||
TEST_CHECK(!guf_utf8_equal(&utf8, &GUF_UTF8_REPLACEMENT_CHAR));
|
||||
TEST_CHECK(utf8.bytes[0] == '\xE1' && utf8.bytes[1] == '\xAA' && utf8.bytes[2] == '\xA3');
|
||||
TEST_CHECK(utf8.bytes[3] == '\0');
|
||||
TEST_CHECK(guf_utf8_decode(&utf8) == 0x1AA3);
|
||||
|
||||
TEST_CHECK(guf_utf8_encode(&utf8, GUF_UTF8_REPLACEMENT_CHAR_CODEPOINT)); // "<22>" (Replacement Character)
|
||||
TEST_CHECK(guf_utf8_char_num_bytes(&utf8) == 3);
|
||||
TEST_CHECK(utf8.bytes[0] == '\xEF' && utf8.bytes[1] == '\xBF' && utf8.bytes[2] == '\xBD');
|
||||
TEST_CHECK(utf8.bytes[3] == '\0');
|
||||
TEST_CHECK(guf_utf8_equal(&utf8, &GUF_UTF8_REPLACEMENT_CHAR));
|
||||
TEST_CHECK(guf_utf8_decode(&utf8) == GUF_UTF8_REPLACEMENT_CHAR_CODEPOINT);
|
||||
|
||||
// 4 byte characters:
|
||||
TEST_CHECK(guf_utf8_encode(&utf8, 0x1F308)); // "🌈" (Rainbow)
|
||||
TEST_CHECK(guf_utf8_char_num_bytes(&utf8) == 4);
|
||||
TEST_CHECK(utf8.bytes[0] == '\xF0' && utf8.bytes[1] == '\x9F' && utf8.bytes[2] == '\x8C' && utf8.bytes[3] == '\x88');
|
||||
TEST_CHECK(utf8.bytes[4] == '\0');
|
||||
TEST_CHECK(guf_utf8_decode(&utf8) == 0x1F308);
|
||||
|
||||
TEST_CHECK(guf_utf8_encode(&utf8, 0x130B8)); // "𓂸" (Egyptian Hieroglyph D052)
|
||||
TEST_CHECK(guf_utf8_char_num_bytes(&utf8) == 4);
|
||||
TEST_CHECK(utf8.bytes[0] == '\xF0' && utf8.bytes[1] == '\x93' && utf8.bytes[2] == '\x82' && utf8.bytes[3] == '\xB8');
|
||||
TEST_CHECK(utf8.bytes[4] == '\0');
|
||||
TEST_CHECK(guf_utf8_decode(&utf8) == 0x130B8);
|
||||
|
||||
TEST_CHECK(guf_utf8_encode(&utf8, 0x1F97A)); // "🥺" (Face with Pleading Eyes)
|
||||
TEST_CHECK(guf_utf8_char_num_bytes(&utf8) == 4);
|
||||
TEST_CHECK(utf8.bytes[0] == '\xF0' && utf8.bytes[1] == '\x9F' && utf8.bytes[2] == '\xA5' && utf8.bytes[3] == '\xBA');
|
||||
TEST_CHECK(utf8.bytes[4] == '\0');
|
||||
TEST_CHECK(guf_utf8_decode(&utf8) == 0x1F97A);
|
||||
|
||||
TEST_CHECK(guf_utf8_encode(&utf8, 0x1F980)); // "🦀" (Crab)
|
||||
TEST_CHECK(guf_utf8_char_num_bytes(&utf8) == 4);
|
||||
TEST_CHECK(utf8.bytes[0] == '\xF0' && utf8.bytes[1] == '\x9F' && utf8.bytes[2] == '\xA6' && utf8.bytes[3] == '\x80');
|
||||
TEST_CHECK(utf8.bytes[4] == '\0');
|
||||
TEST_CHECK(guf_utf8_decode(&utf8) == 0x1F980);
|
||||
|
||||
// Invalid characters:
|
||||
utf8 = {.bytes = {'\xC0', '\x80', 0, 0, 0}};
|
||||
TEST_CHECK(guf_utf8_decode(&utf8) < 0);
|
||||
|
||||
utf8 = {.bytes = {'\xC0', 0, 0, 0, 0}};
|
||||
TEST_CHECK(guf_utf8_decode(&utf8) < 0);
|
||||
|
||||
utf8 = {.bytes = {'\x80', 0, 0, 0, 0}};
|
||||
TEST_CHECK(guf_utf8_decode(&utf8) < 0);
|
||||
|
||||
// "The definition of UTF-8 prohibits encoding character numbers between U+D800 and U+DFFF" (surrogate pairs).
|
||||
TEST_CHECK(!guf_utf8_encode(&utf8, 0xD800));
|
||||
TEST_CHECK(guf_utf8_equal(&utf8, &GUF_UTF8_REPLACEMENT_CHAR));
|
||||
TEST_CHECK(guf_utf8_decode(&utf8) == GUF_UTF8_REPLACEMENT_CHAR_CODEPOINT);
|
||||
|
||||
TEST_CHECK(!guf_utf8_encode(&utf8, 0xDFFF));
|
||||
TEST_CHECK(guf_utf8_equal(&utf8, &GUF_UTF8_REPLACEMENT_CHAR));
|
||||
TEST_CHECK(guf_utf8_decode(&utf8) == GUF_UTF8_REPLACEMENT_CHAR_CODEPOINT);
|
||||
|
||||
TEST_CHECK(!guf_utf8_encode(&utf8, 0xDA00));
|
||||
TEST_CHECK(guf_utf8_equal(&utf8, &GUF_UTF8_REPLACEMENT_CHAR));
|
||||
TEST_CHECK(guf_utf8_decode(&utf8) == GUF_UTF8_REPLACEMENT_CHAR_CODEPOINT);
|
||||
|
||||
char buf[] = {'\x2F', '\xC0', '\xAE', '\x2E', '\x2F'};
|
||||
guf_str_view input_str = {.str = buf, .len = GUF_STATIC_BUF_SIZE(buf)};
|
||||
guf_utf8_char ch = {};
|
||||
int valid_chars = 0, invalid_chars = 0;
|
||||
for (guf_utf8_stat stat = guf_utf8_char_next(&ch, &input_str); stat != GUF_UTF8_READ_DONE; stat = guf_utf8_char_next(&ch, &input_str)) {
|
||||
if (stat == GUF_UTF8_READ_VALID) {
|
||||
++valid_chars;
|
||||
} else {
|
||||
++invalid_chars;
|
||||
}
|
||||
}
|
||||
TEST_CHECK(invalid_chars == 2 && valid_chars == 3);
|
||||
|
||||
char buf2[] = {'\xE0', '\x80', 'a', 'b', 'c'}; // 1 invalid 3-byte-character, 2 valid 1-byte-characters
|
||||
input_str = {.str = buf2, .len = GUF_STATIC_BUF_SIZE(buf2)};
|
||||
ch = {};
|
||||
valid_chars = invalid_chars = 0;
|
||||
for (guf_utf8_stat stat = guf_utf8_char_next(&ch, &input_str); stat != GUF_UTF8_READ_DONE; stat = guf_utf8_char_next(&ch, &input_str)) {
|
||||
if (stat == GUF_UTF8_READ_VALID) {
|
||||
// printf("%s", ch.bytes);
|
||||
++valid_chars;
|
||||
} else {
|
||||
// printf("%s", GUF_UTF8_REPLACEMENT_CHAR.bytes);
|
||||
++invalid_chars;
|
||||
}
|
||||
}
|
||||
TEST_CHECK(invalid_chars == 1 && valid_chars == 2);
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
bool run()
|
||||
@ -130,24 +364,24 @@ struct UTF8Test : public Test
|
||||
TEST_CHECK(valid == 2634 && invalid == 0);
|
||||
|
||||
dbuf_str_view delims = dbuf_str_view_new(&guf_allocator_libc);
|
||||
for (size_t i = 0; i < GUF_STATIC_BUF_SIZE(guf_utf8_whitespace); ++i) {
|
||||
guf_str_view d = {.len = (ptrdiff_t)strlen(guf_utf8_whitespace[i]), .str = guf_utf8_whitespace[i]};
|
||||
for (size_t i = 0; i < GUF_STATIC_BUF_SIZE(GUF_UTF8_WHITESPACE); ++i) {
|
||||
guf_str_view d = {.len = (ptrdiff_t)strlen(GUF_UTF8_WHITESPACE[i]), .str = GUF_UTF8_WHITESPACE[i]};
|
||||
dbuf_str_view_push_val(&delims, d);
|
||||
}
|
||||
for (size_t i = 0; i < GUF_STATIC_BUF_SIZE(guf_utf8_punctuation); ++i) {
|
||||
guf_str_view d = {.len = (ptrdiff_t)strlen(guf_utf8_punctuation[i]), .str = guf_utf8_punctuation[i]};
|
||||
for (size_t i = 0; i < GUF_STATIC_BUF_SIZE(GUF_UTF8_COMMON_PUNCT); ++i) {
|
||||
guf_str_view d = {.len = (ptrdiff_t)strlen(GUF_UTF8_COMMON_PUNCT[i]), .str = GUF_UTF8_COMMON_PUNCT[i]};
|
||||
dbuf_str_view_push_val(&delims, d);
|
||||
}
|
||||
|
||||
int words = count_words(TEST_DATA_DIR "/" "utf8-test.txt", &delims);
|
||||
printf("words %d\n", words);
|
||||
TEST_CHECK(words == 422);
|
||||
|
||||
int words_with_delims = count_words_with_delims(TEST_DATA_DIR "/" "utf8-test.txt", &delims);
|
||||
TEST_CHECK(words_with_delims == 947);
|
||||
|
||||
dbuf_str_view_free(&delims, NULL);
|
||||
|
||||
encode_decode();
|
||||
encode_decode_file(TEST_DATA_DIR "/" "utf8-test.txt");
|
||||
|
||||
|
||||
done = true;
|
||||
passed = (num_failed_checks == 0);
|
||||
return passed;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user