Add better error handling
This commit is contained in:
parent
e668be2612
commit
be2daf72fd
@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.12)
|
|||||||
set(PROJECT_NAME libguf)
|
set(PROJECT_NAME libguf)
|
||||||
project(${PROJECT_NAME})
|
project(${PROJECT_NAME})
|
||||||
|
|
||||||
set(SOURCES src/guf_str.c src/guf_dict.c src/guf_int.c)
|
set(SOURCES src/guf_str.c src/guf_dict.c)
|
||||||
|
|
||||||
add_library(${PROJECT_NAME} STATIC ${SOURCES})
|
add_library(${PROJECT_NAME} STATIC ${SOURCES})
|
||||||
# target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}}/lib/guf)
|
# target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}}/lib/guf)
|
||||||
|
|||||||
125
src/guf_assert.h
125
src/guf_assert.h
@ -3,13 +3,132 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
#include "guf_common_utils.h"
|
||||||
|
|
||||||
|
typedef enum guf_err_type {
|
||||||
|
GUF_ERR_NONE = 0,
|
||||||
|
GUF_ERR_UNSPECIFIED,
|
||||||
|
GUF_ERR_ALLOC_FAIL,
|
||||||
|
GUF_ERR_NULL_PTR,
|
||||||
|
GUF_ERR_INT_OVERFLOW,
|
||||||
|
GUF_ERR_DIV_BY_ZERO,
|
||||||
|
GUF_ERR_DOMAIN,
|
||||||
|
GUF_ERR_IDX_RANGE,
|
||||||
|
GUF_ERR_INVALID_ARG,
|
||||||
|
GUF_ERR_RUNTIME,
|
||||||
|
GUF_ERR_LOGIC,
|
||||||
|
GUF_ERR_RELEASE_ASSERT,
|
||||||
|
GUF_ERR_TYPES_NUM
|
||||||
|
} guf_err_type;
|
||||||
|
|
||||||
|
typedef struct guf_err {
|
||||||
|
guf_err_type type;
|
||||||
|
const char *msg;
|
||||||
|
} guf_err;
|
||||||
|
|
||||||
|
static const guf_err GUF_SUCCESS = (guf_err){.type = GUF_ERR_NONE, .msg = NULL};
|
||||||
|
|
||||||
|
typedef void(*guf_panic_handler_fn)(const guf_err *err);
|
||||||
|
|
||||||
|
extern guf_panic_handler_fn guf_global_panic_handler;
|
||||||
|
extern const char *guf_err_type_str[GUF_ERR_TYPES_NUM];
|
||||||
|
|
||||||
|
static inline void guf_set_global_panic_handler(guf_panic_handler_fn panic_handler)
|
||||||
|
{
|
||||||
|
guf_global_panic_handler = panic_handler;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Break on debug, cf. https://nullprogram.com/blog/2022/06/26/ (last retrieved 2025-01-07)
|
||||||
|
#if __GNUC__ || __clang__
|
||||||
|
#define GUF_DEBUG_BREAK_CODE __builtin_trap()
|
||||||
|
#elif _MSC_VER
|
||||||
|
#define GUF_DEBUG_BREAK_CODE __debugbreak()
|
||||||
|
#else
|
||||||
|
#define GUF_DEBUG_BREAK_CODE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef NDEBUG
|
||||||
|
#define GUF_ASSERT(COND) do { \
|
||||||
|
if (!(COND)) { \
|
||||||
|
fputs("libguf assertion '" #COND "' failed (" GUF_FILE_LINE_STR() ")\n", stderr); \
|
||||||
|
GUF_DEBUG_BREAK_CODE; \
|
||||||
|
abort(); \
|
||||||
|
}\
|
||||||
|
} while(0);
|
||||||
|
#else
|
||||||
|
#define GUF_ASSERT(COND)
|
||||||
|
#endif
|
||||||
|
|
||||||
#define GUF_ASSERT(COND) assert(COND)
|
|
||||||
#define GUF_ASSERT_RELEASE(COND) do { \
|
#define GUF_ASSERT_RELEASE(COND) do { \
|
||||||
if (!(COND)) { \
|
if (!(COND)) { \
|
||||||
fprintf(stderr, "libguf release assertion failed: " #COND ", file " __FILE__ ", line %d\n", __LINE__); \
|
guf_err guf_assert_err = (guf_err){.type = GUF_ERR_RELEASE_ASSERT, .msg = "(assertion '" #COND "' in file " __FILE__ " on line " GUF_STRINGIFY(__LINE__) ")"};\
|
||||||
exit(EXIT_FAILURE); \
|
guf_global_panic_handler(&guf_assert_err);\
|
||||||
} \
|
} \
|
||||||
} while (0);
|
} while (0);
|
||||||
|
|
||||||
|
#define GUF_FILE_LINE_STR() "file '" __FILE__ "' line " GUF_STRINGIFY(__LINE__)
|
||||||
|
#define GUF_ERR_MSG(msg) msg " (" GUF_FILE_LINE_STR() ")"
|
||||||
|
|
||||||
|
#define GUF_PANIC(error_type) do {guf_err guf_panic_err = (guf_err){.type = (error_type), .msg = "(" GUF_FILE_LINE_STR() ")"}; guf_global_panic_handler(&guf_panic_err)} while(0);
|
||||||
|
|
||||||
|
static inline bool guf_is_err(const guf_err *err)
|
||||||
|
{
|
||||||
|
GUF_ASSERT_RELEASE(err);
|
||||||
|
GUF_ASSERT_RELEASE(err->type >= 0 && err->type < GUF_ERR_TYPES_NUM);
|
||||||
|
return err->type != GUF_ERR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void guf_panic_handler_default(const guf_err *err)
|
||||||
|
{
|
||||||
|
if (!err) {
|
||||||
|
fputs("libguf panic!", stderr);
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
fputs("libguf panic: ", stderr);
|
||||||
|
|
||||||
|
if (err->type > 0 || err->type < GUF_ERR_TYPES_NUM) {
|
||||||
|
GUF_ASSERT(GUF_STATIC_BUF_SIZE(guf_err_type_str) == GUF_ERR_TYPES_NUM);
|
||||||
|
fputs(guf_err_type_str[err->type], stderr);
|
||||||
|
fputc(' ', stderr);
|
||||||
|
if (err->msg && err->type != GUF_ERR_NONE) {
|
||||||
|
fputs(err->msg, stderr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fputc('\n', stderr);
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef GUF_IMPLEMENTATION
|
||||||
|
guf_panic_handler_fn guf_global_panic_handler = guf_panic_handler_default;
|
||||||
|
|
||||||
|
const char *guf_err_type_str[] = {
|
||||||
|
[GUF_ERR_NONE] = "Not an error",
|
||||||
|
[GUF_ERR_UNSPECIFIED] = "Error",
|
||||||
|
[GUF_ERR_ALLOC_FAIL] = "Allocation error",
|
||||||
|
[GUF_ERR_NULL_PTR] = "Null pointer dereference",
|
||||||
|
[GUF_ERR_DOMAIN] = "Domain error",
|
||||||
|
[GUF_ERR_INT_OVERFLOW] = "Integer overflow",
|
||||||
|
[GUF_ERR_DIV_BY_ZERO] = "Division by zero",
|
||||||
|
[GUF_ERR_IDX_RANGE] = "Index out of range",
|
||||||
|
[GUF_ERR_INVALID_ARG] = "Invalid argument",
|
||||||
|
[GUF_ERR_RUNTIME] = "Runtime error",
|
||||||
|
[GUF_ERR_LOGIC] = "Logic error",
|
||||||
|
[GUF_ERR_RELEASE_ASSERT] = "Release assertion failed"
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static inline void guf_panic(const guf_err *err)
|
||||||
|
{
|
||||||
|
GUF_ASSERT(guf_global_panic_handler);
|
||||||
|
if (!guf_global_panic_handler) {
|
||||||
|
fputs("libguf panic (note: guf_global_panic_handler is NULL)\n", stderr);
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
guf_global_panic_handler(err);
|
||||||
|
abort(); // Just in case...
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@ -7,9 +7,9 @@
|
|||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
||||||
#include "guf_common_utils.h"
|
#include "guf_common_utils.h"
|
||||||
|
#include "guf_assert.h"
|
||||||
#include "guf_int.h"
|
#include "guf_int.h"
|
||||||
#include "guf_hash.h"
|
#include "guf_hash.h"
|
||||||
#include "guf_assert.h"
|
|
||||||
|
|
||||||
typedef enum guf_obj_cpy_opt {
|
typedef enum guf_obj_cpy_opt {
|
||||||
GUF_CPY_VALUE = 0,
|
GUF_CPY_VALUE = 0,
|
||||||
|
|||||||
@ -1,12 +1,14 @@
|
|||||||
#ifndef GUF_COMMON_UTILS_H
|
#ifndef GUF_COMMON_UTILS_H
|
||||||
#define GUF_COMMON_UTILS_H
|
#define GUF_COMMON_UTILS_H
|
||||||
#include "guf_assert.h"
|
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
|
|
||||||
// The GUFCAT/GUF_TOK_CAT indirection is necessary because the ## operation alone does not evaluate the macro arguments.
|
// The GUFCAT/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
|
||||||
#define GUFCAT(a, b) GUF_TOK_CAT(a, b)
|
#define GUFCAT(a, b) GUF_TOK_CAT(a, b)
|
||||||
|
|
||||||
|
#define GUF_TOK_STRINGIFY(x) #x
|
||||||
|
#define GUF_STRINGIFY(x) GUF_TOK_STRINGIFY(x)
|
||||||
|
|
||||||
#define GUF_FOREACH(CNT_PTR, CNT_TYPE, IT_NAME) for (GUFCAT(CNT_TYPE, _iter) IT_NAME = GUFCAT(CNT_TYPE, _begin)(CNT_PTR); IT_NAME.cur != IT_NAME.end; IT_NAME = IT_NAME.next(&IT_NAME, 1))
|
#define GUF_FOREACH(CNT_PTR, CNT_TYPE, IT_NAME) for (GUFCAT(CNT_TYPE, _iter) IT_NAME = GUFCAT(CNT_TYPE, _begin)(CNT_PTR); IT_NAME.cur != IT_NAME.end; IT_NAME = IT_NAME.next(&IT_NAME, 1))
|
||||||
|
|
||||||
#define GUF_STATIC_BUF_SIZE(BUF) (sizeof((BUF)) / (sizeof((BUF)[0])))
|
#define GUF_STATIC_BUF_SIZE(BUF) (sizeof((BUF)) / (sizeof((BUF)[0])))
|
||||||
|
|||||||
@ -84,6 +84,7 @@ static inline GUF_OBJ_OPS_DEFINE_CMP_VOID(guf_const_cstr, guf_const_cstr_cmp)
|
|||||||
static inline GUF_OBJ_OPS_DEFINE_CMP_VOID_INV(guf_const_cstr, guf_const_cstr_cmp)
|
static inline GUF_OBJ_OPS_DEFINE_CMP_VOID_INV(guf_const_cstr, guf_const_cstr_cmp)
|
||||||
|
|
||||||
static guf_const_cstr_ops_type guf_const_cstr_ops = {
|
static guf_const_cstr_ops_type guf_const_cstr_ops = {
|
||||||
|
.default_value = NULL,
|
||||||
.copy_init = NULL,
|
.copy_init = NULL,
|
||||||
.move_init = NULL,
|
.move_init = NULL,
|
||||||
.free = NULL,
|
.free = NULL,
|
||||||
|
|||||||
434
src/guf_dbuf.h
434
src/guf_dbuf.h
@ -36,93 +36,131 @@
|
|||||||
#define GUF_CNT_NAME GUF_CAT(dbuf_, GUF_CNT_T)
|
#define GUF_CNT_NAME GUF_CAT(dbuf_, GUF_CNT_T)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// TODO: does not work with custom obj_ops_typename
|
|
||||||
// #define GUF_CNT_T_OPS_CPY GUFCAT(GUFCAT(GUF_CNT_T, _ops_type), _cpy)
|
|
||||||
|
|
||||||
typedef struct GUF_CNT_NAME {
|
typedef struct GUF_CNT_NAME {
|
||||||
GUF_CNT_T *data;
|
GUF_CNT_T *data;
|
||||||
ptrdiff_t size, capacity;
|
ptrdiff_t size, capacity;
|
||||||
} GUF_CNT_NAME;
|
} GUF_CNT_NAME;
|
||||||
|
|
||||||
static inline bool GUFCAT(GUF_CNT_NAME, _valid_and_not_empty)(const GUF_CNT_NAME* dbuf)
|
static inline bool GUFCAT(GUF_CNT_NAME, _valid)(const GUF_CNT_NAME* dbuf)
|
||||||
{
|
{
|
||||||
return dbuf && dbuf->data && dbuf->capacity > 0 && dbuf->size > 0 && dbuf->size <= dbuf->capacity;
|
if (!dbuf) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
bool valid_data_ptr = (!dbuf->data && !dbuf->capacity) || (dbuf->data && dbuf->capacity);
|
||||||
|
return valid_data_ptr && dbuf->capacity >= 0 && dbuf->size >= 0 && dbuf->size <= dbuf->capacity;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool GUFCAT(GUF_CNT_NAME, _valid_and_maybe_empty)(const GUF_CNT_NAME* dbuf)
|
bool GUFCAT(GUF_CNT_NAME, _try_reserve)(GUF_CNT_NAME *dbuf, ptrdiff_t min_capacity, guf_err *err)
|
||||||
{
|
{
|
||||||
GUF_ASSERT_RELEASE((!dbuf->data && !dbuf->capacity) || (dbuf->data && dbuf->capacity));
|
GUF_ASSERT_RELEASE(GUFCAT(GUF_CNT_NAME, _valid)(dbuf));
|
||||||
return dbuf && dbuf->capacity >= 0 && dbuf->size >= 0 && dbuf->size <= dbuf->capacity;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool GUFCAT(GUF_CNT_NAME, _reserve)(GUF_CNT_NAME *dbuf, ptrdiff_t min_capacity)
|
|
||||||
{
|
|
||||||
GUF_ASSERT_RELEASE(GUFCAT(GUF_CNT_NAME, _valid_and_maybe_empty)(dbuf));
|
|
||||||
GUF_ASSERT_RELEASE(min_capacity >= 0);
|
GUF_ASSERT_RELEASE(min_capacity >= 0);
|
||||||
|
GUF_ASSERT_RELEASE(err);
|
||||||
|
|
||||||
if (min_capacity <= dbuf->capacity) {
|
if (min_capacity <= dbuf->capacity) {
|
||||||
|
err->type = GUF_ERR_NONE;
|
||||||
|
err->msg = NULL;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!dbuf->data) {
|
if (!dbuf->data) {
|
||||||
GUF_CNT_T *data = calloc(min_capacity, sizeof(GUF_CNT_T));
|
GUF_CNT_T *data = calloc(min_capacity, sizeof(GUF_CNT_T));
|
||||||
GUF_ASSERT(data);
|
|
||||||
if (!data) {
|
if (!data) {
|
||||||
|
err->type = GUF_ERR_ALLOC_FAIL;
|
||||||
|
err->msg = GUF_ERR_MSG("in function dbuf_reserve: Failed to allocate buffer");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
dbuf->data = data;
|
dbuf->data = data;
|
||||||
} else {
|
} else {
|
||||||
GUF_CNT_T *data = realloc(dbuf->data, guf_safe_size_calc(min_capacity, sizeof(GUF_CNT_T)));
|
GUF_CNT_T *data = realloc(dbuf->data, guf_safe_size_calc(min_capacity, sizeof(GUF_CNT_T)));
|
||||||
GUF_ASSERT(data);
|
|
||||||
if (!data) {
|
if (!data) {
|
||||||
|
err->type = GUF_ERR_ALLOC_FAIL;
|
||||||
|
err->msg = GUF_ERR_MSG("in function dbuf_reserve: Failed to re-allocate buffer");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
dbuf->data = data;
|
dbuf->data = data;
|
||||||
}
|
}
|
||||||
dbuf->capacity = min_capacity;
|
dbuf->capacity = min_capacity;
|
||||||
|
err->type = GUF_ERR_NONE;
|
||||||
|
err->msg = NULL;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool GUFCAT(GUF_CNT_NAME, _init)(GUF_CNT_NAME *dbuf, ptrdiff_t start_cap)
|
void GUFCAT(GUF_CNT_NAME, _reserve)(GUF_CNT_NAME *dbuf, ptrdiff_t min_capacity)
|
||||||
|
{
|
||||||
|
guf_err err;
|
||||||
|
GUFCAT(GUF_CNT_NAME, _try_reserve)(dbuf, min_capacity, &err);
|
||||||
|
if (guf_is_err(&err)) {
|
||||||
|
guf_panic(&err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool GUFCAT(GUF_CNT_NAME, _try_init)(GUF_CNT_NAME *dbuf, ptrdiff_t start_cap, guf_err *err)
|
||||||
{
|
{
|
||||||
GUF_ASSERT_RELEASE(dbuf);
|
GUF_ASSERT_RELEASE(dbuf);
|
||||||
|
GUF_ASSERT_RELEASE(err);
|
||||||
GUF_ASSERT_RELEASE(start_cap >= 0);
|
GUF_ASSERT_RELEASE(start_cap >= 0);
|
||||||
|
|
||||||
|
if (dbuf->size != 0 || dbuf->capacity != 0 || dbuf->data) {
|
||||||
|
err->type = GUF_ERR_INVALID_ARG;
|
||||||
|
err->msg = GUF_ERR_MSG("in function dbuf_try_init: dbuf might be already initialised. Set *dbuf to (dbuf){0} before calling this function.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
dbuf->size = dbuf->capacity = 0;
|
dbuf->size = dbuf->capacity = 0;
|
||||||
|
|
||||||
if (start_cap == 0) {
|
if (start_cap == 0) {
|
||||||
dbuf->data = NULL;
|
dbuf->data = NULL;
|
||||||
|
*err = GUF_SUCCESS;
|
||||||
return true;
|
return true;
|
||||||
|
} else {
|
||||||
|
return GUFCAT(GUF_CNT_NAME, _try_reserve)(dbuf, start_cap, err);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool success = GUFCAT(GUF_CNT_NAME, _reserve)(dbuf, start_cap);
|
|
||||||
if (success) {
|
|
||||||
dbuf->capacity = start_cap;
|
|
||||||
}
|
|
||||||
GUF_ASSERT(success);
|
|
||||||
return success;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline GUF_CNT_NAME GUFCAT(GUF_CNT_NAME, _new_with_capacity)(ptrdiff_t start_cap)
|
static inline void GUFCAT(GUF_CNT_NAME, _init)(GUF_CNT_NAME *dbuf, ptrdiff_t start_cap)
|
||||||
{
|
{
|
||||||
GUF_ASSERT_RELEASE(start_cap >= 0);
|
guf_err err;
|
||||||
GUF_CNT_NAME dbuf = {0};
|
GUFCAT(GUF_CNT_NAME, _try_init)(dbuf, start_cap, &err);
|
||||||
bool success = GUFCAT(GUF_CNT_NAME, _init)(&dbuf, start_cap);
|
if (guf_is_err(&err)) {
|
||||||
GUF_ASSERT_RELEASE(success);
|
guf_panic(&err);
|
||||||
return dbuf;
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
GUF_CNT_NAME GUFCAT(GUF_CNT_NAME, _new)(void)
|
GUF_CNT_NAME GUFCAT(GUF_CNT_NAME, _new)(void)
|
||||||
{
|
{
|
||||||
GUF_CNT_NAME dbuf = {0};
|
GUF_CNT_NAME dbuf = {0};
|
||||||
bool success = GUFCAT(GUF_CNT_NAME, _init)(&dbuf, 0);
|
GUFCAT(GUF_CNT_NAME, _init)(&dbuf, 0);
|
||||||
GUF_ASSERT_RELEASE(success);
|
GUF_ASSERT(dbuf.size == 0 && dbuf.capacity == 0);
|
||||||
return dbuf;
|
return dbuf;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline ptrdiff_t GUFCAT(GUF_CNT_NAME, _next_capacity)(ptrdiff_t old_cap)
|
GUF_CNT_NAME GUFCAT(GUF_CNT_NAME, _try_new_with_capacity)(guf_err *err, ptrdiff_t capacity)
|
||||||
|
{
|
||||||
|
GUF_ASSERT_RELEASE(err);
|
||||||
|
GUF_CNT_NAME dbuf = {0};
|
||||||
|
GUFCAT(GUF_CNT_NAME, _try_init)(&dbuf, capacity, err);
|
||||||
|
if (guf_is_err(err)) {
|
||||||
|
return (GUF_CNT_NAME){0};
|
||||||
|
}
|
||||||
|
*err = GUF_SUCCESS;
|
||||||
|
return dbuf;
|
||||||
|
}
|
||||||
|
|
||||||
|
GUF_CNT_NAME GUFCAT(GUF_CNT_NAME, _new_with_capacity)(ptrdiff_t capacity)
|
||||||
|
{
|
||||||
|
guf_err err;
|
||||||
|
GUF_CNT_NAME new_cnt = GUFCAT(GUF_CNT_NAME, _try_new_with_capacity)(&err, capacity);
|
||||||
|
if (guf_is_err(&err)) {
|
||||||
|
guf_panic(&err);
|
||||||
|
}
|
||||||
|
return new_cnt;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline ptrdiff_t GUFCAT(GUF_CNT_NAME, _next_capacity)(ptrdiff_t old_cap, guf_err *err)
|
||||||
{
|
{
|
||||||
GUF_ASSERT_RELEASE(old_cap >= 0);
|
GUF_ASSERT_RELEASE(old_cap >= 0);
|
||||||
|
GUF_ASSERT_RELEASE(err);
|
||||||
size_t new_cap = 0;
|
size_t new_cap = 0;
|
||||||
if (old_cap == 0) {
|
if (old_cap == 0) {
|
||||||
new_cap = GUF_DBUF_INITIAL_CAP;
|
new_cap = GUF_DBUF_INITIAL_CAP;
|
||||||
@ -131,72 +169,135 @@ static inline ptrdiff_t GUFCAT(GUF_CNT_NAME, _next_capacity)(ptrdiff_t old_cap)
|
|||||||
} else {
|
} else {
|
||||||
new_cap = (size_t)old_cap * 3ull / 2ull;
|
new_cap = (size_t)old_cap * 3ull / 2ull;
|
||||||
}
|
}
|
||||||
GUF_ASSERT_RELEASE(new_cap > (size_t)old_cap); // Fail on overflow.
|
|
||||||
GUF_ASSERT_RELEASE(new_cap <= PTRDIFF_MAX);
|
if (new_cap <= (size_t)old_cap || new_cap > PTRDIFF_MAX) { // Detect overflow.
|
||||||
|
err->type = GUF_ERR_INT_OVERFLOW;
|
||||||
|
err->msg = GUF_ERR_MSG("in function dbuf_next_capacity: the next capacity would overflow ptrdiff_t");
|
||||||
|
return -1;
|
||||||
|
} else {
|
||||||
|
err->type = GUF_ERR_NONE;
|
||||||
|
err->msg = NULL;
|
||||||
return new_cap;
|
return new_cap;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static inline bool GUFCAT(GUF_CNT_NAME, _grow_if_full)(GUF_CNT_NAME *dbuf)
|
static inline bool GUFCAT(GUF_CNT_NAME, _grow_if_full)(GUF_CNT_NAME *dbuf, guf_err *err)
|
||||||
{
|
{
|
||||||
GUF_ASSERT_RELEASE(dbuf->capacity >= 0 && dbuf->size >= 0);
|
GUF_ASSERT_RELEASE(dbuf->capacity >= 0 && dbuf->size >= 0);
|
||||||
|
GUF_ASSERT_RELEASE(err);
|
||||||
|
|
||||||
if (dbuf->size == dbuf->capacity) {
|
if (dbuf->size == dbuf->capacity) {
|
||||||
bool success = GUFCAT(GUF_CNT_NAME, _reserve)(dbuf, GUFCAT(GUF_CNT_NAME, _next_capacity)(dbuf->capacity));
|
ptrdiff_t next_cap = GUFCAT(GUF_CNT_NAME, _next_capacity)(dbuf->capacity, err);
|
||||||
if (!success) {
|
if (guf_is_err(err)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
GUF_ASSERT(next_cap > 0);
|
||||||
|
GUFCAT(GUF_CNT_NAME, _try_reserve)(dbuf, next_cap, err);
|
||||||
|
if (guf_is_err(err)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
GUF_ASSERT_RELEASE(dbuf->size < dbuf->capacity);
|
GUF_ASSERT_RELEASE(dbuf->size < dbuf->capacity);
|
||||||
|
err->type = GUF_ERR_NONE;
|
||||||
|
err->msg = NULL;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
GUF_CNT_T *GUFCAT(GUF_CNT_NAME, _push)(GUF_CNT_NAME *dbuf, GUF_CNT_T *elem, guf_obj_cpy_opt cpy_opt)
|
GUF_CNT_T *GUFCAT(GUF_CNT_NAME, _try_push)(GUF_CNT_NAME *dbuf, GUF_CNT_T *elem, guf_obj_cpy_opt cpy_opt, guf_err *err)
|
||||||
{
|
{
|
||||||
GUF_ASSERT_RELEASE(GUFCAT(GUF_CNT_NAME,_valid_and_maybe_empty)(dbuf));
|
GUF_ASSERT(GUFCAT(GUF_CNT_NAME, _valid)(dbuf));
|
||||||
GUF_ASSERT_RELEASE(!(cpy_opt == GUF_CPY_VALUE && GUF_CNT_T_OPS.free)); // Don't allow copy by value if there's a free operation.
|
GUF_ASSERT_RELEASE(err);
|
||||||
|
|
||||||
bool success = GUFCAT(GUF_CNT_NAME, _grow_if_full)(dbuf);
|
if (cpy_opt == GUF_CPY_VALUE && GUF_CNT_T_OPS.free) { // Don't allow copy by value if there's a free operator
|
||||||
GUF_ASSERT(success);
|
if (err) {
|
||||||
if (!success) {
|
err->type = GUF_ERR_INVALID_ARG;
|
||||||
|
err->msg = GUF_ERR_MSG("in function dbuf_try_push: Refusing to copy elem by value (since dbuf has a non-null 'free' operator)");
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
GUFCAT(GUF_CNT_NAME, _grow_if_full)(dbuf, err);
|
||||||
|
if (guf_is_err(err)) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
GUF_CNT_T *dst = dbuf->data + dbuf->size++;
|
GUF_CNT_T *dst = dbuf->data + dbuf->size++;
|
||||||
bool cpy_success = false;
|
bool cpy_success = false;
|
||||||
GUF_OBJ_CPY(GUF_CNT_T, GUF_CNT_T_OPS, dst, elem, cpy_opt, &cpy_success);
|
GUF_OBJ_CPY(GUF_CNT_T, GUF_CNT_T_OPS, dst, elem, cpy_opt, &cpy_success);
|
||||||
GUF_ASSERT(cpy_success);
|
if (!cpy_success) {
|
||||||
if (cpy_success) {
|
err->type = GUF_ERR_ALLOC_FAIL;
|
||||||
return dst;
|
err->msg = GUF_ERR_MSG("in function dbuf_try_push: Failed to copy elem");
|
||||||
} else {
|
|
||||||
return NULL;
|
return NULL;
|
||||||
|
} else {
|
||||||
|
err->type = GUF_ERR_NONE;
|
||||||
|
err->msg = NULL;
|
||||||
|
GUF_ASSERT(dst);
|
||||||
|
return dst;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
GUF_CNT_T *GUFCAT(GUF_CNT_NAME, _push)(GUF_CNT_NAME *dbuf, GUF_CNT_T *elem, guf_obj_cpy_opt cpy_opt)
|
||||||
|
{
|
||||||
|
GUF_ASSERT(GUFCAT(GUF_CNT_NAME, _valid)(dbuf));
|
||||||
|
guf_err err;
|
||||||
|
GUF_CNT_T *pushed = GUFCAT(GUF_CNT_NAME, _try_push)(dbuf, elem, cpy_opt, &err);
|
||||||
|
if (guf_is_err(&err)) {
|
||||||
|
guf_panic(&err);
|
||||||
|
}
|
||||||
|
GUF_ASSERT(pushed);
|
||||||
|
return pushed;
|
||||||
|
}
|
||||||
|
|
||||||
|
GUF_CNT_T *GUFCAT(GUF_CNT_NAME, _try_push_val)(GUF_CNT_NAME *dbuf, GUF_CNT_T elem, guf_err *err)
|
||||||
|
{
|
||||||
|
return GUFCAT(GUF_CNT_NAME, _try_push)(dbuf, &elem, GUF_CPY_VALUE, err);
|
||||||
|
}
|
||||||
|
|
||||||
GUF_CNT_T *GUFCAT(GUF_CNT_NAME, _push_val)(GUF_CNT_NAME *dbuf, GUF_CNT_T elem)
|
GUF_CNT_T *GUFCAT(GUF_CNT_NAME, _push_val)(GUF_CNT_NAME *dbuf, GUF_CNT_T elem)
|
||||||
{
|
{
|
||||||
GUF_ASSERT_RELEASE(!GUF_CNT_T_OPS.free); // Don't allow copy by value if there's a free operation.
|
|
||||||
return GUFCAT(GUF_CNT_NAME, _push)(dbuf, &elem, GUF_CPY_VALUE);
|
return GUFCAT(GUF_CNT_NAME, _push)(dbuf, &elem, GUF_CPY_VALUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GUF_CNT_T *GUFCAT(GUF_CNT_NAME, _try_push_val_cpy)(GUF_CNT_NAME *dbuf, GUF_CNT_T elem, guf_err *err)
|
||||||
|
{
|
||||||
|
return GUFCAT(GUF_CNT_NAME, _try_push)(dbuf, &elem, GUF_CPY_DEEP, err);
|
||||||
|
}
|
||||||
|
|
||||||
GUF_CNT_T *GUFCAT(GUF_CNT_NAME, _push_val_cpy)(GUF_CNT_NAME *dbuf, GUF_CNT_T elem)
|
GUF_CNT_T *GUFCAT(GUF_CNT_NAME, _push_val_cpy)(GUF_CNT_NAME *dbuf, GUF_CNT_T elem)
|
||||||
{
|
{
|
||||||
return GUFCAT(GUF_CNT_NAME, _push)(dbuf, &elem, GUF_CPY_DEEP);
|
return GUFCAT(GUF_CNT_NAME, _push)(dbuf, &elem, GUF_CPY_DEEP);
|
||||||
}
|
}
|
||||||
|
|
||||||
GUF_CNT_T *GUFCAT(GUF_CNT_NAME, _insert)(GUF_CNT_NAME *dbuf, GUF_CNT_T *elem, ptrdiff_t idx, guf_obj_cpy_opt cpy_opt)
|
GUF_CNT_T *GUFCAT(GUF_CNT_NAME, _try_insert)(GUF_CNT_NAME *dbuf, GUF_CNT_T *elem, ptrdiff_t idx, guf_obj_cpy_opt cpy_opt, guf_err *err)
|
||||||
{
|
{
|
||||||
GUF_ASSERT_RELEASE(GUFCAT(GUF_CNT_NAME,_valid_and_maybe_empty)(dbuf));
|
GUF_ASSERT_RELEASE(err);
|
||||||
GUF_ASSERT_RELEASE(idx >= 0 && idx <= dbuf->size);
|
GUF_ASSERT(GUFCAT(GUF_CNT_NAME,_valid)(dbuf));
|
||||||
GUF_ASSERT_RELEASE(!(cpy_opt == GUF_CPY_VALUE && GUF_CNT_T_OPS.free)); // Don't allow copy by value if there's a free operation.
|
|
||||||
|
|
||||||
if (idx == dbuf->size) {
|
if (idx < 0 || idx > dbuf->size) {
|
||||||
return GUFCAT(GUF_CNT_NAME, _push)(dbuf, elem, cpy_opt);
|
if (err) {
|
||||||
|
err->type = GUF_ERR_IDX_RANGE;
|
||||||
|
err->msg = GUF_ERR_MSG("in function dbuf_try_insert");
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
GUF_ASSERT_RELEASE(idx < dbuf->size);
|
if (cpy_opt == GUF_CPY_VALUE && GUF_CNT_T_OPS.free) { // Don't allow copy by value if there's a free operation.
|
||||||
|
if (err) {
|
||||||
|
err->type = GUF_ERR_INVALID_ARG;
|
||||||
|
err->msg = GUF_ERR_MSG("in function dbuf_try_insert: Refusing to copy elem by value (since dbuf has a non-null 'free' operator)");
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
bool success = GUFCAT(GUF_CNT_NAME, _grow_if_full)(dbuf);
|
if (idx == dbuf->size) {
|
||||||
GUF_ASSERT(success);
|
return GUFCAT(GUF_CNT_NAME, _try_push)(dbuf, elem, cpy_opt, err);
|
||||||
if (!success) {
|
}
|
||||||
|
GUF_ASSERT(idx < dbuf->size);
|
||||||
|
|
||||||
|
GUFCAT(GUF_CNT_NAME, _grow_if_full)(dbuf, err);
|
||||||
|
if (guf_is_err(err)) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -209,20 +310,50 @@ GUF_CNT_T *GUFCAT(GUF_CNT_NAME, _insert)(GUF_CNT_NAME *dbuf, GUF_CNT_T *elem, pt
|
|||||||
GUF_CNT_T *dst = dbuf->data + idx;
|
GUF_CNT_T *dst = dbuf->data + idx;
|
||||||
bool cpy_success = false;
|
bool cpy_success = false;
|
||||||
GUF_OBJ_CPY(GUF_CNT_T, GUF_CNT_T_OPS, dst, elem, cpy_opt, &cpy_success)
|
GUF_OBJ_CPY(GUF_CNT_T, GUF_CNT_T_OPS, dst, elem, cpy_opt, &cpy_success)
|
||||||
GUF_ASSERT(cpy_success);
|
|
||||||
|
|
||||||
if (cpy_success) {
|
if (!cpy_success) {
|
||||||
return dst;
|
if (err) {
|
||||||
} else {
|
err->type = GUF_ERR_ALLOC_FAIL;
|
||||||
|
err->msg = GUF_ERR_MSG("in function dbuf_try_insert: Failed to copy elem");
|
||||||
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (err) {
|
||||||
|
err->type = GUF_ERR_NONE;
|
||||||
|
err->msg = NULL;
|
||||||
|
}
|
||||||
|
GUF_ASSERT(dst != NULL)
|
||||||
|
return dst;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GUFCAT(GUF_CNT_NAME, _erase)(GUF_CNT_NAME *dbuf, ptrdiff_t idx)
|
GUF_CNT_T *GUFCAT(GUF_CNT_NAME, _insert)(GUF_CNT_NAME *dbuf, GUF_CNT_T *elem, ptrdiff_t idx, guf_obj_cpy_opt cpy_opt)
|
||||||
{
|
{
|
||||||
GUF_ASSERT_RELEASE(GUFCAT(GUF_CNT_NAME, _valid_and_not_empty)(dbuf));
|
guf_err err;
|
||||||
GUF_ASSERT_RELEASE(idx >= 0);
|
GUF_CNT_T *inserted = GUFCAT(GUF_CNT_NAME, _try_insert)(dbuf, elem, idx, cpy_opt, &err);
|
||||||
GUF_ASSERT_RELEASE(idx < dbuf->size);
|
if (guf_is_err(&err)) {
|
||||||
|
guf_panic(&err);
|
||||||
|
}
|
||||||
|
GUF_ASSERT(inserted);
|
||||||
|
return inserted;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GUFCAT(GUF_CNT_NAME, _try_erase)(GUF_CNT_NAME *dbuf, ptrdiff_t idx, guf_err *err)
|
||||||
|
{
|
||||||
|
GUF_ASSERT_RELEASE(GUFCAT(GUF_CNT_NAME, _valid)(dbuf));
|
||||||
|
GUF_ASSERT_RELEASE(err);
|
||||||
|
|
||||||
|
if (dbuf->size == 0) {
|
||||||
|
err->type = GUF_ERR_IDX_RANGE,
|
||||||
|
err->msg = GUF_ERR_MSG("in function dbuf_try_erase: cannot erase from empty buffer");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (idx < 0 || idx >= dbuf->size) {
|
||||||
|
err->type = GUF_ERR_IDX_RANGE;
|
||||||
|
err->msg = GUF_ERR_MSG("in function dbuf_try_erase");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (GUF_CNT_T_OPS.free) {
|
if (GUF_CNT_T_OPS.free) {
|
||||||
GUF_CNT_T_OPS.free(dbuf->data + idx);
|
GUF_CNT_T_OPS.free(dbuf->data + idx);
|
||||||
@ -233,54 +364,179 @@ void GUFCAT(GUF_CNT_NAME, _erase)(GUF_CNT_NAME *dbuf, ptrdiff_t idx)
|
|||||||
GUF_CNT_T *src = dst + 1;
|
GUF_CNT_T *src = dst + 1;
|
||||||
*dst = *src;
|
*dst = *src;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
*err = GUF_SUCCESS;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GUFCAT(GUF_CNT_NAME, pop)(GUF_CNT_NAME *dbuf)
|
void GUFCAT(GUF_CNT_NAME, _erase)(GUF_CNT_NAME *dbuf, ptrdiff_t idx)
|
||||||
{
|
{
|
||||||
GUF_ASSERT_RELEASE(GUFCAT(GUF_CNT_NAME, _valid_and_not_empty)(dbuf));
|
guf_err err;
|
||||||
|
GUFCAT(GUF_CNT_NAME, _try_erase)(dbuf, idx, &err);
|
||||||
|
if (guf_is_err(&err)) {
|
||||||
|
guf_panic(&err);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GUFCAT(GUF_CNT_NAME, _try_pop)(GUF_CNT_NAME *dbuf, guf_err *err)
|
||||||
|
{
|
||||||
|
GUF_ASSERT_RELEASE(GUFCAT(GUF_CNT_NAME, _valid)(dbuf));
|
||||||
|
GUF_ASSERT_RELEASE(err);
|
||||||
|
|
||||||
|
if (dbuf->size == 0) {
|
||||||
|
err->type = GUF_ERR_IDX_RANGE;
|
||||||
|
err->msg = GUF_ERR_MSG("in function dbuf_try_pop: Cannot pop from empty dbuf");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
GUF_CNT_T *popped = dbuf->data + --dbuf->size;
|
GUF_CNT_T *popped = dbuf->data + --dbuf->size;
|
||||||
if (GUF_CNT_T_OPS.free) {
|
if (GUF_CNT_T_OPS.free) {
|
||||||
GUF_CNT_T_OPS.free(popped);
|
GUF_CNT_T_OPS.free(popped);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
*err = GUF_SUCCESS;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
GUF_CNT_T GUFCAT(GUF_CNT_NAME, pop_cpy)(GUF_CNT_NAME *dbuf, guf_obj_cpy_opt cpy_opt)
|
void GUFCAT(GUF_CNT_NAME, _pop)(GUF_CNT_NAME *dbuf)
|
||||||
{
|
{
|
||||||
GUF_ASSERT_RELEASE(GUFCAT(GUF_CNT_NAME, _valid_and_not_empty)(dbuf));
|
guf_err err;
|
||||||
GUF_CNT_T *popped = dbuf->data + --dbuf->size;
|
GUFCAT(GUF_CNT_NAME, _try_pop)(dbuf, &err);
|
||||||
|
if (guf_is_err(&err)) {
|
||||||
|
guf_panic(&err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
GUF_CNT_T GUFCAT(GUF_CNT_NAME, _try_pop_cpy)(GUF_CNT_NAME *dbuf, guf_obj_cpy_opt cpy_opt, guf_err *err)
|
||||||
|
{
|
||||||
|
GUF_ASSERT_RELEASE(GUFCAT(GUF_CNT_NAME, _valid)(dbuf));
|
||||||
|
GUF_ASSERT_RELEASE(err);
|
||||||
|
|
||||||
|
if (dbuf->size == 0) {
|
||||||
|
err->type = GUF_ERR_IDX_RANGE;
|
||||||
|
err->msg = GUF_ERR_MSG("in function dbuf_try_pop_cpy: Cannot pop from empty dbuf");
|
||||||
|
GUF_CNT_T dummy = GUF_CNT_T_OPS.default_value;
|
||||||
|
return dummy;
|
||||||
|
}
|
||||||
|
|
||||||
|
GUF_CNT_T *popped = dbuf->data + (dbuf->size - 1);
|
||||||
GUF_CNT_T popped_val;
|
GUF_CNT_T popped_val;
|
||||||
bool success = false;
|
|
||||||
GUF_OBJ_CPY(GUF_CNT_T, GUF_CNT_T_OPS, &popped_val, popped, cpy_opt, &success);
|
bool cpy_success = false;
|
||||||
GUF_ASSERT_RELEASE(success);
|
GUF_OBJ_CPY(GUF_CNT_T, GUF_CNT_T_OPS, &popped_val, popped, cpy_opt, &cpy_success);
|
||||||
|
if (!cpy_success) {
|
||||||
|
err->type = GUF_ERR_ALLOC_FAIL;
|
||||||
|
err->msg = GUF_ERR_MSG("in function dbuf_try_pop_cpy: Failed on copy");
|
||||||
|
GUF_CNT_T dummy = GUF_CNT_T_OPS.default_value;
|
||||||
|
return dummy;
|
||||||
|
} else {
|
||||||
|
dbuf->size -= 1;
|
||||||
|
}
|
||||||
|
|
||||||
if (cpy_opt == GUF_CPY_DEEP && GUF_CNT_T_OPS.free) {
|
if (cpy_opt == GUF_CPY_DEEP && GUF_CNT_T_OPS.free) {
|
||||||
GUF_CNT_T_OPS.free(popped);
|
GUF_CNT_T_OPS.free(popped);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
*err = GUF_SUCCESS;
|
||||||
return popped_val;
|
return popped_val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GUF_CNT_T GUFCAT(GUF_CNT_NAME, _pop_cpy)(GUF_CNT_NAME *dbuf, guf_obj_cpy_opt cpy_opt)
|
||||||
|
{
|
||||||
|
guf_err err;
|
||||||
|
GUF_CNT_T popped = GUFCAT(GUF_CNT_NAME, _try_pop_cpy)(dbuf, cpy_opt, &err);
|
||||||
|
if (guf_is_err(&err)) {
|
||||||
|
guf_panic(&err);
|
||||||
|
}
|
||||||
|
return popped;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
GUF_CNT_T *GUFCAT(GUF_CNT_NAME, _try_at)(GUF_CNT_NAME *dbuf, ptrdiff_t idx, guf_err *err)
|
||||||
|
{
|
||||||
|
GUF_ASSERT_RELEASE(GUFCAT(GUF_CNT_NAME, _valid)(dbuf));
|
||||||
|
GUF_ASSERT(err);
|
||||||
|
if (dbuf->size == 0) {
|
||||||
|
err->type = GUF_ERR_IDX_RANGE;
|
||||||
|
err->msg = GUF_ERR_MSG("in function dbuf_try_at: dbuf is empty");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (idx < 0 || idx >= dbuf->size) {
|
||||||
|
err->type = GUF_ERR_IDX_RANGE;
|
||||||
|
err->msg = GUF_ERR_MSG("in function dbuf_try_at");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
GUF_ASSERT(dbuf->data);
|
||||||
|
*err = GUF_SUCCESS;
|
||||||
|
return dbuf->data + idx;
|
||||||
|
}
|
||||||
|
|
||||||
GUF_CNT_T *GUFCAT(GUF_CNT_NAME, _at)(GUF_CNT_NAME *dbuf, ptrdiff_t idx)
|
GUF_CNT_T *GUFCAT(GUF_CNT_NAME, _at)(GUF_CNT_NAME *dbuf, ptrdiff_t idx)
|
||||||
{
|
{
|
||||||
GUF_ASSERT_RELEASE(GUFCAT(GUF_CNT_NAME, _valid_and_not_empty)(dbuf));
|
guf_err err;
|
||||||
GUF_ASSERT_RELEASE(idx >= 0 && idx < dbuf->size)
|
GUF_CNT_T *res = GUFCAT(GUF_CNT_NAME, _try_at)(dbuf, idx, &err);
|
||||||
return dbuf->data + idx;
|
if (guf_is_err(&err)) {
|
||||||
|
guf_panic(&err);
|
||||||
|
}
|
||||||
|
GUF_ASSERT(res);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
GUF_CNT_T *GUFCAT(GUF_CNT_NAME, _try_front)(GUF_CNT_NAME *dbuf, guf_err *err)
|
||||||
|
{
|
||||||
|
GUF_ASSERT_RELEASE(GUFCAT(GUF_CNT_NAME, _valid)(dbuf));
|
||||||
|
GUF_ASSERT_RELEASE(err);
|
||||||
|
|
||||||
|
if (dbuf->size == 0) {
|
||||||
|
err->type = GUF_ERR_IDX_RANGE;
|
||||||
|
err->msg = GUF_ERR_MSG("in function dbuf_front: dbuf is empty");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return dbuf->data + 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
GUF_CNT_T *GUFCAT(GUF_CNT_NAME, _front)(GUF_CNT_NAME *dbuf)
|
GUF_CNT_T *GUFCAT(GUF_CNT_NAME, _front)(GUF_CNT_NAME *dbuf)
|
||||||
{
|
{
|
||||||
GUF_ASSERT_RELEASE(GUFCAT(GUF_CNT_NAME, _valid_and_not_empty)(dbuf));
|
guf_err err;
|
||||||
return dbuf->data + 0;
|
GUF_CNT_T *res = GUFCAT(GUF_CNT_NAME, _try_front)(dbuf, &err);
|
||||||
|
if (guf_is_err(&err)) {
|
||||||
|
guf_panic(&err);
|
||||||
}
|
}
|
||||||
GUF_CNT_T *GUFCAT(GUF_CNT_NAME, back)(GUF_CNT_NAME *dbuf)
|
GUF_ASSERT(res);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
GUF_CNT_T *GUFCAT(GUF_CNT_NAME, _try_back)(GUF_CNT_NAME *dbuf, guf_err *err)
|
||||||
{
|
{
|
||||||
GUF_ASSERT_RELEASE(GUFCAT(GUF_CNT_NAME, _valid_and_not_empty)(dbuf));
|
GUF_ASSERT_RELEASE(GUFCAT(GUF_CNT_NAME, _valid)(dbuf));
|
||||||
|
GUF_ASSERT_RELEASE(err);
|
||||||
|
|
||||||
|
if (dbuf->size == 0) {
|
||||||
|
err->type = GUF_ERR_IDX_RANGE;
|
||||||
|
err->msg = GUF_ERR_MSG("in function dbuf_try_back: dbuf is empty");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
*err = GUF_SUCCESS;
|
||||||
return dbuf->data + (dbuf->size - 1);
|
return dbuf->data + (dbuf->size - 1);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GUFCAT(GUF_CNT_NAME, _shrink_to_fit)(GUF_CNT_NAME *dbuf)
|
GUF_CNT_T *GUFCAT(GUF_CNT_NAME, _back)(GUF_CNT_NAME *dbuf)
|
||||||
{
|
{
|
||||||
GUF_ASSERT_RELEASE(GUFCAT(GUF_CNT_NAME, _valid_and_maybe_empty)(dbuf));
|
guf_err err;
|
||||||
|
GUF_CNT_T *res = GUFCAT(GUF_CNT_NAME, _try_back)(dbuf, &err);
|
||||||
|
if (guf_is_err(&err)) {
|
||||||
|
guf_panic(&err);
|
||||||
|
}
|
||||||
|
GUF_ASSERT(res);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GUFCAT(GUF_CNT_NAME, _try_shrink_to_fit)(GUF_CNT_NAME *dbuf)
|
||||||
|
{
|
||||||
|
GUF_ASSERT_RELEASE(GUFCAT(GUF_CNT_NAME, _valid)(dbuf));
|
||||||
const ptrdiff_t new_capacity = dbuf->size;
|
const ptrdiff_t new_capacity = dbuf->size;
|
||||||
if (new_capacity == dbuf->capacity) {
|
if (new_capacity == dbuf->capacity) {
|
||||||
return true;
|
return true;
|
||||||
@ -300,7 +556,7 @@ bool GUFCAT(GUF_CNT_NAME, _shrink_to_fit)(GUF_CNT_NAME *dbuf)
|
|||||||
|
|
||||||
void GUFCAT(GUF_CNT_NAME, _free)(GUF_CNT_NAME *dbuf)
|
void GUFCAT(GUF_CNT_NAME, _free)(GUF_CNT_NAME *dbuf)
|
||||||
{
|
{
|
||||||
GUF_ASSERT_RELEASE(GUFCAT(GUF_CNT_NAME, _valid_and_maybe_empty)(dbuf));
|
GUF_ASSERT_RELEASE(GUFCAT(GUF_CNT_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);
|
||||||
@ -319,7 +575,7 @@ void GUFCAT(GUF_CNT_NAME, _free)(GUF_CNT_NAME *dbuf)
|
|||||||
|
|
||||||
void GUFCAT(GUF_CNT_NAME, _sort)(GUF_CNT_NAME *dbuf, guf_sort_opt sort_opt)
|
void GUFCAT(GUF_CNT_NAME, _sort)(GUF_CNT_NAME *dbuf, guf_sort_opt sort_opt)
|
||||||
{
|
{
|
||||||
GUF_ASSERT_RELEASE(GUFCAT(GUF_CNT_NAME, _valid_and_maybe_empty)(dbuf));
|
GUF_ASSERT_RELEASE(GUFCAT(GUF_CNT_NAME, _valid)(dbuf));
|
||||||
|
|
||||||
if (dbuf->size == 0) {
|
if (dbuf->size == 0) {
|
||||||
return;
|
return;
|
||||||
@ -358,9 +614,9 @@ static inline GUFCAT(GUF_CNT_NAME, _iter) GUFCAT(GUF_CNT_NAME, _iter_next)(const
|
|||||||
} else if (next_ptr < (intptr_t)it->begin) { // TODO: different end for begin
|
} else if (next_ptr < (intptr_t)it->begin) { // TODO: different end for begin
|
||||||
next_it.cur = it->end;
|
next_it.cur = it->end;
|
||||||
} else {
|
} else {
|
||||||
GUF_ASSERT_RELEASE(next_ptr >= (intptr_t)it->begin);
|
GUF_ASSERT(next_ptr >= (intptr_t)it->begin);
|
||||||
GUF_ASSERT_RELEASE(next_ptr <= (intptr_t)it->end);
|
GUF_ASSERT(next_ptr <= (intptr_t)it->end);
|
||||||
GUF_ASSERT_RELEASE(it->cur + step >= it->begin && it->cur + step <= it->end);
|
GUF_ASSERT(it->cur + step >= it->begin && it->cur + step <= it->end);
|
||||||
next_it.cur = it->cur + step;
|
next_it.cur = it->cur + step;
|
||||||
}
|
}
|
||||||
return next_it;
|
return next_it;
|
||||||
@ -368,7 +624,7 @@ static inline GUFCAT(GUF_CNT_NAME, _iter) GUFCAT(GUF_CNT_NAME, _iter_next)(const
|
|||||||
|
|
||||||
static inline GUFCAT(GUF_CNT_NAME, _iter) GUFCAT(GUF_CNT_NAME, _begin)(const GUF_CNT_NAME* dbuf)
|
static inline GUFCAT(GUF_CNT_NAME, _iter) GUFCAT(GUF_CNT_NAME, _begin)(const GUF_CNT_NAME* dbuf)
|
||||||
{
|
{
|
||||||
GUFCAT(GUF_CNT_NAME, _valid_and_maybe_empty)(dbuf);
|
GUFCAT(GUF_CNT_NAME, _valid)(dbuf);
|
||||||
return (GUFCAT(GUF_CNT_NAME, _iter)) {
|
return (GUFCAT(GUF_CNT_NAME, _iter)) {
|
||||||
.cur = dbuf->data,
|
.cur = dbuf->data,
|
||||||
.begin = dbuf->data,
|
.begin = dbuf->data,
|
||||||
@ -379,7 +635,7 @@ static inline GUFCAT(GUF_CNT_NAME, _iter) GUFCAT(GUF_CNT_NAME, _begin)(const GUF
|
|||||||
|
|
||||||
static inline GUFCAT(GUF_CNT_NAME, _iter) GUFCAT(GUF_CNT_NAME, _end)(const GUF_CNT_NAME* dbuf)
|
static inline GUFCAT(GUF_CNT_NAME, _iter) GUFCAT(GUF_CNT_NAME, _end)(const GUF_CNT_NAME* dbuf)
|
||||||
{
|
{
|
||||||
GUFCAT(GUF_CNT_NAME, _valid_and_maybe_empty)(dbuf);
|
GUFCAT(GUF_CNT_NAME, _valid)(dbuf);
|
||||||
return (GUFCAT(GUF_CNT_NAME, _iter)) {
|
return (GUFCAT(GUF_CNT_NAME, _iter)) {
|
||||||
.cur = dbuf->data ? dbuf->data + dbuf->size : NULL,
|
.cur = dbuf->data ? dbuf->data + dbuf->size : NULL,
|
||||||
.begin = dbuf->data,
|
.begin = dbuf->data,
|
||||||
|
|||||||
@ -1,65 +0,0 @@
|
|||||||
#include "guf_int.h"
|
|
||||||
|
|
||||||
#define GUF_DEFINE_INTEGER_CMP(int_type, fn_name) \
|
|
||||||
int fn_name(const int_type *a, const int_type *b) {GUF_ASSERT(a && b); return (*a == *b ? 0 : *a < *b ? -1 : 1);} \
|
|
||||||
GUF_OBJ_OPS_DEFINE_CMP_VOID(int_type, fn_name) \
|
|
||||||
GUF_OBJ_OPS_DEFINE_CMP_VOID_INV(int_type, fn_name)
|
|
||||||
|
|
||||||
#define GUF_DEFINE_INTEGER_OPS(int_type)\
|
|
||||||
const GUFCAT(int_type, _ops_type) GUFCAT(int_type, _ops) = {\
|
|
||||||
.cmp = GUFCAT(int_type, _cmp),\
|
|
||||||
.cmp_void = GUFCAT(int_type, _cmp_void), \
|
|
||||||
.cmp_void_inv = GUFCAT(int_type, _cmp_void_inv), \
|
|
||||||
.eq = NULL, \
|
|
||||||
.copy_init = NULL,\
|
|
||||||
.move_init = NULL,\
|
|
||||||
.free = NULL\
|
|
||||||
};\
|
|
||||||
|
|
||||||
GUF_DEFINE_INTEGER_CMP(int, guf_int_cmp)
|
|
||||||
GUF_DEFINE_INTEGER_CMP(short, guf_short_cmp)
|
|
||||||
GUF_DEFINE_INTEGER_CMP(long, guf_long_cmp)
|
|
||||||
GUF_DEFINE_INTEGER_CMP(long long, guf_long_long_cmp)
|
|
||||||
GUF_DEFINE_INTEGER_CMP(int8_t, guf_int8_t_cmp)
|
|
||||||
GUF_DEFINE_INTEGER_CMP(int16_t, guf_int16_t_cmp)
|
|
||||||
GUF_DEFINE_INTEGER_CMP(int32_t, guf_int32_t_cmp)
|
|
||||||
GUF_DEFINE_INTEGER_CMP(int64_t, guf_int64_t_cmp)
|
|
||||||
GUF_DEFINE_INTEGER_CMP(ptrdiff_t, guf_ptrdiff_t_cmp)
|
|
||||||
|
|
||||||
GUF_DEFINE_INTEGER_CMP(unsigned, guf_unsigned_cmp)
|
|
||||||
GUF_DEFINE_INTEGER_CMP(unsigned short, guf_unsigned_short_cmp)
|
|
||||||
GUF_DEFINE_INTEGER_CMP(unsigned long, guf_unsigned_long_cmp)
|
|
||||||
GUF_DEFINE_INTEGER_CMP(unsigned long long, guf_unsigned_long_long_cmp)
|
|
||||||
GUF_DEFINE_INTEGER_CMP(uint8_t, guf_uint8_t_cmp)
|
|
||||||
GUF_DEFINE_INTEGER_CMP(uint16_t, guf_uint16_t_cmp)
|
|
||||||
GUF_DEFINE_INTEGER_CMP(uint32_t, guf_uint32_t_cmp)
|
|
||||||
GUF_DEFINE_INTEGER_CMP(uint64_t, guf_uint64_t_cmp)
|
|
||||||
GUF_DEFINE_INTEGER_CMP(size_t, guf_size_t_cmp)
|
|
||||||
|
|
||||||
GUF_DEFINE_INTEGER_CMP(char, guf_char_cmp)
|
|
||||||
GUF_DEFINE_INTEGER_CMP(unsigned char, guf_unsigned_char_cmp)
|
|
||||||
|
|
||||||
GUF_DEFINE_INTEGER_CMP(float, guf_float_cmp)
|
|
||||||
GUF_DEFINE_INTEGER_CMP(double, guf_double_cmp)
|
|
||||||
|
|
||||||
GUF_DEFINE_INTEGER_OPS(guf_int)
|
|
||||||
GUF_DEFINE_INTEGER_OPS(guf_short)
|
|
||||||
GUF_DEFINE_INTEGER_OPS(guf_long_long)
|
|
||||||
GUF_DEFINE_INTEGER_OPS(guf_int8_t)
|
|
||||||
GUF_DEFINE_INTEGER_OPS(guf_int16_t)
|
|
||||||
GUF_DEFINE_INTEGER_OPS(guf_int32_t)
|
|
||||||
GUF_DEFINE_INTEGER_OPS(guf_int64_t)
|
|
||||||
|
|
||||||
GUF_DEFINE_INTEGER_OPS(guf_unsigned)
|
|
||||||
GUF_DEFINE_INTEGER_OPS(guf_unsigned_short)
|
|
||||||
GUF_DEFINE_INTEGER_OPS(guf_unsigned_long_long)
|
|
||||||
GUF_DEFINE_INTEGER_OPS(guf_uint8_t)
|
|
||||||
GUF_DEFINE_INTEGER_OPS(guf_uint16_t)
|
|
||||||
GUF_DEFINE_INTEGER_OPS(guf_uint32_t)
|
|
||||||
GUF_DEFINE_INTEGER_OPS(guf_uint64_t)
|
|
||||||
|
|
||||||
GUF_DEFINE_INTEGER_OPS(guf_char)
|
|
||||||
GUF_DEFINE_INTEGER_OPS(guf_unsigned_char)
|
|
||||||
|
|
||||||
GUF_DEFINE_INTEGER_OPS(guf_float)
|
|
||||||
GUF_DEFINE_INTEGER_OPS(guf_double)
|
|
||||||
199
src/guf_int.h
199
src/guf_int.h
@ -2,6 +2,80 @@
|
|||||||
#define GUF_INT_H
|
#define GUF_INT_H
|
||||||
#include "guf_common.h"
|
#include "guf_common.h"
|
||||||
|
|
||||||
|
#define GUF_MIN(X, Y) ((X) <= (Y) ? (X) : (Y))
|
||||||
|
#define GUF_MAX(X, Y) ((X) >= (Y) ? (X) : (Y))
|
||||||
|
#define GUF_CLAMP(X, MIN, MAX) GUF_MAX(GUF_MIN((X), (MAX)), (MIN))
|
||||||
|
|
||||||
|
#define GUF_DEFINE_MIN_MAX_CLAMP(int_type, int_type_name)\
|
||||||
|
static inline int_type GUFCAT(guf_min_, int_type_name)(int_type a, int_type b) {return a >= b ? a : b;}\
|
||||||
|
static inline int_type GUFCAT(guf_max_, int_type_name)(int_type a, int_type b) {return a >= b ? a : b;}\
|
||||||
|
static inline int_type GUFCAT(guf_clamp_, int_type_name)(int_type x, int_type min, int_type max) {return GUFCAT(guf_max_, int_type_name)(GUFCAT(guf_min_, int_type_name)(x, max), min);}
|
||||||
|
|
||||||
|
GUF_DEFINE_MIN_MAX_CLAMP(int, int)
|
||||||
|
GUF_DEFINE_MIN_MAX_CLAMP(short, short)
|
||||||
|
GUF_DEFINE_MIN_MAX_CLAMP(long, long)
|
||||||
|
GUF_DEFINE_MIN_MAX_CLAMP(long long, long_long)
|
||||||
|
GUF_DEFINE_MIN_MAX_CLAMP(int8_t, i8)
|
||||||
|
GUF_DEFINE_MIN_MAX_CLAMP(int16_t, i16)
|
||||||
|
GUF_DEFINE_MIN_MAX_CLAMP(int32_t, i32)
|
||||||
|
GUF_DEFINE_MIN_MAX_CLAMP(int64_t, i64)
|
||||||
|
|
||||||
|
GUF_DEFINE_MIN_MAX_CLAMP(unsigned, unsigned)
|
||||||
|
GUF_DEFINE_MIN_MAX_CLAMP(unsigned short, unsigned_short)
|
||||||
|
GUF_DEFINE_MIN_MAX_CLAMP(unsigned long, unsigned_long)
|
||||||
|
GUF_DEFINE_MIN_MAX_CLAMP(unsigned long long, unsigned_long_long)
|
||||||
|
GUF_DEFINE_MIN_MAX_CLAMP(uint8_t, u8)
|
||||||
|
GUF_DEFINE_MIN_MAX_CLAMP(uint16_t, u16)
|
||||||
|
GUF_DEFINE_MIN_MAX_CLAMP(uint32_t, u32)
|
||||||
|
GUF_DEFINE_MIN_MAX_CLAMP(uint64_t, u64)
|
||||||
|
|
||||||
|
GUF_DEFINE_MIN_MAX_CLAMP(char, guf_char)
|
||||||
|
GUF_DEFINE_MIN_MAX_CLAMP(unsigned char, guf_unsigned_char)
|
||||||
|
|
||||||
|
#undef GUF_DEFINE_MIN_MAX_CLAMP
|
||||||
|
|
||||||
|
static inline int guf_int(int x) {if (x >= 0) {return x;} GUF_ASSERT_RELEASE(x > INT_MIN ); return -x;}
|
||||||
|
static inline long guf_abs_long(long x) {if (x >= 0) {return x;} GUF_ASSERT_RELEASE(x > LONG_MIN ); return -x;}
|
||||||
|
static inline long long guf_abs_long_long(long long x) {if (x >= 0) {return x;} GUF_ASSERT_RELEASE(x > LLONG_MIN ); return -x;}
|
||||||
|
static inline int8_t guf_abs_i8 (int8_t x) {if (x >= 0) {return x;} GUF_ASSERT_RELEASE(x > INT8_MIN ); return -x;}
|
||||||
|
static inline int16_t guf_abs_i16(int16_t x) {if (x >= 0) {return x;} GUF_ASSERT_RELEASE(x > INT16_MIN); return -x;}
|
||||||
|
static inline int32_t guf_abs_i32(int32_t x) {if (x >= 0) {return x;} GUF_ASSERT_RELEASE(x > INT32_MIN); return -x;}
|
||||||
|
static inline int64_t guf_abs_i64(int64_t x) {if (x >= 0) {return x;} GUF_ASSERT_RELEASE(x > INT64_MIN); return -x;}
|
||||||
|
static inline ptrdiff_t guf_abs_ptrdiff(ptrdiff_t x) {if (x >= 0) {return x;} GUF_ASSERT_RELEASE(x > PTRDIFF_MIN); return -x;}
|
||||||
|
|
||||||
|
static inline bool guf_is_mul_overflow_size_t(size_t a, size_t b)
|
||||||
|
{
|
||||||
|
size_t c = a * b;
|
||||||
|
return a != 0 && ((c / a) != b);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline size_t guf_safe_mul_size_t(size_t a, size_t b)
|
||||||
|
{
|
||||||
|
GUF_ASSERT_RELEASE(!guf_is_mul_overflow_size_t(a, b));
|
||||||
|
return a * b;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool guf_is_safe_size_calc(ptrdiff_t count, ptrdiff_t sizeof_elem)
|
||||||
|
{
|
||||||
|
if (count < 0 || sizeof_elem <= 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (guf_is_mul_overflow_size_t(count, sizeof_elem)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
size_t size = (size_t)count * (size_t)sizeof_elem;
|
||||||
|
return size <= PTRDIFF_MAX;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline ptrdiff_t guf_safe_size_calc(ptrdiff_t count, ptrdiff_t sizeof_elem)
|
||||||
|
{
|
||||||
|
GUF_ASSERT_RELEASE(count >= 0);
|
||||||
|
GUF_ASSERT_RELEASE(sizeof_elem > 0);
|
||||||
|
size_t size = guf_safe_mul_size_t(count, sizeof_elem);
|
||||||
|
GUF_ASSERT_RELEASE(size <= PTRDIFF_MAX);
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
// Signed integer types:
|
// Signed integer types:
|
||||||
|
|
||||||
#define GUF_OBJ_TYPE int
|
#define GUF_OBJ_TYPE int
|
||||||
@ -124,79 +198,76 @@ extern const guf_unsigned_char_ops_type guf_unsigned_char_ops;
|
|||||||
extern const guf_float_ops_type guf_float_ops;
|
extern const guf_float_ops_type guf_float_ops;
|
||||||
extern const guf_double_ops_type guf_double_ops;
|
extern const guf_double_ops_type guf_double_ops;
|
||||||
|
|
||||||
// #define GUF_ABS(X) ((X) >= 0 ? (X) : -(X))
|
#ifdef GUF_IMPLEMENTATION
|
||||||
// #define GUF_MIN(X, Y) ((X) <= (Y) ? (X) : (Y))
|
|
||||||
// #define GUF_MAX(X, Y) ((X) >= (Y) ? (X) : (Y))
|
|
||||||
// #define GUF_CLAMP(X, MIN, MAX) GUF_MAX(GUF_MIN((X), (MAX)), (MIN))
|
|
||||||
|
|
||||||
#define GUF_DEFINE_MIN_MAX_CLAMP(int_type, int_type_name)\
|
#define GUF_DEFINE_INTEGER_CMP(int_type, fn_name) \
|
||||||
static inline int_type GUFCAT(int_type_name, _min)(int_type a, int_type b) {return a >= b ? a : b;}\
|
int fn_name(const int_type *a, const int_type *b) {GUF_ASSERT(a && b); return (*a == *b ? 0 : *a < *b ? -1 : 1);} \
|
||||||
static inline int_type GUFCAT(int_type_name, _max)(int_type a, int_type b) {return a >= b ? a : b;}\
|
GUF_OBJ_OPS_DEFINE_CMP_VOID(int_type, fn_name) \
|
||||||
static inline int_type GUFCAT(int_type_name, _clamp)(int_type x, int_type min, int_type max) {return GUFCAT(int_type_name, _max)(GUFCAT(int_type_name, _min)(x, max), min);}
|
GUF_OBJ_OPS_DEFINE_CMP_VOID_INV(int_type, fn_name)
|
||||||
|
|
||||||
GUF_DEFINE_MIN_MAX_CLAMP(int, guf_int)
|
#define GUF_DEFINE_INTEGER_OPS(int_type)\
|
||||||
GUF_DEFINE_MIN_MAX_CLAMP(short, guf_short)
|
const GUFCAT(int_type, _ops_type) GUFCAT(int_type, _ops) = {\
|
||||||
GUF_DEFINE_MIN_MAX_CLAMP(long, guf_long)
|
.cmp = GUFCAT(int_type, _cmp),\
|
||||||
GUF_DEFINE_MIN_MAX_CLAMP(long long, guf_long_long)
|
.cmp_void = GUFCAT(int_type, _cmp_void), \
|
||||||
GUF_DEFINE_MIN_MAX_CLAMP(int8_t, guf_int8_t)
|
.cmp_void_inv = GUFCAT(int_type, _cmp_void_inv), \
|
||||||
GUF_DEFINE_MIN_MAX_CLAMP(int16_t, guf_int16_t)
|
.default_value = 0,\
|
||||||
GUF_DEFINE_MIN_MAX_CLAMP(int32_t, guf_int32_t)
|
.eq = NULL, \
|
||||||
GUF_DEFINE_MIN_MAX_CLAMP(int64_t, guf_int64_t)
|
.copy_init = NULL,\
|
||||||
|
.move_init = NULL,\
|
||||||
|
.free = NULL\
|
||||||
|
};\
|
||||||
|
|
||||||
GUF_DEFINE_MIN_MAX_CLAMP(unsigned, guf_unsigned)
|
GUF_DEFINE_INTEGER_CMP(int, guf_int_cmp)
|
||||||
GUF_DEFINE_MIN_MAX_CLAMP(unsigned short, guf_unsigned_short)
|
GUF_DEFINE_INTEGER_CMP(short, guf_short_cmp)
|
||||||
GUF_DEFINE_MIN_MAX_CLAMP(unsigned long, guf_unsigned_long)
|
GUF_DEFINE_INTEGER_CMP(long, guf_long_cmp)
|
||||||
GUF_DEFINE_MIN_MAX_CLAMP(unsigned long long, guf_unsigned_long_long)
|
GUF_DEFINE_INTEGER_CMP(long long, guf_long_long_cmp)
|
||||||
GUF_DEFINE_MIN_MAX_CLAMP(uint8_t, guf_uint8_t)
|
GUF_DEFINE_INTEGER_CMP(int8_t, guf_int8_t_cmp)
|
||||||
GUF_DEFINE_MIN_MAX_CLAMP(uint16_t, guf_uint16_t)
|
GUF_DEFINE_INTEGER_CMP(int16_t, guf_int16_t_cmp)
|
||||||
GUF_DEFINE_MIN_MAX_CLAMP(uint32_t, guf_uint32_t)
|
GUF_DEFINE_INTEGER_CMP(int32_t, guf_int32_t_cmp)
|
||||||
GUF_DEFINE_MIN_MAX_CLAMP(uint64_t, guf_uint64_t)
|
GUF_DEFINE_INTEGER_CMP(int64_t, guf_int64_t_cmp)
|
||||||
|
GUF_DEFINE_INTEGER_CMP(ptrdiff_t, guf_ptrdiff_t_cmp)
|
||||||
|
|
||||||
GUF_DEFINE_MIN_MAX_CLAMP(char, guf_char)
|
GUF_DEFINE_INTEGER_CMP(unsigned, guf_unsigned_cmp)
|
||||||
GUF_DEFINE_MIN_MAX_CLAMP(unsigned char, guf_unsigned_char)
|
GUF_DEFINE_INTEGER_CMP(unsigned short, guf_unsigned_short_cmp)
|
||||||
|
GUF_DEFINE_INTEGER_CMP(unsigned long, guf_unsigned_long_cmp)
|
||||||
|
GUF_DEFINE_INTEGER_CMP(unsigned long long, guf_unsigned_long_long_cmp)
|
||||||
|
GUF_DEFINE_INTEGER_CMP(uint8_t, guf_uint8_t_cmp)
|
||||||
|
GUF_DEFINE_INTEGER_CMP(uint16_t, guf_uint16_t_cmp)
|
||||||
|
GUF_DEFINE_INTEGER_CMP(uint32_t, guf_uint32_t_cmp)
|
||||||
|
GUF_DEFINE_INTEGER_CMP(uint64_t, guf_uint64_t_cmp)
|
||||||
|
GUF_DEFINE_INTEGER_CMP(size_t, guf_size_t_cmp)
|
||||||
|
|
||||||
#undef GUF_DEFINE_MIN_MAX_CLAMP
|
GUF_DEFINE_INTEGER_CMP(char, guf_char_cmp)
|
||||||
|
GUF_DEFINE_INTEGER_CMP(unsigned char, guf_unsigned_char_cmp)
|
||||||
|
|
||||||
static inline int guf_int(int x) {if (x >= 0) {return x;} GUF_ASSERT_RELEASE(x > INT_MIN ); return -x;}
|
GUF_DEFINE_INTEGER_CMP(float, guf_float_cmp)
|
||||||
static inline long guf_abs_long(long x) {if (x >= 0) {return x;} GUF_ASSERT_RELEASE(x > LONG_MIN ); return -x;}
|
GUF_DEFINE_INTEGER_CMP(double, guf_double_cmp)
|
||||||
static inline long long guf_abs_long_long(long long x) {if (x >= 0) {return x;} GUF_ASSERT_RELEASE(x > LLONG_MIN ); return -x;}
|
|
||||||
static inline int8_t guf_abs_i8 (int8_t x) {if (x >= 0) {return x;} GUF_ASSERT_RELEASE(x > INT8_MIN ); return -x;}
|
|
||||||
static inline int16_t guf_abs_i16(int16_t x) {if (x >= 0) {return x;} GUF_ASSERT_RELEASE(x > INT16_MIN); return -x;}
|
|
||||||
static inline int32_t guf_abs_i32(int32_t x) {if (x >= 0) {return x;} GUF_ASSERT_RELEASE(x > INT32_MIN); return -x;}
|
|
||||||
static inline int64_t guf_abs_i64(int64_t x) {if (x >= 0) {return x;} GUF_ASSERT_RELEASE(x > INT64_MIN); return -x;}
|
|
||||||
static inline ptrdiff_t guf_abs_ptrdiff(ptrdiff_t x) {if (x >= 0) {return x;} GUF_ASSERT_RELEASE(x > PTRDIFF_MIN); return -x;}
|
|
||||||
|
|
||||||
static inline bool guf_is_mul_overflow_size_t(size_t a, size_t b)
|
GUF_DEFINE_INTEGER_OPS(guf_int)
|
||||||
{
|
GUF_DEFINE_INTEGER_OPS(guf_short)
|
||||||
size_t c = a * b;
|
GUF_DEFINE_INTEGER_OPS(guf_long_long)
|
||||||
return a != 0 && ((c / a) != b);
|
GUF_DEFINE_INTEGER_OPS(guf_int8_t)
|
||||||
}
|
GUF_DEFINE_INTEGER_OPS(guf_int16_t)
|
||||||
|
GUF_DEFINE_INTEGER_OPS(guf_int32_t)
|
||||||
|
GUF_DEFINE_INTEGER_OPS(guf_int64_t)
|
||||||
|
|
||||||
static inline size_t guf_safe_mul_size_t(size_t a, size_t b)
|
GUF_DEFINE_INTEGER_OPS(guf_unsigned)
|
||||||
{
|
GUF_DEFINE_INTEGER_OPS(guf_unsigned_short)
|
||||||
GUF_ASSERT_RELEASE(!guf_is_mul_overflow_size_t(a, b));
|
GUF_DEFINE_INTEGER_OPS(guf_unsigned_long_long)
|
||||||
return a * b;
|
GUF_DEFINE_INTEGER_OPS(guf_uint8_t)
|
||||||
}
|
GUF_DEFINE_INTEGER_OPS(guf_uint16_t)
|
||||||
|
GUF_DEFINE_INTEGER_OPS(guf_uint32_t)
|
||||||
|
GUF_DEFINE_INTEGER_OPS(guf_uint64_t)
|
||||||
|
|
||||||
static inline bool guf_is_safe_size_calc(ptrdiff_t count, ptrdiff_t sizeof_elem)
|
GUF_DEFINE_INTEGER_OPS(guf_char)
|
||||||
{
|
GUF_DEFINE_INTEGER_OPS(guf_unsigned_char)
|
||||||
if (count < 0 || sizeof_elem <= 0) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (guf_is_mul_overflow_size_t(count, sizeof_elem)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
size_t size = (size_t)count * (size_t)sizeof_elem;
|
|
||||||
return size <= PTRDIFF_MAX;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline ptrdiff_t guf_safe_size_calc(ptrdiff_t count, ptrdiff_t sizeof_elem)
|
GUF_DEFINE_INTEGER_OPS(guf_float)
|
||||||
{
|
GUF_DEFINE_INTEGER_OPS(guf_double)
|
||||||
GUF_ASSERT_RELEASE(count >= 0);
|
|
||||||
GUF_ASSERT_RELEASE(sizeof_elem > 0);
|
#undef GUF_DEFINE_INTEGER_OPS
|
||||||
size_t size = guf_safe_mul_size_t(count, sizeof_elem);
|
#undef GUF_DEFINE_INTEGER_CMP
|
||||||
GUF_ASSERT_RELEASE(size <= PTRDIFF_MAX);
|
|
||||||
return size;
|
#endif
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@ -49,7 +49,7 @@
|
|||||||
// #endif
|
// #endif
|
||||||
|
|
||||||
typedef struct GUF_OBJ_OPS_TYPENAME {
|
typedef struct GUF_OBJ_OPS_TYPENAME {
|
||||||
// GUF_OBJ_TYPE *(*init_from)(GUF_OBJ_TYPE *dst, GUF_OBJ_TYPE *src, guf_obj_cpy_opt cpy_opt);
|
GUF_OBJ_TYPE default_value;
|
||||||
GUF_OBJ_TYPE *(*copy_init)(GUF_OBJ_TYPE *dst, const GUF_OBJ_TYPE *src);
|
GUF_OBJ_TYPE *(*copy_init)(GUF_OBJ_TYPE *dst, const GUF_OBJ_TYPE *src);
|
||||||
GUF_OBJ_TYPE *(*move_init)(GUF_OBJ_TYPE *dst, GUF_OBJ_TYPE *src);
|
GUF_OBJ_TYPE *(*move_init)(GUF_OBJ_TYPE *dst, GUF_OBJ_TYPE *src);
|
||||||
void (*free)(GUF_OBJ_TYPE *obj);
|
void (*free)(GUF_OBJ_TYPE *obj);
|
||||||
@ -59,24 +59,5 @@ typedef struct GUF_OBJ_OPS_TYPENAME {
|
|||||||
int (*cmp_void_inv)(const void *a, const void *b);
|
int (*cmp_void_inv)(const void *a, const void *b);
|
||||||
} GUF_OBJ_OPS_TYPENAME;
|
} GUF_OBJ_OPS_TYPENAME;
|
||||||
|
|
||||||
// static inline GUF_OBJ_TYPE *GUFCAT(GUF_OBJ_OPS_TYPENAME, _cpy) (GUF_OBJ_TYPE *dst, GUF_OBJ_TYPE *src, const GUF_OBJ_OPS_TYPENAME *ops, guf_obj_cpy_opt cpy_opt)
|
|
||||||
// {
|
|
||||||
// GUF_ASSERT_RELEASE(dst);
|
|
||||||
// GUF_ASSERT_RELEASE(src);
|
|
||||||
// GUF_ASSERT_RELEASE(ops);
|
|
||||||
// if (cpy_opt == GUF_CPY_VALUE) {
|
|
||||||
// dst = memcpy(dst, src, sizeof(GUF_OBJ_TYPE));
|
|
||||||
// GUF_ASSERT_RELEASE(dst); // Should never fail.
|
|
||||||
// } else if (cpy_opt == GUF_CPY_DEEP) {
|
|
||||||
// GUF_ASSERT_RELEASE(ops->copy_init);
|
|
||||||
// dst = ops->copy_init(dst, src);
|
|
||||||
// } else if (cpy_opt == GUF_CPY_MOVE) {
|
|
||||||
// GUF_ASSERT_RELEASE(ops->move_init);
|
|
||||||
// dst = ops->move_init(dst, src);
|
|
||||||
// }
|
|
||||||
// GUF_ASSERT(dst);
|
|
||||||
// return dst;
|
|
||||||
// }
|
|
||||||
|
|
||||||
#undef GUF_OBJ_TYPE
|
#undef GUF_OBJ_TYPE
|
||||||
#undef GUF_OBJ_OPS_TYPENAME
|
#undef GUF_OBJ_OPS_TYPENAME
|
||||||
@ -1,6 +1,8 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#define GUF_IMPLEMENTATION
|
||||||
#include "guf_common.h"
|
#include "guf_common.h"
|
||||||
#include "guf_cstr.h"
|
#include "guf_cstr.h"
|
||||||
|
|
||||||
@ -42,7 +44,7 @@ int main(void)
|
|||||||
bool success = true;
|
bool success = true;
|
||||||
|
|
||||||
GUF_LIFETIME_BLOCK(dbuf_float floats = dbuf_float_new(), floats, dbuf_float_free, {
|
GUF_LIFETIME_BLOCK(dbuf_float floats = dbuf_float_new(), floats, dbuf_float_free, {
|
||||||
for (int i = 0; i < 16; ++i) {
|
for (int i = 0; i < 10; ++i) {
|
||||||
dbuf_float_push_val(&floats, i % 2 ? i * 2.718f : i * -2.718f);
|
dbuf_float_push_val(&floats, i % 2 ? i * 2.718f : i * -2.718f);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -50,7 +52,7 @@ int main(void)
|
|||||||
printf("float: %f\n", *it.cur);
|
printf("float: %f\n", *it.cur);
|
||||||
}
|
}
|
||||||
|
|
||||||
dbuf_float_sort(&floats, GUF_SORT_DESCENDING);
|
dbuf_float_sort(&floats, GUF_SORT_ASCENDING);
|
||||||
printf("Sorted.\n");
|
printf("Sorted.\n");
|
||||||
GUF_FOREACH(&floats, dbuf_float, it) {
|
GUF_FOREACH(&floats, dbuf_float, it) {
|
||||||
printf("float: %f\n", *it.cur);
|
printf("float: %f\n", *it.cur);
|
||||||
@ -72,6 +74,8 @@ int main(void)
|
|||||||
dbuf_int_push_val(&integers, 620);
|
dbuf_int_push_val(&integers, 620);
|
||||||
dbuf_int_push_val(&integers, 720);
|
dbuf_int_push_val(&integers, 720);
|
||||||
|
|
||||||
|
printf("%d\n", *dbuf_int_at(&integers, 4));
|
||||||
|
|
||||||
int i = 0;
|
int i = 0;
|
||||||
GUF_DBUF_FOREACH(integers, int, elem) {
|
GUF_DBUF_FOREACH(integers, int, elem) {
|
||||||
printf("elem %d: %d\n", i, *elem);
|
printf("elem %d: %d\n", i, *elem);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user