165 lines
4.4 KiB
C
165 lines
4.4 KiB
C
/*
|
|
is parametrized: no, but needs to be included with GUF_INIT in the init implementation
|
|
|
|
TOOD: - Thread safety?
|
|
- Maybe allow user defined guf_errs?
|
|
*/
|
|
|
|
#ifndef GUF_ASSERT_H
|
|
#define GUF_ASSERT_H
|
|
#include <stdio.h>
|
|
#include <assert.h>
|
|
#include "guf_common.h"
|
|
|
|
typedef enum guf_err {
|
|
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_NOT_FOUND,
|
|
GUF_ERR_ALREADY_EXISTS,
|
|
GUF_ERR_ASSERT_FAIL,
|
|
GUF_ERR_TYPES_NUM
|
|
} guf_err;
|
|
|
|
typedef void(*guf_panic_handler_fn)(guf_err err, const char *msg);
|
|
|
|
extern guf_panic_handler_fn guf_global_panic_handler;
|
|
|
|
extern void guf_set_global_panic_handler(guf_panic_handler_fn panic_handler);
|
|
extern void guf_panic_handler_default(guf_err err, const char *msg);
|
|
extern const char *guf_err_to_str(guf_err err);
|
|
|
|
#define GUF_FILE_LINE_STR() "file '" __FILE__ "' line " GUF_STRINGIFY(__LINE__)
|
|
#define GUF_ERR_MSG(msg) msg " (" GUF_FILE_LINE_STR() ")"
|
|
#define GUF_ERR_MSG_EMPTY() "(" GUF_FILE_LINE_STR() ")"
|
|
|
|
extern void guf_panic(guf_err err, const char *msg);
|
|
|
|
#define GUF_PANIC(err) guf_panic(err, "(" GUF_FILE_LINE_STR() ")");
|
|
|
|
// 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 abort()
|
|
#endif
|
|
|
|
#ifndef NDEBUG
|
|
#define GUF_ASSERT(COND) do { \
|
|
if (!(COND)) { \
|
|
guf_global_panic_handler(GUF_ERR_ASSERT_FAIL, "(assertion '" #COND "' " GUF_FILE_LINE_STR() ")"); \
|
|
abort(); \
|
|
}\
|
|
} while(0);
|
|
#else
|
|
#define GUF_ASSERT(COND)
|
|
#endif
|
|
|
|
#define GUF_ASSERT_RELEASE(COND) do { \
|
|
if (!(COND)) { \
|
|
guf_global_panic_handler(GUF_ERR_ASSERT_FAIL, "(release assertion '" #COND "' " GUF_FILE_LINE_STR() ")"); \
|
|
abort();\
|
|
} \
|
|
} while (0);
|
|
|
|
static inline void guf_err_set_or_panic(guf_err *err, guf_err err_val, const char *panic_msg)
|
|
{
|
|
if (!err) {
|
|
guf_panic(err_val, panic_msg);
|
|
} else {
|
|
*err = err_val;
|
|
}
|
|
}
|
|
|
|
static inline void guf_err_set_if_not_null(guf_err *err, guf_err err_val)
|
|
{
|
|
if (err) {
|
|
*err = err_val;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#ifdef GUF_INIT
|
|
#undef GUF_INIT
|
|
static 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_NOT_FOUND] = "Not found error",
|
|
[GUF_ERR_ALREADY_EXISTS] = "Already exists error",
|
|
[GUF_ERR_RUNTIME] = "Runtime error",
|
|
[GUF_ERR_LOGIC] = "Logic error",
|
|
[GUF_ERR_ASSERT_FAIL] = "Assertion failed"
|
|
};
|
|
|
|
extern void guf_panic(guf_err err, const char *msg)
|
|
{
|
|
if (!guf_global_panic_handler) {
|
|
fputs("libguf panic (note: guf_global_panic_handler is NULL)\n", stderr);
|
|
if (msg) {
|
|
fputs(": ", stderr);
|
|
fputs(msg, stderr);
|
|
}
|
|
abort();
|
|
}
|
|
guf_global_panic_handler(err, msg);
|
|
abort(); // Just in case...
|
|
}
|
|
|
|
extern void guf_set_global_panic_handler(guf_panic_handler_fn panic_handler)
|
|
{
|
|
guf_global_panic_handler = panic_handler;
|
|
}
|
|
|
|
extern const char *guf_err_to_str(guf_err err)
|
|
{
|
|
if (GUF_ARR_SIZE(guf_err_type_str) != GUF_ERR_TYPES_NUM) {
|
|
fputs("libguf warning (in guf_assert.h): array size of guf_err_type_str != GUF_ERR_TYPES_NUM", stderr);
|
|
}
|
|
|
|
if (err < 0 || err >= GUF_ERR_TYPES_NUM) {
|
|
return "Invalid error code";
|
|
} else {
|
|
if (err > GUF_ARR_SIZE(guf_err_type_str)) {
|
|
return "Invalid error string";
|
|
}
|
|
return guf_err_type_str[err];
|
|
}
|
|
}
|
|
|
|
extern void guf_panic_handler_default(guf_err err, const char *msg)
|
|
{
|
|
fputs("libguf panic: ", stderr);
|
|
fputs(guf_err_to_str(err), stderr);
|
|
fputc(' ', stderr);
|
|
if (msg && err != GUF_ERR_NONE) {
|
|
fputs(msg, stderr);
|
|
}
|
|
fputc('\n', stderr);
|
|
|
|
#ifndef NDEBUG
|
|
GUF_DEBUG_BREAK_CODE;
|
|
#endif
|
|
abort();
|
|
}
|
|
|
|
guf_panic_handler_fn guf_global_panic_handler = guf_panic_handler_default;
|
|
|
|
#endif
|