/// Macros header /// /// # Features /// * `_EVAL_DEBUG_ONLY_STMTS` - Evaluate expressions passed to macros that are no-ops when not in debug mode. #ifndef _MACROS_H #define _MACROS_H #include #include #include #include // Attribute macros #define _pure __attribute__((const)) #define _readonly __attribute__((pure)) #ifndef __cplusplus #define noreturn __attribute__((noreturn)) #define deprecated __attribute__((deprecated)) #define deprecated_message(str) __attribute__((deprecated(str))) #endif #define noinline __attribute__((noinline)) #define always_inline __attribute__((always_inline)) #ifdef DEBUG #define _mixin static inline always_inline #else #define _mixin extern inline always_inline #endif #define unrestrict __attribute__((may_alias)) #define _shared unrestrict #ifdef __cplusplus #define restrict __restrict__ #endif // Type macros #define AS(x, t) ((t)(x)) #ifdef __cplusplus #define let auto #define var(x) decltype(x) #else #define let __auto_type #define var(x) __typeof((x)) #endif // Control flow macros #define LIKELY(x) __builtin_expect(!!(x), 1) #define UNLIKELY(x) __builtin_expect(!!(x), 0) /// Equivalent to GNU C `x ?: y` operator. #define TERN_OR(x, y) ({ let _x = (x); _x ? _x : (y); }) // Statement macros #define _no_op ((void)0) #define IGNORE(x) ((void)(x)) _mixin void _drain_val(void* x, ...) { IGNORE(x); } #define _drain(...) _drain_val(NULL, __VA_ARGS__) // Allocation macros #define box(t) aligned_alloc(_Alignof(t), sizeof(t)) #define stackalloc(t) __builtin_alloca_with_align(sizeof(t), _Alignof(t)) // Function macros #define TRACEx(X, msg, ...) (fprintf(stderr, "[" X "] " __FILE__ ":%d->%s(): " msg "\n", __LINE__, __func__, ## __VA_ARGS__)) #ifdef DEBUG #define TRACE(msg, ...) TRACEx("trace", msg, ## __VA_ARGS__) #elif defined(_EVAL_DEBUG_ONLY_STMTS) #define TRACE(msg, ...) _drain(msg, ## __VA_ARGS__) #else #define TRACE(msg, ...) _no_op #endif #define INFO(msg, ...) TRACEx("info", msg, ## __VA_ARGS__) #define WARN(msg, ...) TRACEx("warning", msg, ## __VA_ARGS__) #define ERROR(msg, ...) TRACEx("error", msg, ## __VA_ARGS__) #define FATAL(msg, ...) (TRACEx("FATAL", msg, ## __VA_ARGS__), abort()) // Assertion macros #ifdef DEBUG #define debug_assert(x) assert((x)) #elif defined(_EVAL_DEBUG_ONLY_STMTS) #define debug_assert(x) IGNORE(x) #else #define debug_assert(x) _no_op #endif #define assert_eq(x,y) assert((x) == (y)) #define assert_ne(x,y) assert((x) != (y)) #define debug_assert_eq(x,y) debug_assert((x) == (y)) #define debug_assert_ne(x,y) debug_assert((x) != (y)) #ifdef DEBUG #define debug_static_assert(x, msg) _Static_assert((x), msg) #else #define debug_static_assert(x, msg) _Static_assert(1, msg) #endif // Version macros #define _UI(x) ((uint32_t)(x)) #define VER_COMP_MAJ 24u #define VER_COMP_MIN 16u #define VER_COMP_BF 8u #define VER_COMP_REV 0u /// Create a `uint32_t` from these version componants #define VERSION(maj,min,bf,rev) _UI( _UI(maj) << 24u | _UI(min) << 16u | _UI(bf) << 8u | _UI(rev) ) /// Mask `ver` to retain only the version component specified by `mask` /// /// # Example /// `_Static_assert( (VERSION_COMP(VERSION(1,2,3,4), VER_COMP_MIN) >> VER_COMP_MIN) == 2u)` #define VERSION_COMP(ver, mask) _UI( _UI(ver) & (0xffu << _UI(mask)) /*>> _UI(mask)*/ ) #define VERSION_MAJ(ver) _UI(VERSION_COMP((ver), 24u) >> 24u) #define VERSINO_MIN(ver) _UI(VERSION_COMP((ver), 16u) >> 16u) #define VERSINO_BF(ver) _UI(VERSION_COMP((ver), 8u) >> 8u) #define VERSINO_REV(ver) _UI(_UI(ver) & 0xffu) _Static_assert( (VERSION_COMP(VERSION(1,2,3,4), VER_COMP_MIN) >> VER_COMP_MIN) == 2u, "invalid native version spec"); #undef _UI #endif /* _MACROS_H */