142 lines
		
	
	
		
			5.0 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			142 lines
		
	
	
		
			5.0 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| 
 | |
| #pragma once
 | |
| 
 | |
| #if !defined(MIJIN_DEBUG_ASSERT_HPP_INCLUDED)
 | |
| #define MIJIN_DEBUG_ASSERT_HPP_INCLUDED 1
 | |
| 
 | |
| #include <cstdio>
 | |
| #include <cstdlib>
 | |
| #include <source_location>
 | |
| 
 | |
| #ifdef _WIN32
 | |
| #pragma comment(lib, "kernel32")
 | |
| extern "C" __declspec(dllimport) void __stdcall DebugBreak();
 | |
| #define MIJIN_TRAP() DebugBreak()
 | |
| #define MIJIN_FUNC() __FUNCSIG__
 | |
| #else // _WIN32
 | |
| #include <csignal>
 | |
| #define MIJIN_TRAP() (void) std::raise(SIGTRAP)
 | |
| #define MIJIN_FUNC() "" // TODO: __PRETTY_FUNCTION__ is not working for some reason -.-
 | |
| #endif // !_WIN32
 | |
| 
 | |
| namespace mijin
 | |
| {
 | |
| 
 | |
| //
 | |
| // public defines
 | |
| //
 | |
| 
 | |
| #if MIJIN_DEBUG
 | |
| 
 | |
| #define MIJIN_RAISE_ERROR(msg, source_loc) \
 | |
| switch (mijin::handleError(msg, source_loc))  \
 | |
| {                                             \
 | |
|     case mijin::ErrorHandling::CONTINUE:      \
 | |
|         break;                                \
 | |
|     case mijin::ErrorHandling::TRAP:          \
 | |
|         MIJIN_TRAP();                         \
 | |
|         [[fallthrough]];                      \
 | |
|     default: /* ABORT */                      \
 | |
|         std::abort();                         \
 | |
| }
 | |
| 
 | |
| #define MIJIN_ERROR(msg) \
 | |
| MIJIN_RAISE_ERROR(msg, std::source_location::current())
 | |
| 
 | |
| #define MIJIN_FATAL(msg) \
 | |
| MIJIN_ERROR(msg)         \
 | |
| std::abort()
 | |
| 
 | |
| // TODO: make ignoreAll work (static variables cannot be used in constexpr functions)
 | |
| #define MIJIN_ASSERT(condition, msg)                                               \
 | |
| if (!static_cast<bool>(condition))                                                 \
 | |
| {                                                                                  \
 | |
|     /* static bool ignoreAll = false; */                                           \
 | |
|     if (true) /*!ignoreAll */                                                      \
 | |
|     {                                                                              \
 | |
|         const mijin::AssertionResult assertion_result__ = mijin::handleAssert(     \
 | |
|                 #condition, msg, std::source_location::current());                 \
 | |
|         switch (assertion_result__)                                                \
 | |
|         {                                                                          \
 | |
|         case mijin::AssertionResult::ABORT:                                        \
 | |
|             std::abort();                                                          \
 | |
|             break;                                                                 \
 | |
|         case mijin::AssertionResult::IGNORE:                                       \
 | |
|             /*break*/;                                                             \
 | |
|         case mijin::AssertionResult::IGNORE_ALL:                                   \
 | |
|             /* ignoreAll = true; */                                                \
 | |
|             break;                                                                 \
 | |
|         default: /* ERROR */                                                       \
 | |
|             MIJIN_ERROR("Debug assertion failed: " #condition "\nMessage:  " msg); \
 | |
|             break;                                                                 \
 | |
|         }                                                                          \
 | |
|     }                                                                              \
 | |
| }
 | |
| 
 | |
| #define MIJIN_ASSERT_FATAL(condition, msg)                                  \
 | |
| if (!static_cast<bool>(condition))                                          \
 | |
| {                                                                           \
 | |
|     MIJIN_ERROR("Debug assertion failed: " #condition "\nMessage: " msg);   \
 | |
| }
 | |
| #else // MIJIN_DEBUG
 | |
| #define MIJIN_ERROR(...)
 | |
| #define MIJIN_FATAL(...) std::abort()
 | |
| #define MIJIN_ASSERT(...)
 | |
| #define MIJIN_ASSERT_FATAL(...)
 | |
| #endif // !MIJIN_DEBUG  
 | |
| 
 | |
| //
 | |
| // public constants
 | |
| //
 | |
| 
 | |
| //
 | |
| // public types
 | |
| //
 | |
| 
 | |
| enum class AssertionResult
 | |
| {
 | |
|     ABORT = -1,    // call std::abort()
 | |
|     ERROR = 0,     // raise an error using MIJIN_ERROR() handling
 | |
|     IGNORE = 1,    // do nothing
 | |
|     IGNORE_ALL = 2 // do nothing and nevery halt again (not implemented yet)
 | |
| };
 | |
| 
 | |
| enum class ErrorHandling
 | |
| {
 | |
|     TRAP = 0,
 | |
|     CONTINUE = 1,
 | |
|     ABORT = 2
 | |
| };
 | |
| 
 | |
| //
 | |
| // public functions
 | |
| //
 | |
| 
 | |
| #ifdef MIJIN_USE_CUSTOM_ASSERTION_HANDLER
 | |
| AssertionResult handleAssert(const char* condition,
 | |
|         const char* message, const std::source_location& location);
 | |
| #else
 | |
| constexpr AssertionResult handleAssert(const char* /* condition */,
 | |
|         const char* /* message */, const std::source_location& /* location */)
 | |
| {
 | |
|     return AssertionResult::ERROR;
 | |
| }
 | |
| #endif // MIJIN_USE_CUSTOM_ASSERTION_HANDLER
 | |
| 
 | |
| #ifdef MIJIN_USE_CUSTOM_ERROR_HANDLER
 | |
| ErrorHandling handleError(const char* message, const std::source_location& location);
 | |
| #else
 | |
| inline ErrorHandling handleError(const char* message, const std::source_location& location) noexcept
 | |
| {
 | |
|     std::puts(message);
 | |
|     std::printf("Function: %s\n", location.function_name());
 | |
|     std::printf("Location: %s:%d:%d\n", location.file_name(), location.line(), location.column());
 | |
|     (void) std::fflush(stdout);
 | |
|     return ErrorHandling::TRAP;
 | |
| }
 | |
| #endif
 | |
| 
 | |
| } // namespace mijin
 | |
| 
 | |
| #endif // !defined(MIJIN_DEBUG_ASSERT_HPP_INCLUDED)
 |