diff --git a/include/bx/bx.h b/include/bx/bx.h index c309bce..a366b7c 100644 --- a/include/bx/bx.h +++ b/include/bx/bx.h @@ -113,6 +113,32 @@ namespace bx /// Unknown source code location. static constexpr LocationFull kUnknownLocationFull("Unknown?", "Unknown?", 0); + /// Assert handler function. + /// + /// @param[in] _location Source code location where function is called. + /// @param[in] _format Printf style format. + /// @param[in] ... Arguments for `_format` specification. + /// + /// @returns True if assert should stop code execution, otherwise returns false. + /// + typedef bool (*AssertHandlerFn)(const Location& _location, const char* _format, va_list _argList); + + /// Set assert handler function. + /// + /// @param[in] _assertHandlerFn Pointer to AssertHandlerFn function. + /// + void setAssertHandler(AssertHandlerFn _assertHandlerFn); + + /// Assert function calls AssertHandlerFn. + /// + /// @param[in] _location Source code location where function is called. + /// @param[in] _format Printf style format. + /// @param[in] ... Arguments for `_format` specification. + /// + /// @returns True if assert should stop code execution, otherwise returns false. + /// + bool assertFunction(const Location& _location, const char* _format, ...); + /// Arithmetic type `Ty` limits. template()> struct LimitsT; diff --git a/include/bx/macros.h b/include/bx/macros.h index d66cb20..1bca118 100644 --- a/include/bx/macros.h +++ b/include/bx/macros.h @@ -302,22 +302,22 @@ } \ BX_MACRO_BLOCK_END -#define _BX_ASSERT(_condition, _format, ...) \ - BX_MACRO_BLOCK_BEGIN \ - if (!BX_IGNORE_C4127(_condition) ) \ - { \ - BX_TRACE("ASSERT " _format, ##__VA_ARGS__); \ - bx::debugBreak(); \ - } \ +#define _BX_ASSERT(_condition, _format, ...) \ + BX_MACRO_BLOCK_BEGIN \ + if (!BX_IGNORE_C4127(_condition) \ + && bx::assertFunction(bx::Location::current(), "ASSERT " #_condition " -> " _format, ##__VA_ARGS__) ) \ + { \ + bx::debugBreak(); \ + } \ BX_MACRO_BLOCK_END -#define _BX_ASSERT_LOC(_location, _condition, _format, ...) \ - BX_MACRO_BLOCK_BEGIN \ - if (!BX_IGNORE_C4127(_condition) ) \ - { \ - _BX_TRACE_LOC(_location, "ASSERT " _format, ##__VA_ARGS__); \ - bx::debugBreak(); \ - } \ +#define _BX_ASSERT_LOC(_location, _condition, _format, ...) \ + BX_MACRO_BLOCK_BEGIN \ + if (!BX_IGNORE_C4127(_condition) \ + && bx::assertFunction(_location, "ASSERT " #_condition " -> " _format, ##__VA_ARGS__) ) \ + { \ + bx::debugBreak(); \ + } \ BX_MACRO_BLOCK_END #define _BX_WARN_LOC(_location, _condition, _format, ...) \ diff --git a/src/bx.cpp b/src/bx.cpp index dc27b19..d0af3e7 100644 --- a/src/bx.cpp +++ b/src/bx.cpp @@ -22,6 +22,47 @@ namespace bx return LocationFull(_function, _filePath, _line); } + static bool defaultAssertHandler(const Location& _location, const char* _format, va_list _argList) + { + char temp[8192]; + int32_t pos = 0; + + pos += snprintf(&temp[pos], max(0, sizeof(temp)-pos), "%s(%d): " + , _location.filePath + , _location.line + ); + pos += vsnprintf(&temp[pos], max(0, sizeof(temp)-pos), _format, _argList); + pos += snprintf(&temp[pos], max(0, sizeof(temp)-pos), "\n"); + debugOutput(temp); + + return true; + } + + static AssertHandlerFn s_assertHandler = defaultAssertHandler; + + void setAssertHandler(AssertHandlerFn _assertHandlerFn) + { + BX_WARN(defaultAssertHandler == s_assertHandler, "Assert handler is already set."); + + if (defaultAssertHandler == s_assertHandler) + { + s_assertHandler = NULL == _assertHandlerFn + ? defaultAssertHandler + : _assertHandlerFn + ; + } + } + + bool assertFunction(const Location& _location, const char* _format, ...) + { + va_list argList; + va_start(argList, _format); + const bool result = s_assertHandler(_location, _format, argList); + va_end(argList); + + return result; + } + void swap(void* _a, void* _b, size_t _numBytes) { uint8_t* lhs = (uint8_t*)_a; diff --git a/tests/run_test.cpp b/tests/run_test.cpp index c754f7d..48b1d3a 100644 --- a/tests/run_test.cpp +++ b/tests/run_test.cpp @@ -5,9 +5,25 @@ #define CATCH_CONFIG_RUNNER #include "test.h" +#include + +bool testAssertHandler(const bx::Location& _location, const char* _format, va_list _argList) +{ + bx::printf("%s(%d): ", _location.filePath, _location.line); + bx::vprintf(_format, _argList); + bx::printf("\n"); + + // Throwing exceptions is required for testing asserts being trigged. + // Use REQUIRE_THROWS to test asserts. + throw std::exception(); + + return true; +} int runAllTests(int _argc, const char* _argv[]) { + bx::setAssertHandler(testAssertHandler); + DBG("Compiler: " BX_COMPILER_NAME ", CPU: " BX_CPU_NAME ", Architecture: " BX_ARCH_NAME