Anklang-0.3.0.dev835+g24d8ae08 anklang-0.3.0.dev835+g24d8ae08
ASE — Anklang Sound Engine (C++)

« « « Anklang Documentation
Loading...
Searching...
No Matches
cxxaux.hh
Go to the documentation of this file.
1 // This Source Code Form is licensed MPL-2.0: http://mozilla.org/MPL/2.0
2#ifndef __ASE_CXXAUX_HH__
3#define __ASE_CXXAUX_HH__
4
5#include <ase/sysconfig.h>
6#include <sys/types.h> // uint, ssize
7#include <cstdint> // uint64_t
8#include <string>
9#include <functional>
10#include <vector>
11#include <memory>
12#include <cmath>
13#include <mutex>
14#include <map>
15
16namespace Ase {
17
18typedef uint32_t uint;
19static_assert (sizeof (uint) == 4, "");
20
21// == type aliases ==
22typedef uint8_t uint8;
26typedef int8_t int8;
27typedef int16_t int16;
28typedef int32_t int32;
29typedef int64_t int64;
31static_assert (sizeof (uint8) == 1 && sizeof (uint16) == 2 && sizeof (uint32) == 4 && sizeof (uint64) == 8, "");
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, "");
34using std::void_t;
38using VoidF = std::function<void()>;
39
40// == Utility Macros ==
41#define ASE_CPP_STRINGIFY(s) ASE_CPP_STRINGIFY_ (s)
42#define ASE_CPP_STRINGIFY_(s) #s // Indirection helper, required to expand macros like __LINE__
43#define ASE_CPP_PASTE2_(a,b) a ## b // Indirection helper, required to expand macros like __LINE__
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))
55
56// Ase macro shorthands for <a href="https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html">GCC Attributes</a>.
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)) // gcc-3.3 also needs "used" to emit code
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__))
77
79#define ASE_RETURN_UNLESS(cond, ...) do { if (ASE_UNLIKELY (!bool (cond))) return __VA_ARGS__; } while (0)
80
82#define ASE_ASSERT_RETURN(expr, ...) do { if (expr) [[likely]] break; ::Ase::assertion_failed (#expr); return __VA_ARGS__; } while (0)
83
85#define ASE_ASSERT_RETURN_UNREACHED(...) do { ::Ase::assertion_failed (nullptr); return __VA_ARGS__; } while (0)
86
88#define ASE_ASSERT_UNREACHED(...) do { ::Ase::assertion_fatal (nullptr); } while (0)
89
91#define ASE_ASSERT(expr) do { if (expr) [[likely]] break; ::Ase::assertion_fatal (#expr); } while (0)
92
94#define ASE_ASSERT_WARN(expr) do { if (expr) [[likely]] break; ::Ase::assertion_failed (#expr); } while (0)
95
96#ifndef NDEBUG
98#define ASE_PARANOID(expr) do { if (expr) [[likely]] break; ::Ase::assertion_failed (#expr); } while (0)
99#else
100#define ASE_PARANOID(expr) do { break; } while (expr)
101#endif
102
103
105#define ASE_DIE(msg) do { errno = 0; ::Ase::perror_die (msg); } while (0)
106
108#define ASE_PERROR_DIE(msg) do { ::Ase::perror_die (msg); } while (0)
109
111#define ASE_CLASS_NON_COPYABLE(ClassName) \
112 /*copy-ctor*/ ClassName (const ClassName&) = delete; \
113 ClassName& operator= (const ClassName&) = delete
114
116#define ASE_STRUCT_DECLS(Klass) \
117 struct Klass; \
118 using ASE_CPP_PASTE2 (Klass, P) = ::std::shared_ptr<Klass>; \
119 using ASE_CPP_PASTE2 (Klass, S) = ::std::vector<Klass>;
120
122#define ASE_CLASS_DECLS(Klass) \
123 class Klass; \
124 using ASE_CPP_PASTE2 (Klass, W) = ::std::weak_ptr<Klass>; \
125 using ASE_CPP_PASTE2 (Klass, P) = ::std::shared_ptr<Klass>; \
126 using ASE_CPP_PASTE2 (Klass, S) = ::std::vector<ASE_CPP_PASTE2 (Klass, P)>;
127
128// == Operations on flags enum classes ==
129#define ASE_DEFINE_ENUM_EQUALITY(Enum) \
130 constexpr bool operator== (Enum v, int64_t n) { return int64_t (v) == n; } \
131 constexpr bool operator== (int64_t n, Enum v) { return n == int64_t (v); } \
132 constexpr bool operator!= (Enum v, int64_t n) { return int64_t (v) != n; } \
133 constexpr bool operator!= (int64_t n, Enum v) { return n != int64_t (v); }
134#define ASE_DEFINE_FLAGS_ARITHMETIC(Enum) \
135 constexpr int64_t operator>> (Enum v, int64_t n) { return int64_t (v) >> n; } \
136 constexpr int64_t operator<< (Enum v, int64_t n) { return int64_t (v) << n; } \
137 constexpr int64_t operator^ (Enum v, int64_t n) { return int64_t (v) ^ n; } \
138 constexpr int64_t operator^ (int64_t n, Enum v) { return n ^ int64_t (v); } \
139 constexpr Enum operator^ (Enum v, Enum w) { return Enum (int64_t (v) ^ w); } \
140 constexpr int64_t operator| (Enum v, int64_t n) { return int64_t (v) | n; } \
141 constexpr int64_t operator| (int64_t n, Enum v) { return n | int64_t (v); } \
142 constexpr Enum operator| (Enum v, Enum w) { return Enum (int64_t (v) | w); } \
143 constexpr int64_t operator& (Enum v, int64_t n) { return int64_t (v) & n; } \
144 constexpr int64_t operator& (int64_t n, Enum v) { return n & int64_t (v); } \
145 constexpr Enum operator& (Enum v, Enum w) { return Enum (int64_t (v) & w); } \
146 constexpr bool operator! (Enum e) noexcept { return static_cast<std::underlying_type_t<Enum>> (e) == 0; } \
147 constexpr int64_t operator~ (Enum v) { return ~int64_t (v); } \
148 constexpr int64_t operator+ (Enum v) { return +int64_t (v); } \
149 constexpr int64_t operator- (Enum v) { return -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 int64_t operator* (Enum v, int64_t n) { return int64_t (v) * n; } \
155 constexpr int64_t operator* (int64_t n, Enum v) { return n * int64_t (v); } \
156 constexpr int64_t operator/ (Enum v, int64_t n) { return int64_t (v) / n; } \
157 constexpr int64_t operator/ (int64_t n, Enum v) { return n / int64_t (v); } \
158 constexpr int64_t operator% (Enum v, int64_t n) { return int64_t (v) % n; } \
159 constexpr int64_t operator% (int64_t n, Enum v) { return n % int64_t (v); } \
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 constexpr Enum& operator&= (Enum &e, int64_t n) { e = Enum (e & n); return e; } \
163 constexpr Enum& operator+= (Enum &e, int64_t n) { e = Enum (e + n); return e; } \
164 constexpr Enum& operator-= (Enum &e, int64_t n) { e = Enum (e - n); return e; } \
165 constexpr Enum& operator*= (Enum &e, int64_t n) { e = Enum (e * n); return e; } \
166 constexpr Enum& operator/= (Enum &e, int64_t n) { e = Enum (e / n); return e; } \
167 constexpr Enum& operator%= (Enum &e, int64_t n) { e = Enum (e % n); return e; } \
168 ASE_DEFINE_ENUM_EQUALITY (Enum)
169
171template<typename UInt> static inline constexpr UInt
172rotr (UInt bits, uint32_t offset)
173{
174 const uint32_t wrapped_bits = sizeof (bits) * 8 - offset;
175 return (bits >> offset) | (bits << wrapped_bits);
176}
177
179template<typename UInt> static inline constexpr UInt
180rotl (UInt bits, uint32_t offset)
181{
182 const uint32_t wrapped_bits = sizeof (bits) * 8 - offset;
183 return (bits << offset) | (bits >> wrapped_bits);
184}
185
187template<typename T> static inline constexpr T
188divmod (T dividend, T divisor, T *reminderp)
189{
190 *reminderp = dividend % divisor; // uses single DIV or IDIV for %
191 return dividend / divisor; // and / in gcc and clang with -O1
192}
193
195const char* cxx_demangle (const std::type_info &typeinfo) noexcept;
196std::string cxx_demangle (const char *mangled_identifier) noexcept;
197
199template<class T> ASE_PURE static inline const char*
200typeid_name()
201{
202 return cxx_demangle (typeid (T));
203}
204
206template<class T> ASE_PURE static inline const char*
207typeid_name (T &obj)
208{
209 return cxx_demangle (typeid (obj));
210}
211
213template<typename T> static T*
214unalias_ptr (T *ptr)
215{
216 asm ("" : "+r" (ptr)); // accept ptr and yield ptr
217 return ptr;
218}
219
222protected:
223 virtual ~VirtualBase() noexcept = 0;
224};
226
228void perror_die (const std::string &msg) noexcept ASE_NORETURN;
229void assertion_failed (const char *msg = nullptr, const char *file = __builtin_FILE(),
230 int line = __builtin_LINE(), const char *func = __builtin_FUNCTION()) noexcept;
231void assertion_fatal (const char *msg = nullptr, const char *file = __builtin_FILE(),
232 int line = __builtin_LINE(), const char *func = __builtin_FUNCTION()) noexcept ASE_NORETURN;
233
235void ase_rethrow (std::exception_ptr exception = std::current_exception());
236
238extern inline constexpr bool
239constexpr_equals (const char *a, const char *b, size_t n)
240{
241 return n == 0 || (a[0] == b[0] && (a[0] == 0 || constexpr_equals (a + 1, b + 1, n - 1)));
242}
243
245template<class Type, class ...Ts> ASE_ALWAYS_INLINE inline void
246new_inplace (Type &typemem, Ts &&... args)
247{
248 new (&typemem) Type (std::forward<Ts> (args)...);
249}
250
252template<class Type> ASE_ALWAYS_INLINE inline void
253delete_inplace (Type &typemem)
254{
255 typemem.~Type();
256}
257
259template<class T> void
261{
262 delete o; // automatically handles nullptr
263}
264
266template<bool value> using REQUIRES = typename ::std::enable_if<value, bool>::type;
267
269template<bool value> using REQUIRESv = typename ::std::enable_if<value, void>::type;
270
275#define ASE_DEFINE_MAKE_SHARED(CLASS) \
276 struct MakeSharedAllocator_ : std::allocator<CLASS> { \
277 template<typename ...Args> \
278 static void construct (CLASS *p, Args &&...args) \
279 { ::new (p) CLASS (std::forward<Args> (args)...); } \
280 static void destroy (CLASS *p) \
281 { p->~CLASS (); } \
282 template<typename U> struct rebind { \
283 using other = \
284 std::conditional_t<std::is_same<U, CLASS>::value, \
285 MakeSharedAllocator_, std::allocator<U>>; \
286 }; \
287 }; \
288 template<typename ...Args> static std::shared_ptr<CLASS> \
289 make_shared (Args &&...args) \
290 { \
291 return std::allocate_shared<CLASS> (MakeSharedAllocator_(), \
292 std::forward<Args> (args)...); \
293 }
294
311template<class Target, class Source> std::shared_ptr<typename std::remove_pointer<Target>::type>
312shared_ptr_cast (Source *object)
313{
314 if (!object)
315 return nullptr;
316 // construct shared_ptr if possible
317 typedef decltype (object->shared_from_this()) ObjectP;
318 ObjectP sptr;
320 try {
321 sptr = object->shared_from_this();
322 } catch (const std::bad_weak_ptr&) {
323 return nullptr;
324 }
325 else // for non-pointers, allow bad_weak_ptr exceptions
326 sptr = object->shared_from_this();
327 // cast into target shared_ptr<> type
329}
331template<class Target, class Source> const std::shared_ptr<typename std::remove_pointer<Target>::type>
332shared_ptr_cast (const Source *object)
333{
334 return shared_ptr_cast<Target> (const_cast<Source*> (object));
335}
337template<class Target, class Source> std::shared_ptr<typename std::remove_pointer<Target>::type>
343template<class Target, class Source> const std::shared_ptr<typename std::remove_pointer<Target>::type>
345{
346 return shared_ptr_cast<Target> (const_cast<std::shared_ptr<Source>&> (sptr));
347}
348
351shared_ptr_from (Source *object)
352{
353 // ultimately calls shared_from_this()
354 return shared_ptr_cast<Source> (object);
355}
356
358template<class C> std::shared_ptr<C>
360{
361 std::shared_ptr<C> cptr = wptr.lock();
362 if (__builtin_expect (!!cptr, true))
363 return cptr; // fast path
364 std::shared_ptr<C> nptr = ctor();
365 { // C++20 has: std::atomic<std::weak_ptr<C>>::compare_exchange
366 static std::mutex mutex;
367 std::lock_guard<std::mutex> locker (mutex);
368 cptr = wptr.lock();
369 if (!cptr)
370 wptr = cptr = nptr;
371 }
372 return cptr;
373}
374
379template<class Class>
380class Persistent final {
381 static_assert (std::is_class<Class>::value, "Persistent<Class> requires class template argument");
382 uint64 mem_[(sizeof (Class) + sizeof (uint64) - 1) / sizeof (uint64)] = { 0, };
383 Class *ptr_ = nullptr;
384 void
385 initialize() ASE_NOINLINE
386 {
387 static std::mutex mtx;
389 if (ptr_ == nullptr)
390 ptr_ = new (mem_) Class(); // exclusive construction
391 }
392public:
394 constexpr Persistent () noexcept {}
396 explicit operator bool () const ASE_PURE { return ptr_ != nullptr; }
398 Class& operator* () ASE_PURE { return *operator->(); }
400 Class* operator-> () ASE_PURE
401 {
402 if (ASE_UNLIKELY (ptr_ == nullptr))
403 initialize();
404 return ptr_;
405 }
406};
407
409struct Id32 {
410 template<typename T,
411 REQUIRES< (sizeof (T) <= 4 && (std::is_integral<T>::value || std::is_enum<T>::value)) > = true>
412 constexpr
413 Id32 (T eid) :
414 id (uint32_t (eid))
415 {}
416 operator uint32_t () const noexcept { return id; }
417 bool operator== (int64_t i) const noexcept { return id == i; }
418 bool operator!= (int64_t i) const noexcept { return id != i; }
419 friend bool operator== (int64_t i, const Id32 &id) { return id.operator== (i); }
420 friend bool operator!= (int64_t i, const Id32 &id) { return id.operator!= (i); }
421 uint32_t id;
422};
423
424} // Ase
425
426#endif // __ASE_CXXAUX_HH__
Create an instance of Class on demand that is constructed and never destructed.
Definition cxxaux.hh:380
constexpr Persistent() noexcept
A constexpr constructor avoids the static initialization order fiasco.
Definition cxxaux.hh:394
Class * operator->() __attribute__((__pure__))
Retrieve pointer to Class instance, always returns the same pointer.
Definition cxxaux.hh:400
Class & operator*() __attribute__((__pure__))
Retrieve reference to Class instance, always returns the same reference.
Definition cxxaux.hh:398
#define ASE_UNLIKELY(expr)
Compiler hint to optimize for expr evaluating to false.
Definition cxxaux.hh:46
typedef int
The Anklang C++ API namespace.
Definition api.hh:9
void delete_inplace(Type &typemem)
Call inplace delete operator by automatically inferring the Type.
Definition cxxaux.hh:253
uint64_t uint64
A 64-bit unsigned integer, use PRI*64 in format strings.
Definition cxxaux.hh:25
void call_delete(T *o)
Simple way to create a standalone callback to delete an object of type T.
Definition cxxaux.hh:260
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.
Definition cxxaux.cc:81
int32_t int32
A 32-bit signed integer.
Definition cxxaux.hh:28
int16_t int16
A 16-bit signed integer.
Definition cxxaux.hh:27
uint8_t uint8
An 8-bit unsigned integer.
Definition cxxaux.hh:22
const char * cxx_demangle(const std::type_info &typeinfo) noexcept
Demangle a std::typeinfo.name() string into a proper C++ type name.
Definition cxxaux.cc:23
int8_t int8
An 8-bit signed integer.
Definition cxxaux.hh:26
int64_t int64
A 64-bit unsigned integer, use PRI*64 in format strings.
Definition cxxaux.hh:29
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.
Definition cxxaux.hh:359
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...
Definition cxxaux.hh:266
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.
Definition cxxaux.cc:74
void perror_die(const std::string &msg) noexcept
Issue a warning about an assertion error.
Definition cxxaux.cc:62
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...
Definition cxxaux.hh:269
constexpr bool constexpr_equals(const char *a, const char *b, size_t n)
Test string equality at compile time.
Definition cxxaux.hh:239
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<>.
Definition cxxaux.hh:351
uint32_t unichar
A 32-bit unsigned integer used for Unicode characters.
Definition cxxaux.hh:30
uint16_t uint16
A 16-bit unsigned integer.
Definition cxxaux.hh:23
void new_inplace(Type &typemem, Ts &&... args)
Call inplace new operator by automatically inferring the Type.
Definition cxxaux.hh:246
uint32_t uint32
A 32-bit unsigned integer.
Definition cxxaux.hh:24
std::shared_ptr< typename std::remove_pointer< Target >::type > shared_ptr_cast(Source *object)
Shorthand for std::dynamic_pointer_cast<>(shared_from_this()).
Definition cxxaux.hh:312
uint32_t uint
Provide 'uint' as convenience type.
Definition cxxaux.hh:18
void ase_rethrow(std::exception_ptr exception)
Helper to trace rethrown exceptions.
Definition cxxaux.cc:87
T rotl(T... args)
typedef uint32_t
Helper class for integer IDs up to 32 Bit, possibly of enum type.
Definition cxxaux.hh:409
Common base type to allow casting between polymorphic classes.
Definition cxxaux.hh:221