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)
 |