/********************************************************************* * \file Assert.hpp * * \author Romain BOULLARD * \date October 2025 *********************************************************************/ #ifndef BIN2CPP_ASSERT_HPP #define BIN2CPP_ASSERT_HPP #include #if defined BIN2CPP_NOT_OPTIMIZED #include #include #include #if defined BIN2CPP_LINUX #include #endif namespace Bin2CPP { class AssertHandler { public: AssertHandler() = delete; AssertHandler(const AssertHandler& p_handler) = delete; AssertHandler(AssertHandler&& p_handler) = delete; ~AssertHandler() = delete; /** * Handle an assertion. * * \param p_location Location of the assertion. * \param p_stacktrace The stack trace * \param p_format Format string for the assertion message. * \param p_args Arguments for the format string. */ template static void Handle(const std::source_location& p_location, const std::string_view p_stacktrace, std::format_string p_format, ARGS&&... p_args) { BIN2CPP_LOG_FATAL("Assert: {} (File:{}, Line:{}, Function:{})\n{}", std::format(p_format, std::forward(p_args)...), p_location.file_name(), p_location.line(), p_location.function_name(), p_stacktrace); } AssertHandler& operator=(const AssertHandler& p_handler) = delete; AssertHandler& operator=(AssertHandler&& p_handler) = delete; }; } // namespace Bin2CPP #if defined BIN2CPP_WINDOWS #define BIN2CPP_BREAK \ do \ { \ __debugbreak(); \ } while (false) #elif defined BIN2CPP_LINUX #define BIN2CPP_BREAK \ do \ { \ std::raise(SIGTRAP); \ } while (false) #endif #define BIN2CPP_ASSERT(p_assert, p_message, ...) \ do \ { \ constexpr std::source_location location = std::source_location::current(); \ if (!(p_assert)) [[unlikely]] \ { \ Bin2CPP::AssertHandler::Handle(location, \ cpptrace::generate_trace().to_string(), \ p_message __VA_OPT__(, ) __VA_ARGS__); \ if (Bin2CPP::Singleton::HasInstance()) \ { \ Bin2CPP::Singleton::Instance().Flush(); \ } \ BIN2CPP_BREAK; \ } \ } while (false) #define BIN2CPP_SOFT_ASSERT(p_assert, p_message, ...) \ do \ { \ constexpr std::source_location location = std::source_location::current(); \ if (!(p_assert)) [[unlikely]] \ { \ Bin2CPP::AssertHandler::Handle(location, \ cpptrace::generate_trace().to_string(), \ p_message __VA_OPT__(, ) __VA_ARGS__); \ if (Bin2CPP::Singleton::HasInstance()) \ { \ Bin2CPP::Singleton::Instance().Flush(); \ } \ BIN2CPP_BREAK; \ } \ } while (false) #define BIN2CPP_CRITICAL_ASSERT(p_assert, p_message, ...) \ do \ { \ constexpr std::source_location location = std::source_location::current(); \ if (!(p_assert)) [[unlikely]] \ { \ Bin2CPP::AssertHandler::Handle(location, \ cpptrace::generate_trace().to_string(), \ p_message __VA_OPT__(, ) __VA_ARGS__); \ if (Bin2CPP::Singleton::HasInstance()) \ { \ Bin2CPP::Singleton::Instance().Flush(); \ } \ BIN2CPP_BREAK; \ std::abort(); \ } \ } while (false) #else #define BIN2CPP_ASSERT(p_assert, p_message, ...) #define BIN2CPP_SOFT_ASSERT(p_assert, p_message, ...) #define BIN2CPP_CRITICAL_ASSERT(p_assert, p_message, ...) #endif #endif