You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
naka/include/macros.h

137 lines
3.6 KiB

/// 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 <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdarg.h>
// 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 */