1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
|
#pragma once
#include <csignal>
#include <cstdio>
#include <cstring>
namespace Assert::Detail {
#ifdef _WIN32
// MinGW has weird behavior with SIGTRAP,
// and debugging won't be done on Windows anyway,
// so SIGABRT is used instead.
constexpr int DebugSignal = SIGABRT;
#else
constexpr int DebugSignal = SIGTRAP;
#endif
}
// https://stackoverflow.com/a/26100478/11342122
// Two levels are needed to make sure that the argument is expanded before stringification
#define _ASSERT_IS_DEFINED(x) _ASSERT_IS_DEFINED2(x)
// TODO: This doesn't compile away on -O0, but it's not a big deal
#define _ASSERT_IS_DEFINED2(x) (#x[0] == 0 || (#x[0] >= '1' && #x[0] <= '9'))
// Stopping macro, non-fatal in debug mode
#define _ASSERT_STOP (_ASSERT_IS_DEFINED(NDEBUG) ? std::abort() : (void)raise(Assert::Detail::DebugSignal))
// Assertion message macros, with optional message
#define _ASSERT_NOTIFY_NO_MESSAGE(start) fprintf(stderr, start ".\n", __FILE__, __LINE__)
#define _ASSERT_NOTIFY_WITH_MESSAGE(start, message) fprintf(stderr, start ": %s\n", __FILE__, __LINE__, message "")
#define _ASSERT_NOTIFY(start, ...) ((strcmp(__VA_ARGS__ "", "") == 0) ? _ASSERT_NOTIFY_NO_MESSAGE(start) : _ASSERT_NOTIFY_WITH_MESSAGE(start, __VA_ARGS__))
// Debuggable assertion macro, with optional message
#define ASSERT(condition, ...) do { \
if (__builtin_expect(!(condition), 0)) { \
_ASSERT_NOTIFY("ASSERT(" #condition ") failed at %s:%d", __VA_ARGS__); \
_ASSERT_STOP; \
} \
} while (0)
// Debuggable unreachable macro, with optional message
#define UNREACHABLE(...) do { \
_ASSERT_NOTIFY("UNREACHABLE() reached at %s:%d", __VA_ARGS__); \
_ASSERT_STOP; \
} while (0)
|