This commit is contained in:
jun 2025-03-02 18:21:25 +01:00
parent 8b02eff3b7
commit cd1c1cd5db
24 changed files with 1010 additions and 612 deletions

View File

@ -21,7 +21,7 @@ endif ()
add_executable(libguf_example src/test/example.c src/test/guf_dict_impl.c) add_executable(libguf_example src/test/example.c src/test/guf_dict_impl.c)
target_include_directories(libguf_example PRIVATE src src/test) 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) target_include_directories(libguf_test PRIVATE src src/test)
if (NOT DEFINED MSVC) if (NOT DEFINED MSVC)

View File

@ -6,6 +6,8 @@
#include <inttypes.h> #include <inttypes.h>
#include <stddef.h> #include <stddef.h>
// #define GUF_HASH_32_BIT
/* /*
// Copy- and move constructors: // Copy- and move constructors:
GUF_T_COPY: GUF_T *(*copy)(GUF_T *dst, const GUF_T *src, void *ctx); 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_MIN(X, Y) ((X) < (Y) ? (X) : (Y))
#define GUF_MAX(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. // 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 #define GUF_TOK_CAT(a, b) a##b

View File

@ -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 #ifndef GUF_DBUF_H
#define GUF_DBUF_H #define GUF_DBUF_H
#include "guf_common.h" #include "guf_common.h"
@ -9,7 +15,7 @@
/* /*
Template parameters: Template parameters:
- GUF_T: The value type stored in the container. - 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_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) - 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" #error "Undefined container template GUF_T"
#endif #endif
#ifndef GUF_CNT_NAME #ifndef GUF_DBUF_NAME
#define GUF_CNT_NAME GUF_CAT(dbuf_, GUF_T) #define GUF_DBUF_NAME GUF_CAT(dbuf_, GUF_T)
#endif #endif
#ifdef GUF_ONLY_TYPES #ifdef GUF_DBUF_ONLY_TYPES
#undef GUF_ONLY_TYPES typedef struct GUF_DBUF_NAME {
typedef struct GUF_CNT_NAME {
GUF_T *data; GUF_T *data;
ptrdiff_t size, capacity; ptrdiff_t size, capacity;
guf_allocator *allocator; guf_allocator *allocator;
#ifdef GUF_CNT_WITH_ELEM_CTX #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 void *elem_ctx; // NULL by default; is passed as the ctx argument to GUF_T_COPY, GUF_T_MOVE and GUF_T_FREE
#endif #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 *ptr;
GUF_T *base; // Not NULL For reverse iterators (unless dbuf->size == 0, then ptr and base are NULL for both iterator types) 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 #else
// Used for the first growth if dbuf->capacity is zero. // 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" #error "Integral types do not need COPY, MOVE, FREE or EQ functions"
#endif #endif
#if defined(GUF_STATIC) || defined(GUF_IMPL_STATIC) #if !defined(GUF_DBUF_IMPL) && !defined(GUF_DBUF_WITHOUT_TYPES)
#define GUF_FN_KEYWORDS static
#else
#define GUF_FN_KEYWORDS
#endif
#if !defined(GUF_IMPL) typedef struct GUF_DBUF_NAME {
typedef struct GUF_CNT_NAME {
GUF_T *data; GUF_T *data;
ptrdiff_t size, capacity; ptrdiff_t size, capacity;
guf_allocator *allocator; guf_allocator *allocator;
#ifdef GUF_CNT_WITH_ELEM_CTX #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 void *elem_ctx; // NULL by default; is passed as the ctx argument to GUF_T_COPY, GUF_T_MOVE and GUF_T_FREE
#endif #endif
} GUF_CNT_NAME; } GUF_DBUF_NAME;
/* /*
- Regular iterator: base is always NULL - 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 - 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 - 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 *ptr;
GUF_T *base; // Not NULL For reverse iterators (unless dbuf->size == 0, then ptr and base are NULL for both iterator types) 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 #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_DBUF_KWRDS void GUF_CAT(GUF_DBUF_NAME, _try_reserve)(GUF_DBUF_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, _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_DBUF_KWRDS void GUF_CAT(GUF_DBUF_NAME, _try_init)(GUF_DBUF_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_DBUF_KWRDS void GUF_CAT(GUF_DBUF_NAME, _init)(GUF_DBUF_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_DBUF_KWRDS GUF_DBUF_NAME GUF_CAT(GUF_DBUF_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_DBUF_KWRDS GUF_DBUF_NAME GUF_CAT(GUF_DBUF_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 GUF_DBUF_NAME GUF_CAT(GUF_DBUF_NAME, _new_with_capacity)(ptrdiff_t capacity, guf_allocator *allocator);
#ifdef GUF_CNT_WITH_ELEM_CTX #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 #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_DBUF_KWRDS void GUF_CAT(GUF_DBUF_NAME, _free)(GUF_DBUF_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_DBUF_KWRDS GUF_DBUF_NAME *GUF_CAT(GUF_DBUF_NAME, _copy)(GUF_DBUF_NAME *dst, const GUF_DBUF_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 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_DBUF_KWRDS ptrdiff_t GUF_CAT(GUF_DBUF_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_DBUF_KWRDS void GUF_CAT(GUF_DBUF_NAME, _try_grow_if_full)(GUF_DBUF_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 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_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_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);
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);
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);
#ifdef GUF_T_COPY #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);
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);
#endif #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_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);
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);
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);
#ifdef GUF_T_COPY #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);
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);
#endif #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_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_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_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_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_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);
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_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);
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_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);
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_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);
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_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_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_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_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);
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_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_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_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);
#if defined(GUF_T_IS_INTEGRAL_TYPE) || defined(GUF_T_EQ) #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_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);
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_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);
#endif #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) { if (!dbuf) {
return false; 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; 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); GUF_ASSERT_RELEASE(min_capacity >= 0);
if (min_capacity <= dbuf->capacity || 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_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(dbuf);
GUF_ASSERT_RELEASE(capacity >= 0); 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")); 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; return;
} }
@ -252,44 +251,44 @@ GUF_FN_KEYWORDS void GUF_CAT(GUF_CNT_NAME, _try_init)(GUF_CNT_NAME *dbuf, ptrdif
dbuf->data = NULL; dbuf->data = NULL;
guf_err_set_if_not_null(err, GUF_ERR_NONE); guf_err_set_if_not_null(err, GUF_ERR_NONE);
} else { } 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_DBUF_NAME dbuf = {0};
GUF_CAT(GUF_CNT_NAME, _init)(&dbuf, 0, allocator); GUF_CAT(GUF_DBUF_NAME, _init)(&dbuf, 0, allocator);
GUF_ASSERT(dbuf.size == 0 && dbuf.capacity == 0); GUF_ASSERT(dbuf.size == 0 && dbuf.capacity == 0);
return dbuf; 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) { 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); guf_err_set_if_not_null(err, GUF_ERR_NONE);
return dbuf; 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 #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 #ifdef GUF_CNT_WITH_ELEM_CTX
dbuf->elem_ctx = elem_ctx; dbuf->elem_ctx = elem_ctx;
#else #else
@ -299,7 +298,7 @@ GUF_FN_KEYWORDS void GUF_CAT(GUF_CNT_NAME, _set_elem_ctx)(GUF_CNT_NAME *dbuf, vo
} }
#endif #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 #ifdef GUF_CNT_WITH_ELEM_CTX
return dbuf->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 #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; (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) { if (dbuf->capacity == 0) {
GUF_ASSERT_RELEASE(!dbuf->data); GUF_ASSERT_RELEASE(!dbuf->data);
GUF_ASSERT_RELEASE(dbuf->size == 0); 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 #ifdef GUF_T_FREE
for (ptrdiff_t idx = 0; idx < dbuf->size; ++idx) { 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 #endif
@ -335,10 +334,10 @@ GUF_FN_KEYWORDS void GUF_CAT(GUF_CNT_NAME, _free)(GUF_CNT_NAME *dbuf, void *ctx)
#endif #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; (void)ctx;
if (!dst || !src || GUF_CAT(GUF_CNT_NAME, _valid)(src)) { if (!dst || !src || GUF_CAT(GUF_DBUF_NAME, _valid)(src)) {
return NULL; 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) { for (ptrdiff_t i = 0; i < src->size; ++i) {
#ifdef GUF_T_COPY #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) { if (!cpy_success) {
dst->size = i; dst->size = i;
return NULL; 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; (void)ctx;
if (!dst || !src) { 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; 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); GUF_ASSERT_RELEASE(old_cap >= 0);
size_t new_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); GUF_ASSERT_RELEASE(dbuf->capacity >= 0 && dbuf->size >= 0);
if (dbuf->size == dbuf->capacity) { 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) { if (err && *err != GUF_ERR_NONE) {
return; return;
} }
GUF_ASSERT(next_cap > 0); 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) { if (err && *err != GUF_ERR_NONE) {
return; 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); 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) { if (cpy_opt == GUF_CPY_DEEP) {
#ifdef GUF_T_COPY #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) { if (idx < 0 || idx > dbuf->size) {
guf_err_set_or_panic(err, GUF_ERR_IDX_RANGE, GUF_ERR_MSG("in function dbuf_try_insert")); guf_err_set_or_panic(err, GUF_ERR_IDX_RANGE, GUF_ERR_MSG("in function dbuf_try_insert"));
return NULL; 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) { if (err && *err != GUF_ERR_NONE) {
return NULL; 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; GUF_T *dst = dbuf->data + idx;
if (!GUF_CAT(GUF_CNT_NAME, _copy_opt_available)(cpy_opt)) { 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_CNT_NAME, _copy_opt_available)) ": cpy_opt unavailable")); 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; return NULL;
} else if (cpy_opt == GUF_CPY_DEEP) { } else if (cpy_opt == GUF_CPY_DEEP) {
#ifdef GUF_T_COPY #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 #else
GUF_ASSERT_RELEASE(false); GUF_ASSERT_RELEASE(false);
#endif #endif
} else if (cpy_opt == GUF_CPY_MOVE) { } else if (cpy_opt == GUF_CPY_MOVE) {
#ifdef GUF_T_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 #else
GUF_ASSERT_RELEASE(false); GUF_ASSERT_RELEASE(false);
#endif #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 #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 #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)); GUF_ASSERT(GUF_CAT(GUF_DBUF_NAME, _valid)(dbuf));
return GUF_CAT(GUF_CNT_NAME, _try_insert)(dbuf, elem, dbuf->size, cpy_opt, err); 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 #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 #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) { 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")); 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 #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 #endif
for (ptrdiff_t free_idx = idx; free_idx < dbuf->size - 1; ++free_idx) { // Make space by moving elements to the left if necessary. 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; 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) { 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")); 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 #ifdef GUF_T_FREE
GUF_T *popped = dbuf->data + --dbuf->size; 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 #else
--dbuf->size; --dbuf->size;
#endif #endif
@ -646,14 +645,14 @@ GUF_FN_KEYWORDS bool GUF_CAT(GUF_CNT_NAME, _try_pop)(GUF_CNT_NAME *dbuf, guf_err
return true; 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) { 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")); 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 popped_val;
GUF_T *dst = &popped_val; GUF_T *dst = &popped_val;
#if defined(GUF_T_MOVE) #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 #else
*dst = *popped; *dst = *popped;
memset(popped, 0, sizeof(GUF_T)); 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) { 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")); 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; 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) { if (dbuf->size == 0) {
guf_err_set_or_panic(err, GUF_ERR_IDX_RANGE, GUF_ERR_MSG("in function dbuf_front: dbuf is empty")); 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; 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) { 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")); 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); 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; const ptrdiff_t new_capacity = dbuf->size;
if (new_capacity == dbuf->capacity || (!dbuf->data && !dbuf->capacity)) { if (new_capacity == dbuf->capacity || (!dbuf->data && !dbuf->capacity)) {
guf_err_set_if_not_null(err, GUF_ERR_NONE); 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 */ /* 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, .ptr = dbuf->data && dbuf->size ? dbuf->data : NULL,
.base = 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)); 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 + dbuf->size : NULL, .ptr = dbuf->data && dbuf->size ? dbuf->data + dbuf->size : NULL,
.base = 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)); GUF_ASSERT_RELEASE(GUF_CAT(GUF_DBUF_NAME, _valid)(dbuf));
return (GUF_CAT(GUF_CNT_NAME, _iter)) { return (GUF_CAT(GUF_DBUF_NAME, _iter)) {
.base = dbuf->data && dbuf->size ? dbuf->data + dbuf->size : NULL, .base = dbuf->data && dbuf->size ? dbuf->data + dbuf->size : NULL,
.ptr = dbuf->data && dbuf->size ? dbuf->data + (dbuf->size - 1) : 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)); GUF_ASSERT_RELEASE(GUF_CAT(GUF_DBUF_NAME, _valid)(dbuf));
return (GUF_CAT(GUF_CNT_NAME, _iter)) { return (GUF_CAT(GUF_DBUF_NAME, _iter)) {
.base = dbuf->data && dbuf->size ? dbuf->data : NULL, .base = dbuf->data && dbuf->size ? dbuf->data : NULL,
.ptr = 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 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; 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; it.base = NULL;
if (!dbuf->data || !dbuf->size) { 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; 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) { if (!dbuf->data || !dbuf->size) {
it.base = NULL; 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; 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) { if ((!it.ptr && !it.base) || !dbuf->data || !dbuf->size) {
return GUF_CNT_NPOS; return GUF_CNT_NPOS;
} }
const bool is_reverse_it = it.base != NULL; 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) { if (it.ptr == end_it.ptr) {
return is_reverse_it ? -1 : dbuf->size; 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)) { if (!dbuf->size || !dbuf->data || (!it.base && !it.ptr)) {
it.ptr = NULL; 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) #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); GUF_ASSERT_RELEASE(needle);
const bool is_reverse_it = begin.base != NULL; 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. 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)) { if (!dbuf->data || !dbuf->size || (!begin.ptr && !begin.base) || (!end.ptr && !end.base)) {
return dbuf_end_it; 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; 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 #ifdef GUF_T_EQ
if (GUF_T_EQ(it.ptr, needle)) { if (GUF_T_EQ(it.ptr, needle)) {
return it; 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; 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_DBUF_NAME, _iter) beg = GUF_CAT(GUF_DBUF_NAME, _begin)(dbuf);
GUF_CAT(GUF_CNT_NAME, _iter) end = GUF_CAT(GUF_CNT_NAME, _end)(dbuf); GUF_CAT(GUF_DBUF_NAME, _iter) end = GUF_CAT(GUF_DBUF_NAME, _end)(dbuf);
return GUF_CAT(GUF_CNT_NAME, _find)(dbuf, beg, end, needle).ptr != end.ptr; 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 #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); GUF_ASSERT_RELEASE(predicate);
const bool is_reverse_it = begin.base != NULL; 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. 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)) { if (!dbuf->data || !dbuf->size || (!begin.ptr && !begin.base) || (!end.ptr && !end.base)) {
return dbuf_end_it; 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; 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)) { if (predicate(it.ptr)) {
return it; 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 #ifdef GUF_IMPL */
#endif /* end GUF_ONLY_TYPES */ #endif /* end GUF_DBUF_ONLY_TYPES */
#undef GUF_DBUF_INITIAL_CAP #undef GUF_DBUF_INITIAL_CAP
#undef GUF_DBUF_USE_GROWTH_FAC_ONE_POINT_FIVE #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_CNT_WITH_ELEM_CTX
#undef GUF_T #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_EQ
#undef GUF_T_IS_INTEGRAL_TYPE #undef GUF_T_IS_INTEGRAL_TYPE
#undef GUF_FN_KEYWORDS #undef GUF_DBUF_KWRDS
#undef GUF_IMPL #undef GUF_DBUF_IMPL
#undef GUF_IMPL_STATIC #undef GUF_DBUF_IMPL_STATIC
#undef GUF_STATIC
#undef GUF_DBUF_WITHOUT_TYPES
#undef GUF_DBUF_ONLY_TYPES

