2#ifndef __ASE_CXXAUX_HH__
3#define __ASE_CXXAUX_HH__
5#include <ase/sysconfig.h>
19static_assert (
sizeof (
uint) == 4,
"");
32static_assert (
sizeof (
int8) == 1 &&
sizeof (
int16) == 2 &&
sizeof (
int32) == 4 &&
sizeof (
int64) == 8,
"");
33static_assert (
sizeof (
int) == 4 &&
sizeof (
uint) == 4 &&
sizeof (
unichar) == 4,
"");
41#define ASE_CPP_STRINGIFY(s) ASE_CPP_STRINGIFY_ (s)
42#define ASE_CPP_STRINGIFY_(s) #s
43#define ASE_CPP_PASTE2_(a,b) a ## b
44#define ASE_CPP_PASTE2(a,b) ASE_CPP_PASTE2_ (a,b)
45#define ASE_ISLIKELY(expr) __builtin_expect (bool (expr), 1)
46#define ASE_UNLIKELY(expr) __builtin_expect (bool (expr), 0)
47#define ASE_ABS(a) ((a) < 0 ? -(a) : (a))
48#define ASE_MIN(a,b) ((a) <= (b) ? (a) : (b))
49#define ASE_MAX(a,b) ((a) >= (b) ? (a) : (b))
50#define ASE_CLAMP(v,mi,ma) ((v) < (mi) ? (mi) : ((v) > (ma) ? (ma) : (v)))
51#define ASE_ARRAY_SIZE(array) (sizeof (array) / sizeof ((array)[0]))
52#define ASE_ALIGN(size, base) ((base) * ((size_t (size) + (base) - 1) / (base)))
53#define ASE_ALIGNMENT16(pointer) (0xf & ptrdiff_t (pointer))
54#define ASE_ALIGNED16(pointer) (!ALIGNMENT16 (pointer))
57#define ASE_ALWAYS_INLINE __attribute__ ((always_inline))
58#define ASE_COLD __attribute__ ((__cold__))
59#define ASE_CONST __attribute__ ((__const__))
60#define ASE_CONSTRUCTOR __attribute__ ((constructor,used))
61#define ASE_DEPRECATED __attribute__ ((__deprecated__))
62#define ASE_FORMAT(fx) __attribute__ ((__format_arg__ (fx)))
63#define ASE_HOT __attribute__ ((__hot__))
64#define ASE_MALLOC __attribute__ ((__malloc__))
65#define ASE_MAY_ALIAS __attribute__ ((may_alias))
66#define ASE_NOINLINE __attribute__ ((noinline))
67#define ASE_NORETURN __attribute__ ((__noreturn__))
68#define ASE_NO_INSTRUMENT __attribute__ ((__no_instrument_function__))
69#define ASE_PRINTF(fx, ax) __attribute__ ((__format__ (__printf__, fx, ax)))
70#define ASE_PURE __attribute__ ((__pure__))
71#define ASE_SCANF(fx, ax) __attribute__ ((__format__ (__scanf__, fx, ax)))
72#define ASE_SENTINEL __attribute__ ((__sentinel__))
73#define ASE_UNUSED __attribute__ ((__unused__))
74#define ASE_USE_RESULT __attribute__ ((warn_unused_result))
75#define ASE_USED __attribute__ ((__used__))
76#define ASE_WEAK __attribute__ ((__weak__))
79#define ASE_RETURN_UNLESS(cond, ...) do { if (ASE_UNLIKELY (!bool (cond))) return __VA_ARGS__; } while (0)
82#define ASE_ASSERT_RETURN(expr, ...) do { if (expr) [[likely]] break; ::Ase::assertion_failed (#expr); return __VA_ARGS__; } while (0)
85#define ASE_ASSERT_RETURN_UNREACHED(...) do { ::Ase::assertion_failed (nullptr); return __VA_ARGS__; } while (0)
88#define ASE_ASSERT_UNREACHED(...) do { ::Ase::assertion_fatal (nullptr); } while (0)
91#define ASE_ASSERT(expr) do { if (expr) [[likely]] break; ::Ase::assertion_fatal (#expr); } while (0)
94#define ASE_ASSERT_WARN(expr) do { if (expr) [[likely]] break; ::Ase::assertion_failed (#expr); } while (0)
97#define ASE_ASSERT_PARANOID(expr) do { if (expr) [[likely]] break; ::Ase::assertion_failed (#expr); } while (0)
100#define ASE_DIE(msg) do { errno = 0; ::Ase::perror_die (msg); } while (0)
103#define ASE_PERROR_DIE(msg) do { ::Ase::perror_die (msg); } while (0)
106#define ASE_CLASS_NON_COPYABLE(ClassName) \
107 ClassName (const ClassName&) = delete; \
108 ClassName& operator= (const ClassName&) = delete
111#define ASE_STRUCT_DECLS(Klass) \
113 using ASE_CPP_PASTE2 (Klass, P) = ::std::shared_ptr<Klass>; \
114 using ASE_CPP_PASTE2 (Klass, S) = ::std::vector<Klass>;
117#define ASE_CLASS_DECLS(Klass) \
119 using ASE_CPP_PASTE2 (Klass, W) = ::std::weak_ptr<Klass>; \
120 using ASE_CPP_PASTE2 (Klass, P) = ::std::shared_ptr<Klass>; \
121 using ASE_CPP_PASTE2 (Klass, S) = ::std::vector<ASE_CPP_PASTE2 (Klass, P)>;
124#define ASE_DEFINE_ENUM_EQUALITY(Enum) \
125 constexpr bool operator== (Enum v, int64_t n) { return int64_t (v) == n; } \
126 constexpr bool operator== (int64_t n, Enum v) { return n == int64_t (v); } \
127 constexpr bool operator!= (Enum v, int64_t n) { return int64_t (v) != n; } \
128 constexpr bool operator!= (int64_t n, Enum v) { return n != int64_t (v); }
129#define ASE_DEFINE_FLAGS_ARITHMETIC(Enum) \
130 constexpr int64_t operator>> (Enum v, int64_t n) { return int64_t (v) >> n; } \
131 constexpr int64_t operator<< (Enum v, int64_t n) { return int64_t (v) << n; } \
132 constexpr int64_t operator^ (Enum v, int64_t n) { return int64_t (v) ^ n; } \
133 constexpr int64_t operator^ (int64_t n, Enum v) { return n ^ int64_t (v); } \
134 constexpr Enum operator^ (Enum v, Enum w) { return Enum (int64_t (v) ^ w); } \
135 constexpr int64_t operator| (Enum v, int64_t n) { return int64_t (v) | n; } \
136 constexpr int64_t operator| (int64_t n, Enum v) { return n | int64_t (v); } \
137 constexpr Enum operator| (Enum v, Enum w) { return Enum (int64_t (v) | w); } \
138 constexpr int64_t operator& (Enum v, int64_t n) { return int64_t (v) & n; } \
139 constexpr int64_t operator& (int64_t n, Enum v) { return n & int64_t (v); } \
140 constexpr Enum operator& (Enum v, Enum w) { return Enum (int64_t (v) & w); } \
141 constexpr int64_t operator~ (Enum v) { return ~int64_t (v); } \
142 constexpr int64_t operator+ (Enum v) { return +int64_t (v); } \
143 constexpr int64_t operator- (Enum v) { return -int64_t (v); } \
144 constexpr int64_t operator+ (Enum v, int64_t n) { return int64_t (v) + n; } \
145 constexpr int64_t operator+ (int64_t n, Enum v) { return n + int64_t (v); } \
146 constexpr int64_t operator- (Enum v, int64_t n) { return int64_t (v) - n; } \
147 constexpr int64_t operator- (int64_t n, Enum v) { return n - int64_t (v); } \
148 constexpr int64_t operator* (Enum v, int64_t n) { return int64_t (v) * n; } \
149 constexpr int64_t operator* (int64_t n, Enum v) { return n * int64_t (v); } \
150 constexpr int64_t operator/ (Enum v, int64_t n) { return int64_t (v) / n; } \
151 constexpr int64_t operator/ (int64_t n, Enum v) { return n / int64_t (v); } \
152 constexpr int64_t operator% (Enum v, int64_t n) { return int64_t (v) % n; } \
153 constexpr int64_t operator% (int64_t n, Enum v) { return n % int64_t (v); } \
154 constexpr Enum& operator^= (Enum &e, int64_t n) { e = Enum (e ^ n); return e; } \
155 constexpr Enum& operator|= (Enum &e, int64_t n) { e = Enum (e | n); return e; } \
156 constexpr Enum& operator&= (Enum &e, int64_t n) { e = Enum (e & n); return e; } \
157 constexpr Enum& operator+= (Enum &e, int64_t n) { e = Enum (e + n); return e; } \
158 constexpr Enum& operator-= (Enum &e, int64_t n) { e = Enum (e - n); return e; } \
159 constexpr Enum& operator*= (Enum &e, int64_t n) { e = Enum (e * n); return e; } \
160 constexpr Enum& operator/= (Enum &e, int64_t n) { e = Enum (e / n); return e; } \
161 constexpr Enum& operator%= (Enum &e, int64_t n) { e = Enum (e % n); return e; } \
162 ASE_DEFINE_ENUM_EQUALITY (Enum)
165template<
typename UInt>
static inline constexpr UInt
166rotr (UInt bits, uint32_t offset)
168 const uint32_t wrapped_bits =
sizeof (bits) * 8 - offset;
169 return (bits >> offset) | (bits << wrapped_bits);
173template<
typename UInt>
static inline constexpr UInt
174rotl (UInt bits, uint32_t offset)
176 const uint32_t wrapped_bits =
sizeof (bits) * 8 - offset;
177 return (bits << offset) | (bits >> wrapped_bits);
181template<
typename T>
static inline constexpr T
182divmod (T dividend, T divisor, T *reminderp)
184 *reminderp = dividend % divisor;
185 return dividend / divisor;
192template<
class T> ASE_PURE
static inline const char*
199template<
class T> ASE_PURE
static inline const char*
206template<
typename T>
static T*
209 asm (
"" :
"+r" (ptr));
222void assertion_failed (
const char *msg =
nullptr,
const char *file = __builtin_FILE(),
223 int line = __builtin_LINE(),
const char *func = __builtin_FUNCTION()) noexcept;
224void assertion_fatal (const
char *msg =
nullptr, const
char *file = __builtin_FILE(),
225 int line = __builtin_LINE(), const
char *func = __builtin_FUNCTION()) noexcept ASE_NORETURN;
232extern inline constexpr
bool
235 return n == 0 || (a[0] == b[0] && (a[0] == 0 ||
constexpr_equals (a + 1, b + 1, n - 1)));
239template<
class Type,
class ...Ts> __attribute__ ((always_inline))
inline void
240new_inplace (Type &typemem, Ts &&... args)
246template<
class Type> __attribute__ ((always_inline))
inline void
247delete_inplace (Type &typemem)
253template<
class T>
void
260template<
bool value>
using REQUIRES = typename ::std::enable_if<value, bool>::type;
263template<
bool value>
using REQUIRESv = typename ::std::enable_if<value, void>::type;
269#define ASE_DEFINE_MAKE_SHARED(CLASS) \
270 struct MakeSharedAllocator_ : std::allocator<CLASS> { \
271 template<typename ...Args> \
272 static void construct (CLASS *p, Args &&...args) \
273 { ::new (p) CLASS (std::forward<Args> (args)...); } \
274 static void destroy (CLASS *p) \
276 template<typename U> struct rebind { \
278 std::conditional_t<std::is_same<U, CLASS>::value, \
279 MakeSharedAllocator_, std::allocator<U>>; \
282 template<typename ...Args> static std::shared_ptr<CLASS> \
283 make_shared (Args &&...args) \
285 return std::allocate_shared<CLASS> (MakeSharedAllocator_(), \
286 std::forward<Args> (args)...); \
311 typedef decltype (
object->shared_from_this()) ObjectP;
315 sptr =
object->shared_from_this();
320 sptr =
object->shared_from_this();
328 return shared_ptr_cast<Target> (
const_cast<Source*
> (
object));
348 return shared_ptr_cast<Source> (
object);
356 if (__builtin_expect (!!cptr,
true))
377 Class *ptr_ =
nullptr;
379 initialize() ASE_NOINLINE
384 ptr_ =
new (mem_) Class();
390 explicit operator bool () const ASE_PURE {
return ptr_ !=
nullptr; }
410 operator uint32_t ()
const noexcept {
return id; }
411 bool operator== (
int64_t i)
const noexcept {
return id == i; }
412 bool operator!= (
int64_t i)
const noexcept {
return id != i; }
413 friend bool operator== (
int64_t i,
const Id32 &
id) {
return id.operator== (i); }
414 friend bool operator!= (
int64_t i,
const Id32 &
id) {
return id.operator!= (i); }
constexpr Persistent() noexcept
A constexpr constructor avoids the static initialization order fiasco.
Class * operator->() __attribute__((__pure__))
Retrieve pointer to Class instance, always returns the same pointer.
Class & operator*() __attribute__((__pure__))
Retrieve reference to Class instance, always returns the same reference.
#define ASE_UNLIKELY(expr)
Compiler hint to optimize for expr evaluating to false.
The Anklang C++ API namespace.
uint64_t uint64
A 64-bit unsigned integer, use PRI*64 in format strings.
void call_delete(T *o)
Simple way to create a standalone callback to delete an object of type T.
void assertion_failed(const char *msg, const char *file, int line, const char *func) noexcept
Print instructive message, handle "breakpoint", "backtrace" and "fatal-warnings" in $ASE_DEBUG.
int32_t int32
A 32-bit signed integer.
int16_t int16
A 16-bit signed integer.
uint8_t uint8
An 8-bit unsigned integer.
int8_t int8
An 8-bit signed integer.
int64_t int64
A 64-bit unsigned integer, use PRI*64 in format strings.
std::shared_ptr< C > weak_ptr_fetch_or_create(std::weak_ptr< C > &wptr, const std::function< std::shared_ptr< C >()> &ctor)
Fetch shared_ptr from wptr and create C with ctor if needed.
typename ::std::enable_if< value, bool >::type REQUIRES
REQUIRES<value> - Simplified version of std::enable_if<cond,bool>::type to use SFINAE in function tem...
void assertion_fatal(const char *msg, const char *file, int line, const char *func) noexcept
Print a debug message via assertion_failed() and abort the program.
void perror_die(const std::string &msg) noexcept
Issue a warning about an assertion error.
typename ::std::enable_if< value, void >::type REQUIRESv
REQUIRESv<value> - Simplified version of std::enable_if<cond,void>::type to use SFINAE in struct temp...
constexpr bool constexpr_equals(const char *a, const char *b, size_t n)
Test string equality at compile time.
std::shared_ptr< typename std::remove_pointer< Source >::type > shared_ptr_from(Source *object)
Use shared_ptr_cast<>() to convert an object pointer into a shared_ptr<>.
uint32_t unichar
A 32-bit unsigned integer used for Unicode characters.
const char * string_demangle_cxx(const char *mangled_identifier) noexcept
Demangle identifier via libcc.
std::string backtrace_command()
Find GDB and construct command line.
bool assertion_failed_fatal
Global flag to force aborting on assertion warnings.
uint16_t uint16
A 16-bit unsigned integer.
uint32_t uint32
A 32-bit unsigned integer.
std::shared_ptr< typename std::remove_pointer< Target >::type > shared_ptr_cast(Source *object)
uint32_t uint
Provide 'uint' as convenience type.
Helper class for integer IDs up to 32 Bit, possibly of enum type.
Common base type to allow casting between polymorphic classes.