Browse Source

Added configurable assert handler function.

Бранимир Караџић 2 years ago
parent
commit
44fe98c53c
4 changed files with 97 additions and 14 deletions
  1. 26 0
      include/bx/bx.h
  2. 14 14
      include/bx/macros.h
  3. 41 0
      src/bx.cpp
  4. 16 0
      tests/run_test.cpp

+ 26 - 0
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<typename Ty, bool SignT = isSigned<Ty>()>
 	struct LimitsT;

+ 14 - 14
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, ...)             \

+ 41 - 0
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;

+ 16 - 0
tests/run_test.cpp

@@ -5,9 +5,25 @@
 
 #define CATCH_CONFIG_RUNNER
 #include "test.h"
+#include <bx/string.h>
+
+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