View File

@ -1,28 +1,14 @@
#ifdef GUF_STATIC #if defined(GUF_DICT_IMPL_STATIC)
#define GUF_DICT_STATIC #define GUF_DICT_KWRDS 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
#else #else
#define GUF_DICT_FN_KEYWORDS #define GUF_DICT_KWRDS
#endif #endif
#ifndef GUF_DICT_H #ifndef GUF_DICT_H
#define GUF_DICT_H #define GUF_DICT_H
#include "guf_common.h" #include "guf_common.h"
#include "guf_alloc.h" #include "guf_alloc.h"
#include "guf_hash.h"
typedef struct guf_dict_kv_meta_32 { typedef struct guf_dict_kv_meta_32 {
uint32_t kv_idx; // Index into the kv_elems dbuf. 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 kv_idx; // Index into the kv_elems dbuf.
uint64_t key_hash; uint64_t key_hash;
} guf_dict_kv_meta_64; } 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 #endif
#ifndef GUF_DICT_KEY_T #ifndef GUF_DICT_KEY_T
@ -51,18 +42,23 @@
#define GUF_DICT_IS_SET #define GUF_DICT_IS_SET
#endif #endif
#ifdef GUF_DICT_32_BIT #if defined(GUF_DICT_32_BIT)
#define GUF_DICT_SIZE_T uint32_t #define GUF_DICT_SIZE_T uint32_t
#define GUF_DICT_KV_META_T guf_dict_kv_meta_32 #define GUF_DICT_KV_META_T guf_dict_kv_meta_32
#define GUF_DICT_KV_IDX_NULL UINT32_MAX #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_SIZE_T uint64_t
#define GUF_DICT_KV_META_T guf_dict_kv_meta_64 #define GUF_DICT_KV_META_T guf_dict_kv_meta_64
#define GUF_DICT_KV_IDX_NULL UINT64_MAX #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 #endif
#define GUF_DICT_KV_IDX_TOMBSTONE (GUF_DICT_KV_IDX_NULL - 1) #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 // #ifndef GUF_DICT_KEY_LOOKUP_T
// #define GUF_DICT_KEY_LOOKUP_T GUF_DICT_KEY_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; } GUF_DICT_KV_NAME;
#define GUF_T GUF_DICT_KV_NAME #define GUF_T GUF_DICT_KV_NAME
#define GUF_CNT_NAME GUF_DICT_KV_DBUF #define GUF_DBUF_NAME GUF_DICT_KV_DBUF
#define GUF_ONLY_TYPES #define GUF_DBUF_ONLY_TYPES
#include "guf_dbuf.h" #include "guf_dbuf.h"
typedef struct GUF_DICT_NAME { typedef struct GUF_DICT_NAME {
@ -112,48 +108,48 @@ typedef GUF_CAT(GUF_DICT_KV_DBUF, _iter) GUF_CAT(GUF_DICT_NAME, _iter);
#endif #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_KWRDS 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, _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_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_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_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_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_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_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);
#ifdef GUF_DICT_VAL_T #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_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);
#endif #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_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);
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_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);
/* Iterator functions */ /* 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_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_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_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_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);
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_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_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_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);
#if defined(GUF_DICT_VAL_T) && (defined(GUF_DICT_VAL_T_EQ) || defined(GUF_DICT_VAL_T_IS_INTEGRAL_TYPE)) #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_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_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_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 #endif
#if defined(GUF_DICT_VAL_T) #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 #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 GUF_DICT_KV_NAME
#define GUF_T_FREE GUF_CAT(GUF_DICT_KV_NAME, _free) #define GUF_T_FREE GUF_CAT(GUF_DICT_KV_NAME, _free)
#define GUF_CNT_NAME GUF_DICT_KV_DBUF #define GUF_DBUF_NAME GUF_DICT_KV_DBUF
#define GUF_STATIC #define GUF_DBUF_WITHOUT_TYPES
#define GUF_IMPL #define GUF_DBUF_IMPL_STATIC
#include "guf_dbuf.h" #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) { if (ht->kv_indices_cap == 0) {
return 1; 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; 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) { if (!ht || !alloc) {
guf_err_set_or_panic(err, GUF_ERR_INVALID_ARG, GUF_ERR_MSG("in dict_try_init: ht or alloc NULL")); 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; 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); 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) { if (!ht) {
return false; 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; 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; (void)ctx;
GUF_ASSERT_RELEASE(GUF_CAT(GUF_DICT_NAME, _valid)(ht)); 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; 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)); GUF_ASSERT_RELEASE(GUF_CAT(GUF_DICT_NAME, _valid)(ht));
return ht->kv_elems.size; 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 #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)); 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_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_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_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); GUF_CAT(GUF_DICT_NAME, _insert)(ht, &key, &val, key_opt, val_opt);
} }
#ifdef GUF_DICT_VAL_T #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)); GUF_ASSERT_RELEASE(GUF_CAT(GUF_DICT_NAME, _valid)(ht));
if (!key) { 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); return GUF_CAT(GUF_DICT_NAME, _at)(ht, &key);
} }
#endif #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)); GUF_ASSERT_RELEASE(GUF_CAT(GUF_DICT_NAME, _valid)(ht));
if (!key) { 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; 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); 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)); 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; 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); 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 */ /* 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_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); 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}; 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_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); 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}; 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_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); 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}; 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_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); 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}; 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 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); 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; 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); 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}; 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); 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}; 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); 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}; 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); 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)) #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(GUF_CAT(GUF_DICT_NAME, _valid)(ht));
GUF_ASSERT_RELEASE(needle); 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; 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); return GUF_CAT(GUF_DICT_NAME, _find_val)(ht, begin, end, &needle);
} }
#endif #endif
#if defined(GUF_DICT_VAL_T) #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(GUF_CAT(GUF_DICT_NAME, _valid)(ht));
GUF_ASSERT_RELEASE(predicate); 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_STATIC
#undef GUF_DICT_IMPL #undef GUF_DICT_IMPL
#undef GUF_DICT_STATIC #undef GUF_DICT_KWRDS
#undef GUF_DICT_FN_KEYWORDS

View File

@ -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 #ifndef GUF_HASH_H
#define GUF_HASH_H #define GUF_HASH_H
#include "guf_common.h" #include "guf_common.h"
@ -8,17 +14,12 @@
cf. http://www.isthe.com/chongo/tech/comp/fnv/ (last retrieved: 2023-11-30) 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_HASH32_INIT UINT32_C(2166136261)
#define GUF_HASH64_INIT UINT64_C(14695981039346656037) #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_HASH_KWRDS 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 uint64_t guf_hash64(const void *data, ptrdiff_t num_bytes, uint64_t hash); // FNV-1a (64 bit)
#ifdef GUF_HASH_32_BIT #ifdef GUF_HASH_32_BIT
typedef uint32_t guf_hash_size_t; 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 #endif
#if defined(GUF_IMPL) || defined(GUF_IMPL_STATIC) #if defined(GUF_HASH_IMPL) || defined(GUF_HASH_IMPL_STATIC)
#include "guf_assert.h" #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(data);
GUF_ASSERT_RELEASE(num_bytes >= 0); 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; 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(data);
GUF_ASSERT_RELEASE(num_bytes >= 0); 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; return hash;
} }
#undef GUF_IMPL #undef GUF_HASH_IMPL
#undef GUF_IMPL_STATIC #undef GUF_HASH_IMPL_STATIC
#endif /* endif GUF_IMPL/GUF_IMPL_STATIC */ #endif /* endif GUF_IMPL/GUF_IMPL_STATIC */
#undef GUF_FN_KEYWORDS #undef GUF_HASH_KWRDS
#undef GUF_STATIC

View File

@ -5,7 +5,7 @@
#define GUF_INIT #define GUF_INIT
#include "guf_assert.h" #include "guf_assert.h"
#define GUF_IMPL #define GUF_HASH_IMPL
#include "guf_hash.h" #include "guf_hash.h"
// static inline bool guf_init(void) // static inline bool guf_init(void)

View File

@ -3,6 +3,7 @@
#include "guf_assert.h" #include "guf_assert.h"
#define GUF_PI 3.14159265358979323846264338327950288 #define GUF_PI 3.14159265358979323846264338327950288
#define GUF_PI_F32 3.14159265358979323846264338327950288f
// Rotate left. // Rotate left.
static inline uint64_t guf_rotl_u64(uint64_t x, int k) {return (x << k) | (x >> (64 - k));} static inline uint64_t guf_rotl_u64(uint64_t x, int k) {return (x << k) | (x >> (64 - k));}

View File

@ -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 #ifndef GUF_RAND_H
#define GUF_RAND_H #define GUF_RAND_H
#include "guf_common.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 #ifdef GUF_RAND_32_BIT
#define GUF_RAND_MAX UINT32_MAX #define GUF_RAND_MAX UINT32_MAX
typedef struct guf_randstate { // State for xoshiro128** 1.1 typedef struct guf_randstate { // State for xoshiro128** 1.1
@ -21,38 +21,38 @@
} guf_randstate; } guf_randstate;
#endif #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); GUF_RAND_KWRDS 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_jump(guf_randstate *state); // Advance the state; equivalent to 2^128 calls to guf_rand_u64(state)
// uniform distributions // uniform distributions
GUF_FN_KEYWORDS uint32_t guf_rand_u32(guf_randstate *state); // [0, UINT32_MAX] GUF_RAND_KWRDS 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_RAND_KWRDS 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_RAND_KWRDS 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 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) // 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_RAND_KWRDS 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_RAND_KWRDS 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_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_RAND_KWRDS 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 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_RAND_KWRDS 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_RAND_KWRDS 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 int64_t guf_randrange_i64(guf_randstate *state, int64_t min, int64_t max); // [min, max]
// normal distributions // 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_RAND_KWRDS 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_RAND_KWRDS 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_RAND_KWRDS 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 float guf_rand_normal_sample_one_f32(guf_randstate *state, float mean, float std_dev);
#endif #endif
#if defined(GUF_IMPL) || defined(GUF_IMPL_STATIC) #if defined(GUF_RAND_IMPL) || defined(GUF_RAND_IMPL_STATIC)
#include <math.h> #include <math.h>
#include <float.h> #include <float.h>
#include "guf_common.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) 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) 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); GUF_ASSERT(state);
uint64_t z = ((*state) += 0x9e3779b97f4a7c15); uint64_t z = ((*state) += 0x9e3779b97f4a7c15);
@ -72,7 +72,7 @@ GUF_FN_KEYWORDS uint64_t guf_rand_splitmix64(uint64_t *state)
return z ^ (z >> 31); 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); GUF_ASSERT_RELEASE(state);
#ifdef GUF_RAND_32_BIT #ifdef GUF_RAND_32_BIT
@ -101,7 +101,7 @@ GUF_FN_KEYWORDS void guf_randstate_init(guf_randstate *state, uint64_t seed)
#endif #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);
GUF_ASSERT(state->s[0] || state->s[1] || state->s[2] || state->s[3]); 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 #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);
GUF_ASSERT(state->s[0] || state->s[1] || state->s[2] || state->s[3]); 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) 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. 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); GUF_ASSERT(state);
#ifdef GUF_RAND_32_BIT #ifdef GUF_RAND_32_BIT
@ -204,14 +204,14 @@ void guf_randstate_jump(guf_randstate *state)
} }
// Generate double in the unit interval [0, 1) // 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) // 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) 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) // 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 #ifdef GUF_RAND_32_BIT
return (guf_rand_u32(state) >> 8) * 0x1.0p-24f; // 8 == 32 - 24; (float has a 24-bit mantissa/significand) 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 #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); 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) 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); 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) 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 #ifdef GUF_RAND_32_BIT
return guf_rand_bernoulli_trial_f32(state, 0.5f); 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) // 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) { if (min == (double)INFINITY) {
min = DBL_MAX; 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) // 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) { if (min == INFINITY) {
min = FLT_MAX; 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) // 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); GUF_ASSERT_RELEASE(max >= min);
if (min == max) { 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; 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); GUF_ASSERT_RELEASE(max >= min);
if (min == max) { 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) // 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); GUF_ASSERT_RELEASE(max >= min);
if (min == max) { 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) // 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(result);
GUF_ASSERT_RELEASE(n >= 0); 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(result);
GUF_ASSERT_RELEASE(n >= 0); 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; double result;
guf_rand_normal_sample_f64(state, mean, std_dev, &result, 1); guf_rand_normal_sample_f64(state, mean, std_dev, &result, 1);
return result; 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; float result;
guf_rand_normal_sample_f32(state, mean, std_dev, &result, 1); guf_rand_normal_sample_f32(state, mean, std_dev, &result, 1);
return result; return result;
} }
#undef GUF_IMPL #undef GUF_RAND_IMPL
#undef GUF_IMPL_STATIC #undef GUF_RAND_IMPL_STATIC
#endif /* endif GUF_IMPL/GUF_IMPL_STATIC */ #endif /* end impl */
#undef GUF_STATIC #undef GUF_RAND_KWRDS
#undef GUF_FN_KEYWORDS
#undef GUF_RAND_32_BIT #undef GUF_RAND_32_BIT

