#pragma once #include #include #include #include #include #include namespace rex { #define static_assert_size(type, size) \ static_assert(sizeof(type) == size, "bad definition for " #type ": must be " #size " bytes") #define rex_assert assert #define __REX_EXPAND(x) x #define __REX_ARGC(...) \ __REX_EXPAND(__REX_ARGC_IMPL(__VA_ARGS__, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)) #define __REX_ARGC_IMPL(x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15, N, ...) N #define __REX_MACRO_DISPATCH(func, ...) __REX_MACRO_DISPATCH_(func, __REX_ARGC(__VA_ARGS__)) #define __REX_MACRO_DISPATCH_(func, nargs) __REX_MACRO_DISPATCH__(func, nargs) #define __REX_MACRO_DISPATCH__(func, nargs) func##nargs [[noreturn]] inline void rex_assert_fail( const char* file, int line, const char* expression, const char* message) { std::fprintf(stderr, "Assertion failed: %s\n" " Expression: %s\n" " Location: %s:%d\n", message, expression, file, line); std::fflush(stderr); std::abort(); } #define assert_always(...) assert_always_impl(__VA_OPT__(__VA_ARGS__,) "assert_always triggered") #define assert_always_impl(message, ...) rex::rex_assert_fail(__FILE__, __LINE__, "false", message) #define assert_true(...) __REX_MACRO_DISPATCH(assert_true, __VA_ARGS__)(__VA_ARGS__) #define assert_true1(expr) rex_assert(expr) #define assert_true2(expr, message) \ do { \ if (!(expr)) { \ rex::rex_assert_fail(__FILE__, __LINE__, #expr, message); \ } \ } while (0) #define assert_false(...) __REX_MACRO_DISPATCH(assert_false, __VA_ARGS__)(__VA_ARGS__) #define assert_false1(expr) rex_assert(!(expr)) #define assert_false2(expr, message) \ do { \ if (!!(expr)) { \ rex::rex_assert_fail(__FILE__, __LINE__, "!(" #expr ")", message); \ } \ } while (0) #define assert_zero(...) __REX_MACRO_DISPATCH(assert_zero, __VA_ARGS__)(__VA_ARGS__) #define assert_zero1(expr) rex_assert((expr) == 0) #define assert_zero2(expr, message) \ do { \ if ((expr) != 0) { \ rex::rex_assert_fail(__FILE__, __LINE__, "(" #expr ") == 0", message); \ } \ } while (0) #define assert_not_zero(...) __REX_MACRO_DISPATCH(assert_not_zero, __VA_ARGS__)(__VA_ARGS__) #define assert_not_zero1(expr) rex_assert((expr) != 0) #define assert_not_zero2(expr, message) \ do { \ if ((expr) == 0) { \ rex::rex_assert_fail(__FILE__, __LINE__, "(" #expr ") != 0", message); \ } \ } while (0) #define assert_null(...) __REX_MACRO_DISPATCH(assert_null, __VA_ARGS__)(__VA_ARGS__) #define assert_null1(expr) rex_assert((expr) == nullptr) #define assert_null2(expr, message) \ do { \ if ((expr) != nullptr) { \ rex::rex_assert_fail(__FILE__, __LINE__, "(" #expr ") == nullptr", message); \ } \ } while (0) #define assert_not_null(...) __REX_MACRO_DISPATCH(assert_not_null, __VA_ARGS__)(__VA_ARGS__) #define assert_not_null1(expr) rex_assert((expr) != nullptr) #define assert_not_null2(expr, message) \ do { \ if ((expr) == nullptr) { \ rex::rex_assert_fail(__FILE__, __LINE__, "(" #expr ") != nullptr", message); \ } \ } while (0) #define assert_unhandled_case(variable) assert_always("unhandled switch(" #variable ") case") #define rex_unreachable() std::unreachable() [[noreturn]] inline void FatalError(const char* message) { std::fprintf(stderr, "FATAL ERROR: %s\n", message); std::fflush(stderr); std::abort(); } [[noreturn]] inline void FatalError(const std::string& message) { FatalError(message.c_str()); } } // namespace rex