#pragma once #include #include #include 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)