View File

@ -15,19 +15,19 @@ typedef enum guf_sort_opt {
#define GUF_FN_NAME_PREFIX GUF_CAT(GUF_T, _arr) #define GUF_FN_NAME_PREFIX GUF_CAT(GUF_T, _arr)
#endif #endif
#if defined(GUF_IMPL_STATIC) || defined(GUF_STATIC) #if defined(GUF_SORT_IMPL_STATIC)
#define GUF_FN_KEYWORDS static #define GUF_SORT_KWRDS static
#else #else
#define GUF_FN_KEYWORDS #define GUF_SORT_KWRDS
#endif #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_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_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_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_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(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)) #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) - time: worst O(n^2); average O(n^2); best O(n) (if arr is already sorted)
- space: O(1) - 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(arr);
GUF_ASSERT_RELEASE(n >= 0); 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) - time: O(n * log n) (worst, average, and best)
- space: always O(n) (for arr_tmp, allocated and freed by the caller) - 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(arr);
GUF_ASSERT_RELEASE(n >= 0); 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; 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(arr);
GUF_ASSERT_RELEASE(sort_opt == GUF_SORT_ASCENDING || sort_opt == GUF_SORT_DESCENDING); 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); GUF_ASSERT_RELEASE(arr);
for (ptrdiff_t i = 0; i < n - 1; ++i) { 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
#undef guf_before_or_equal #undef guf_before_or_equal
#undef GUF_IMPL #undef GUF_SORT_IMPL
#undef GUF_IMPL_STATIC #undef GUF_SORT_IMPL_STATIC
#endif /* end #ifdef GUF_IMPL */ #endif /* end #ifdef GUF_IMPL */
#undef GUF_STATIC #undef GUF_SORT_KWRDS
#undef GUF_FN_KEYWORDS
#undef GUF_T #undef GUF_T
#undef GUF_FN_NAME_PREFIX #undef GUF_FN_NAME_PREFIX
#endif /* end #ifdef GUF_T */ #endif /* end #ifdef GUF_T */

View File

@ -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 #ifndef GUF_STR_H
#define GUF_STR_H #define GUF_STR_H
#include "guf_common.h" #include "guf_common.h"
#include "guf_alloc.h" #include "guf_alloc.h"
#include "guf_str_view_type.h"
#if defined(GUF_STATIC) || defined(GUF_IMPL_STATIC) #include "guf_utf8.h"
#define GUF_FN_KEYWORDS static
#else
#define GUF_FN_KEYWORDS
#endif
typedef enum guf_str_state { typedef enum guf_str_state {
GUF_STR_STATE_INIT = 0, GUF_STR_STATE_INIT = 0,
@ -33,78 +35,149 @@ typedef struct guf_str {
guf_str_state state; guf_str_state state;
} guf_str; } 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_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_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}) #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: // Creation:
GUF_FN_KEYWORDS guf_str *guf_str_init(guf_str *str, guf_str_view str_view); GUF_STR_KWRDS 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_STR_KWRDS 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_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_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_STR_KWRDS 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_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_STR_KWRDS 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_empty_with_capacity(size_t capacity);
// Destruction: // Destruction:
GUF_FN_KEYWORDS void guf_str_free(guf_str *str); GUF_STR_KWRDS void guf_str_free(guf_str *str);
// Modification: // Modification:
GUF_FN_KEYWORDS guf_str *guf_str_append(guf_str *str, guf_str_view to_append); GUF_STR_KWRDS 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_STR_KWRDS 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_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_STR_KWRDS 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_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_STR_KWRDS 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_front(guf_str *str);
// Copying and viewing: // 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_STR_KWRDS 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_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: // Indexing:
GUF_FN_KEYWORDS char *guf_str_at(guf_str *str, size_t idx); GUF_STR_KWRDS char *guf_str_at(guf_str *str, size_t idx);
GUF_FN_KEYWORDS char *guf_str_back(guf_str *str); GUF_STR_KWRDS char *guf_str_back(guf_str *str);
GUF_FN_KEYWORDS char *guf_str_front(guf_str *str); GUF_STR_KWRDS char *guf_str_front(guf_str *str);
GUF_FN_KEYWORDS const char *guf_str_const_cstr(const guf_str *str); GUF_STR_KWRDS const char *guf_str_const_cstr(const guf_str *str);
// Metadata retrieval: // 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_STR_KWRDS 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_STR_KWRDS size_t guf_str_capacity(const guf_str *str);
GUF_FN_KEYWORDS bool guf_str_is_stack_allocated(const guf_str *str); GUF_STR_KWRDS bool guf_str_is_stack_allocated(const guf_str *str);
GUF_FN_KEYWORDS bool guf_str_is_valid(const guf_str *str); GUF_STR_KWRDS bool guf_str_is_valid(const guf_str *str);
GUF_FN_KEYWORDS bool guf_str_alloc_success(const guf_str *str); GUF_STR_KWRDS bool guf_str_alloc_success(const guf_str *str);
// Comparison: // 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_FN_KEYWORDS bool guf_str_equal(const guf_str *a, const guf_str *b); GUF_STR_KWRDS 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_STR_KWRDS 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_STR_KWRDS 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 int guf_str_view_cmp(const void *str_view_a, const void *str_view_b); // For qsort etc.
#endif #endif
#if defined(GUF_IMPL) || defined(GUF_IMPL_STATIC) #if defined(GUF_STR_IMPL) || defined(GUF_STR_IMPL_STATIC)
#include <string.h> #include <string.h>
#ifndef GUF_FN_KEYWORDS #ifdef GUF_STR_IMPL
#define GUF_FN_KEYWORDS #define GUF_UTF8_IMPL
#else
#define GUF_UTF8_IMPL_STATIC
#endif #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. // TODO: find_first_of and tokenise -> for parsing, see aoclib.
GUF_STR_KWRDS guf_str_view guf_substr_view(guf_str_view str, ptrdiff_t pos, ptrdiff_t count)
GUF_FN_KEYWORDS guf_str_view guf_substr_view(guf_str_view str, ptrdiff_t pos, ptrdiff_t count)
{ {
GUF_ASSERT(str.str); GUF_ASSERT(str.str);
GUF_ASSERT(pos >= 0); 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: // 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 && b);
GUF_ASSERT_RELEASE(a->str && b->str); GUF_ASSERT_RELEASE(a->str && b->str);
if (a->len != b->len) { if (a->len != b->len) {
return false; return false;
} }
GUF_ASSERT_RELEASE(a->len >= 0); 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); 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 */ #endif /* end impl */
#undef GUF_STR_KWRDS

10
src/guf_str_view_type.h Normal file
View 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

View File

@ -1,70 +1,213 @@
#if defined(GUF_UTF8_IMPL_STATIC)
#define GUF_UTF8_KWRDS static
#else
#define GUF_UTF8_KWRDS
#endif
#ifndef GUF_UTF8_H #ifndef GUF_UTF8_H
#define GUF_UTF8_H #define GUF_UTF8_H
#include "guf_common.h" #include "guf_common.h"
#include "guf_str.h" #include "guf_str_view_type.h"
#if defined(GUF_STATIC) || defined(GUF_STATIC_IMPL) // Corresponds to one unicode codepoint (NOTE: one guf_utf8_char does not necessarily correspond to one printable character, e.g. combining characters).
#define GUF_FN_KEYWORDS static typedef struct guf_utf8_char {
#else
#define GUF_FN_KEYWORDS
#endif
typedef struct guf_utf8_char {
char bytes[5]; char bytes[5];
} guf_utf8_char; } guf_utf8_char;
typedef enum guf_utf8_stat { typedef enum guf_utf8_stat {
GUF_UTF8_READ_DONE, GUF_UTF8_READ_DONE,
GUF_UTF8_READ_VALID, GUF_UTF8_READ_VALID,
GUF_UTF8_READ_INVALID, GUF_UTF8_READ_INVALID,
GUF_UTF8_READ_TRUNCATED, GUF_UTF8_READ_TRUNCATED,
} guf_utf8_stat; } guf_utf8_stat;
static inline bool guf_char_is_ascii(int c) {return c <= 0 && c <= 127;} 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;} 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_UTF8_KWRDS 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_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_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_FN_KEYWORDS bool guf_utf8_char_is_valid(const guf_utf8_char *c); GUF_UTF8_KWRDS bool guf_utf8_encode(guf_utf8_char *result, uint32_t codepoint); // Returns false for invalid codepoints.
GUF_FN_KEYWORDS bool guf_utf8_char_is_whitespace(const guf_utf8_char *c); 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 guf_utf8_char GUF_UTF8_REPLACEMENT_CHAR; // Replacement character "<22>" (U+FFFD)
extern const char* const guf_utf8_punctuation[29]; #define GUF_UTF8_REPLACEMENT_CHAR_CODEPOINT UINT32_C(0xFFFD)
#endif #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" // All utf-8 whitespace, cf. https://en.wikipedia.org/wiki/Whitespace_character#Unicode (last-retrieved 2025-02-27)
#include "guf_assert.h" const char* const GUF_UTF8_WHITESPACE[25] =
const char* const guf_utf8_whitespace[25] =
{ {
" ", "\n", "\t", "\t", "\v", "\f", " ", "\n", "\t", "\t", "\v", "\f",
"\xC2\x85", "\xC2\xA0", "\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" "\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 #ifndef GUF_FN_KEYWORDS
#define GUF_FN_KEYWORDS #define GUF_FN_KEYWORDS
#endif #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); const int num_bytes_a = guf_utf8_char_num_bytes(a);
GUF_ASSERT_RELEASE(str); 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) { if (str->len <= 0 || str->str == NULL) {
return GUF_UTF8_READ_DONE; 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)) { } else if (guf_utf8_char_is_valid(res)) {
return GUF_UTF8_READ_VALID; return GUF_UTF8_READ_VALID;
} else { } 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; return GUF_UTF8_READ_INVALID;
} }
} }
// cf. https://www.rfc-editor.org/rfc/rfc3629#page-4 // 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 if (c <= 0x7F) { // bits: 0xxx.xxxx
return 1; 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); GUF_ASSERT(c);
return guf_utf8_num_bytes(c->bytes[0]); 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]); 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; 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) { 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 // "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 #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) // 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_one_byte[] = {" ", "\n", "\t", "\t", "\v", "\f"};
const char *ws_two_bytes[] = {"\xC2\x85", "\xC2\xA0"}; 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) #undef GUF_UTF8_IMPL
{ #undef GUF_UTF8_IMPL_STATIC
if (input->len <= 0 || input->str == NULL) { #endif /* end impl */
return (guf_str_view){.str = NULL, .len = 0};
}
ptrdiff_t max_delim_len = -1; #undef GUF_UTF8_KWRDS
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

View File

@ -8,43 +8,43 @@
#include "guf_alloc_libc.h" #include "guf_alloc_libc.h"
#include "guf_cstr.h" #include "guf_cstr.h"
#define GUF_IMPL_STATIC
#define GUF_T float #define GUF_T float
#define GUF_SORT_IMPL_STATIC
#include "guf_sort.h" #include "guf_sort.h"
#define GUF_IMPL_STATIC
#define GUF_T int #define GUF_T int
#define GUF_SORT_IMPL_STATIC
#include "guf_sort.h" #include "guf_sort.h"
#define GUF_CNT_NAME dbuf_int #define GUF_DBUF_NAME dbuf_int
#define GUF_T int #define GUF_T int
#define GUF_T_IS_INTEGRAL_TYPE #define GUF_T_IS_INTEGRAL_TYPE
#define GUF_IMPL_STATIC #define GUF_DBUF_IMPL_STATIC
#include "guf_dbuf.h" #include "guf_dbuf.h"
#define GUF_CNT_NAME dbuf_float #define GUF_DBUF_NAME dbuf_float
#define GUF_T float #define GUF_T float
#define GUF_T_IS_INTEGRAL_TYPE #define GUF_T_IS_INTEGRAL_TYPE
#define GUF_IMPL_STATIC #define GUF_DBUF_IMPL_STATIC
#include "guf_dbuf.h" #include "guf_dbuf.h"
#define GUF_T guf_cstr_heap #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_COPY guf_cstr_heap_copy
#define GUF_T_MOVE guf_cstr_heap_move #define GUF_T_MOVE guf_cstr_heap_move
#define GUF_T_FREE guf_cstr_heap_free #define GUF_T_FREE guf_cstr_heap_free
#define GUF_T_EQ guf_cstr_heap_eq #define GUF_T_EQ guf_cstr_heap_eq
#define GUF_IMPL_STATIC #define GUF_DBUF_IMPL_STATIC
// #define GUF_CNT_WITH_ELEM_CTX // #define GUF_CNT_WITH_ELEM_CTX
#include "guf_dbuf.h" #include "guf_dbuf.h"
#define GUF_T guf_cstr_const #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_T_EQ guf_cstr_const_eq
#define GUF_IMPL_STATIC #define GUF_DBUF_IMPL_STATIC
#include "guf_dbuf.h" #include "guf_dbuf.h"
#define GUF_IMPL_STATIC #define GUF_RAND_IMPL_STATIC
#include "guf_rand.h" #include "guf_rand.h"
#include "guf_dict_impl.h" #include "guf_dict_impl.h"

View File

@ -1,40 +1,46 @@
#include "guf_dbuf_impl.h" #include "guf_dbuf_impl.h"
#define GUF_CNT_NAME dbuf_int #define GUF_DBUF_NAME dbuf_int
#define GUF_T int #define GUF_T int
#define GUF_T_IS_INTEGRAL_TYPE #define GUF_T_IS_INTEGRAL_TYPE
#define GUF_IMPL #define GUF_DBUF_IMPL
#include "guf_dbuf.h" #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 char
#define GUF_T_IS_INTEGRAL_TYPE #define GUF_T_IS_INTEGRAL_TYPE
#define GUF_IMPL #define GUF_DBUF_IMPL
#include "guf_dbuf.h" #include "guf_dbuf.h"
#define GUF_CNT_NAME dbuf_float #define GUF_DBUF_NAME dbuf_float
#define GUF_T float #define GUF_T float
#define GUF_T_IS_INTEGRAL_TYPE #define GUF_T_IS_INTEGRAL_TYPE
#define GUF_IMPL #define GUF_DBUF_IMPL
#include "guf_dbuf.h" #include "guf_dbuf.h"
#define GUF_T guf_cstr_heap #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_COPY guf_cstr_heap_copy
#define GUF_T_MOVE guf_cstr_heap_move #define GUF_T_MOVE guf_cstr_heap_move
#define GUF_T_FREE guf_cstr_heap_free #define GUF_T_FREE guf_cstr_heap_free
#define GUF_T_EQ guf_cstr_heap_eq #define GUF_T_EQ guf_cstr_heap_eq
#define GUF_IMPL #define GUF_DBUF_IMPL
#include "guf_dbuf.h" #include "guf_dbuf.h"
#define GUF_T guf_cstr_const #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_T_EQ guf_cstr_const_eq
#define GUF_IMPL #define GUF_DBUF_IMPL
#include "guf_dbuf.h" #include "guf_dbuf.h"
#define GUF_T guf_str_view #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_T_EQ guf_str_view_equal
#define GUF_IMPL #define GUF_DBUF_IMPL
#include "guf_dbuf.h" #include "guf_dbuf.h"

View File

@ -4,25 +4,28 @@
#include "guf_cstr.h" #include "guf_cstr.h"
#include "guf_str.h" #include "guf_str.h"
#define GUF_CNT_NAME dbuf_int #define GUF_DBUF_NAME dbuf_int
#define GUF_T int #define GUF_T int
#define GUF_T_IS_INTEGRAL_TYPE #define GUF_T_IS_INTEGRAL_TYPE
#include "guf_dbuf.h" #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 char
#define GUF_T_IS_INTEGRAL_TYPE #define GUF_T_IS_INTEGRAL_TYPE
#include "guf_dbuf.h" #include "guf_dbuf.h"
#define GUF_CNT_NAME dbuf_float #define GUF_DBUF_NAME dbuf_float
#define GUF_T float #define GUF_T float
#define GUF_T_IS_INTEGRAL_TYPE #define GUF_T_IS_INTEGRAL_TYPE
#include "guf_dbuf.h" #include "guf_dbuf.h"
#define GUF_T guf_cstr_heap #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_COPY guf_cstr_heap_copy
#define GUF_T_MOVE guf_cstr_heap_move #define GUF_T_MOVE guf_cstr_heap_move
#define GUF_T_FREE guf_cstr_heap_free #define GUF_T_FREE guf_cstr_heap_free
@ -30,12 +33,12 @@ typedef unsigned char uchar;
#include "guf_dbuf.h" #include "guf_dbuf.h"
#define GUF_T guf_cstr_const #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_T_EQ guf_cstr_const_eq
#include "guf_dbuf.h" #include "guf_dbuf.h"
#define GUF_T guf_str_view #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_T_EQ guf_str_view_equal
#include "guf_dbuf.h" #include "guf_dbuf.h"

View File

@ -6,7 +6,7 @@
#define GUF_DICT_VAL_T int #define GUF_DICT_VAL_T int
#define GUF_DICT_VAL_T_IS_INTEGRAL_TYPE #define GUF_DICT_VAL_T_IS_INTEGRAL_TYPE
#define GUF_DICT_NAME dict_cstr_int #define GUF_DICT_NAME dict_cstr_int
#define GUF_IMPL #define GUF_DICT_IMPL
#include "guf_dict.h" #include "guf_dict.h"
#define GUF_DICT_KEY_T int32_t #define GUF_DICT_KEY_T int32_t
@ -15,5 +15,5 @@
#define GUF_DICT_VAL_T bool #define GUF_DICT_VAL_T bool
#define GUF_DICT_VAL_T_IS_INTEGRAL_TYPE #define GUF_DICT_VAL_T_IS_INTEGRAL_TYPE
#define GUF_DICT_NAME dict_i32_bool #define GUF_DICT_NAME dict_i32_bool
#define GUF_IMPL #define GUF_DICT_IMPL
#include "guf_dict.h" #include "guf_dict.h"

View File

@ -1,2 +1,2 @@
#define GUF_IMPL #define GUF_RAND_IMPL
#include "guf_rand.h" #include "guf_rand.h"

View File

@ -1,17 +1,17 @@
#include "guf_sort_impl.h" #include "guf_sort_impl.h"
#define GUF_T float #define GUF_T float
#define GUF_IMPL #define GUF_SORT_IMPL
#include "guf_sort.h" #include "guf_sort.h"
#define GUF_T int32_t #define GUF_T int32_t
#define GUF_IMPL #define GUF_SORT_IMPL
#include "guf_sort.h" #include "guf_sort.h"
#define GUF_T int8_t #define GUF_T int8_t
#define GUF_IMPL #define GUF_SORT_IMPL
#include "guf_sort.h" #include "guf_sort.h"
#define GUF_T guf_cstr_heap #define GUF_T guf_cstr_heap
#define GUF_IMPL #define GUF_SORT_IMPL
#include "guf_sort.h" #include "guf_sort.h"

View File

@ -1,5 +1,6 @@
#ifndef GUF_SORT_IMPL_H #ifndef GUF_SORT_IMPL_H
#define GUF_SORT_IMPL_H #define GUF_SORT_IMPL_H
#include "guf_cstr.h" #include "guf_cstr.h"
#define GUF_T float #define GUF_T float

2
src/test/guf_str_impl.c Normal file
View File

@ -0,0 +1,2 @@
#define GUF_STR_IMPL
#include "guf_str.h"

View File

@ -1,7 +0,0 @@
#include "guf_utf8.h"
#define GUF_IMPL
#include "guf_utf8.h"
#define GUF_IMPL
#include "guf_str.h"

View File

@ -6,7 +6,6 @@ extern "C"
{ {
#include "guf_alloc_libc.h" #include "guf_alloc_libc.h"
#include "guf_dict_impl.h" #include "guf_dict_impl.h"
#include "guf_utf8.h"
#include "guf_str.h" #include "guf_str.h"
} }
@ -27,12 +26,12 @@ struct DictCstrToIntTest : public Test
dict_cstr_int_init(&word_cnt_dict, &guf_allocator_libc); dict_cstr_int_init(&word_cnt_dict, &guf_allocator_libc);
dbuf_str_view delims = dbuf_str_view_new(&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) { 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]}; guf_str_view d = {.len = (ptrdiff_t)strlen(GUF_UTF8_WHITESPACE[i]), .str = GUF_UTF8_WHITESPACE[i]};
dbuf_str_view_push_val(&delims, d); dbuf_str_view_push_val(&delims, d);
} }
for (size_t i = 0; i < GUF_STATIC_BUF_SIZE(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_punctuation[i]), .str = guf_utf8_punctuation[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); dbuf_str_view_push_val(&delims, d);
} }
guf_str_view input_str = {.str = text_buf.data, .len = text_buf.size}; guf_str_view input_str = {.str = text_buf.data, .len = text_buf.size};

