#ifndef SUPPORT_ASSERT_CHECKPOINT_H #define SUPPORT_ASSERT_CHECKPOINT_H #include #include #include struct Checkpoint { const char* file; const char* func; int line; const char* msg; Checkpoint() : file(nullptr) , func(nullptr) , line(-1) , msg(nullptr) {} Checkpoint(const char* xfile, const char* xfunc, int xline, const char* xmsg) : file(xfile) , func(xfunc) , line(xline) , msg(xmsg) {} template void print(Stream& s) const { if (!file) { s << "NO CHECKPOINT\n"; return; } s << file << ":" << line << " " << func << ": Checkpoint"; if (msg) { s << " '" << msg << "'"; } s << '\n'; } }; inline Checkpoint& globalCheckpoint() { static Checkpoint C; return C; } inline void clearCheckpoint() { globalCheckpoint() = Checkpoint(); } #if defined(__GNUC__) # define CHECKPOINT_FUNCTION_NAME __PRETTY_FUNCTION__ #else # define CHECKPOINT_FUNCTION_NAME __func__ #endif #define CHECKPOINT(msg) globalCheckpoint() = Checkpoint(__FILE__, CHECKPOINT_FUNCTION_NAME, __LINE__, msg); inline void checkpointSignalHandler(int signal) { if (signal == SIGABRT) { globalCheckpoint().print(std::cerr); } else { std::cerr << "Unexpected signal " << signal << " received\n"; } std::_Exit(EXIT_FAILURE); } inline bool initCheckpointHandler() { using HandlerT = void (*)(int); static bool isInit = false; if (isInit) { return true; } HandlerT prev_h = std::signal(SIGABRT, checkpointSignalHandler); if (prev_h == SIG_ERR) { std::cerr << "Setup failed.\n"; std::_Exit(EXIT_FAILURE); } isInit = true; return false; } static bool initDummy = initCheckpointHandler(); #endif