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.

83 lines
2.7 KiB

#ifndef _MACROS_H
#define _MACROS_H
#ifdef __cplusplus
#include <type_traits>
#include <utility>
#define $CXX 1
#define $C 0
#else
#include <stdbool.h>
#define $CXX 0
#define $C 1
#endif
// Empty token
#define $NULL
#if $CXX // C++
#define LINK_START(C) extern #C {
#define LINK_END }
#define restrict __restrict__
#define $auto __auto_type
#define typeof(...) decltype(__VA_ARGS__)
#define $typeof(...) __typeof__(__VA_ARGS__)
#define $LIKELY(expr) __builtin_expect(bool(expr), true)
#define $UNLIKELY(expr) __builtin_expect(bool(expr), false)
#else // C
#define $LIKELY(expr) __builtin_expect((bool)(expr), true)
#define $UNLIKELY(expr) __builtin_expect((bool)(expr), false)
#define auto __auto_type
#define $auto __auto_type
#define LINK_START(_)
#define LINK_END
#define nullptr ((void*)0)
#define $typeof __typeof__
#define alignof _Alignof
#define static_assert _Static_assert
#define alignas(...) __attribute__((aligned(__VA_ARGS__)))
#endif
#define unrestrict __attribute__((__may_alias__))
#if $CXX
#define $READ_ONCE_FROM(...) [&] () noexcept -> auto { using cvx_t = ::std::add_pointer_t<::std::add_const_t<::std::add_volatile_t<decltype(__VA_ARGS__)>>>; \
return *static_cast<cvx_t>(::std::addressof(__VA_ARGS__)); \
}()
#define $WRITE_ONCE_TO(X, value) [&] () noexcept -> decltype(auto) { using vx_t = ::std::add_pointer_t<::std::add_volatile_t<decltype(X)>>; \
static_assert(::std::is_convertible_v<decltype(value), decltype(*::std::declval<vx_t>())>, "Cannot convert " #value " to assign to " #X); \
return *static_cast<vx_t>(::std::addressof(X)) = ::std::forward<decltype(value)>(value); \
}()
#else
#define $READ_ONCE_FROM(X) ({ $auto $__read_once_from = (X); *((const volatile $typeof($__read_once_from)*)(&$__read_once_from)); })
#define $WRITE_ONCE_TO(X, value) ({ $auto $__write_once_to = (X); *((volatile $typeof($__write_once_to)*)(&$__write_once_to)) = (value); })
#endif
#define $identity_type(...) $typeof(__VA_ARGS__)
#define $TRANSMUTE(T, expr) \
({ $auto $__expr_from = (expr); \
static_assert(sizeof(typeof($__expr_from)) == sizeof(T) \
&& alignof(typeof($__expr_from)) == alignof(typeof($__expr_from)), "Transmute source type does not have identical layout to dest type " #T); \
union { typeof($__expr_from) from; $typeof(T) to; } $__rec = { .from = $__expr_from; }; \
$__rec.to; })
#if $CXX
#define TRANSMUTE(T, ...) ::std::bit_cast<$typeof(T)>(__VA_ARGS__)
#else
#define TRANSMUTE(T, ...) $TRANSMUTE(T, __VA_ARGS__)
#endif
#define $__int_width_
#define $int(N) $identity_type(_BitInt(N))
#define $sint(N) $identity_type(signed _BitInt(N))
#define $uint(N) $identity_type(unsigned _BitInt(N))
#if !defined(_MACROS_HH) && defined(__cplusplus)
#include "macros.hh"
#endif
#endif /* _MACROS_H */