View File

@ -6,7 +6,6 @@ extern "C"
#include "guf_alloc_libc.h" #include "guf_alloc_libc.h"
#include "guf_dict_impl.h" #include "guf_dict_impl.h"
#include "guf_dbuf_impl.h" #include "guf_dbuf_impl.h"
#include "guf_utf8.h"
#include "guf_str.h" #include "guf_str.h"
} }
@ -117,6 +116,241 @@ struct UTF8Test : public Test
return num_words; 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: public:
bool run() bool run()
@ -130,24 +364,24 @@ struct UTF8Test : public Test
TEST_CHECK(valid == 2634 && invalid == 0); TEST_CHECK(valid == 2634 && invalid == 0);
dbuf_str_view delims = dbuf_str_view_new(&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) { 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]}; guf_str_view d = {.len = (ptrdiff_t)strlen(GUF_UTF8_WHITESPACE[i]), .str = GUF_UTF8_WHITESPACE[i]};
dbuf_str_view_push_val(&delims, d); dbuf_str_view_push_val(&delims, d);
} }
for (size_t i = 0; i < GUF_STATIC_BUF_SIZE(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_punctuation[i]), .str = guf_utf8_punctuation[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); dbuf_str_view_push_val(&delims, d);
} }
int words = count_words(TEST_DATA_DIR "/" "utf8-test.txt", &delims); int words = count_words(TEST_DATA_DIR "/" "utf8-test.txt", &delims);
printf("words %d\n", words);
TEST_CHECK(words == 422); TEST_CHECK(words == 422);
int words_with_delims = count_words_with_delims(TEST_DATA_DIR "/" "utf8-test.txt", &delims); int words_with_delims = count_words_with_delims(TEST_DATA_DIR "/" "utf8-test.txt", &delims);
TEST_CHECK(words_with_delims == 947); TEST_CHECK(words_with_delims == 947);
dbuf_str_view_free(&delims, NULL); dbuf_str_view_free(&delims, NULL);
encode_decode();
encode_decode_file(TEST_DATA_DIR "/" "utf8-test.txt");
done = true; done = true;
passed = (num_failed_checks == 0); passed = (num_failed_checks == 0);
return passed; return passed;

View File

@ -1,2 +1,5 @@
- guf_stack, guf_queue, guf_ringbuf - guf_stack, guf_queue, guf_ringbuf
- guf_rand etc.: move guf_fn_keywors out of header guard? (-> no, add a GUF_WITHOUT_TYPES) - guf_rand etc.: move guf_fn_keywors out of header guard? (-> no, add a GUF_WITHOUT_TYPES)
- unicode normalisation
- fix 32-bit dict (and add 32/64 bit defs in common.h)