diff --git a/include/blt/std/assert.h b/include/blt/std/assert.h new file mode 100644 index 0000000..e9f8960 --- /dev/null +++ b/include/blt/std/assert.h @@ -0,0 +1,44 @@ +/* + * Created by Brett on 23/08/23. + * Licensed under GNU General Public License V3.0 + * See LICENSE file for license detail + */ + +#ifndef BLT_ASSERT_H +#define BLT_ASSERT_H + +#ifdef __GNUC__ + + #include + #include + +#endif + +#ifdef __GNUC__ + #define BLT_STACK_TRACE(number) void* ptrs[number]; \ + int size = backtrace(ptrs, number); \ + char** messages = backtrace_symbols(ptrs, size); + + #define BLT_FREE_STACK_TRACE() free(messages); +#else + #define BLT_STACK_TRACE(number) void(); + #define BLT_FREE_STACK_TRACE() void(); +#endif + +namespace blt +{ + void printStacktrace(char** messages, int size, const char* path, int line); + + void b_assert_failed(const char* expression, const char* path, int line); + + void b_throw(const char* what, const char* path, int line); +} + +// prints error with stack trace if assertion fails. Does not stop execution. +#define blt_assert(expr) static_cast(expr) ? void(0) : blt::b_assert_failed(#expr, __FILE__, __LINE__) +// prints error with stack trace then exits with failure. +#define BLT_ASSERT(expr) {static_cast(expr) ? void(0) : blt::b_assert_failed(#expr, __FILE__, __LINE__); std::exit(EXIT_FAILURE); } +#define blt_throw(throwable) {blt::b_throw(throwable.what(), __FILE__, __LINE__); throw throwable;} + + +#endif //BLT_ASSERT_H diff --git a/src/blt/std/assert.cpp b/src/blt/std/assert.cpp new file mode 100644 index 0000000..5472479 --- /dev/null +++ b/src/blt/std/assert.cpp @@ -0,0 +1,92 @@ +/* + * Created by Brett on 23/08/23. + * Licensed under GNU General Public License V3.0 + * See LICENSE file for license detail + */ +#include +#include +#include +#include +#include +#include + +namespace blt { + + static inline std::string _macro_filename(const std::string& path){ + auto paths = blt::string::split(path, "/"); + auto final = paths[paths.size()-1]; + if (final == "/") + return paths[paths.size()-2]; + return final; + } + + void b_throw(const char* what, const char* path, int line) + { +#ifdef __GNUC__ + BLT_STACK_TRACE(50); + + BLT_ERROR("An exception '%s' has occurred in file '%s:%d'", what, path, line); + BLT_ERROR("Stack Trace:"); + printStacktrace(messages, size, path, line); + + BLT_FREE_STACK_TRACE(); +#endif + } + + void b_assert_failed(const char* expression, const char* path, int line) + { +#ifdef __GNUC__ + BLT_STACK_TRACE(50); + + BLT_ERROR("The assertion '%s' has failed in file '%s:%d'", expression, path, line); + BLT_ERROR("Stack Trace:"); + + backtrace_symbols(ptrs, size); + + printStacktrace(messages, size, path, line); + + BLT_FREE_STACK_TRACE(); +#endif + } + + void printStacktrace(char** messages, int size, const char* path, int line) + { +#ifdef __GNUC__ + for (int i = 1; i < size; i++){ + int tabs = i - 1; + std::string buffer; + for (int j = 0; j < tabs; j++) + buffer += '\t'; + if (i != 1) + buffer += "тоб"; + + std::string message(messages[i]); + + auto f = message.find('('); + + auto mes = message.substr(f + 1, message.size()); + std::string loc; + + buffer += message.substr(0, f); + if (i == 1) + { + loc = '\''; + loc += _macro_filename(path); + loc += ':'; + loc += std::to_string(line); + loc += '\''; + } else + loc = mes.substr(0, mes.find('+')); + + if (!loc.empty()) + buffer += " in "; + buffer += loc; + + + BLT_ERROR(buffer); + } +#endif + } + + +} \ No newline at end of file