From 0b473c0f8ad30dc6bf0f786ec3d3c29540dfe53e Mon Sep 17 00:00:00 2001 From: NaifBanana <30419422+NaifBanana@users.noreply.github.com> Date: Mon, 6 Apr 2026 02:22:28 -0500 Subject: [PATCH 01/11] Made errors mostly work as hoped --- CMakeLists.txt | 3 +- engine/NBCore/ANSITerm.hpp | 6 - engine/NBCore/CMakeLists.txt | 8 +- engine/NBCore/Errors.hpp | 225 +++++++++++++++++--------- engine/NBCore/Types.hpp | 25 --- engine/NBCore/Utils.hpp | 45 ++++++ engine/NBCore/src/Errors.cpp | 11 +- engine/NBCore/src/Processes.cpp | 1 - engine/NBCore/src/Utils.cpp | 23 +++ engine/NBCore/tests/CMakeLists.txt | 5 +- engine/NBCore/tests/testErrors.cpp | 31 ++-- engine/NBCore/tests/testProcesses.cpp | 2 - engine/NBCore/tests/testUtils.cpp | 41 +++++ 13 files changed, 284 insertions(+), 142 deletions(-) delete mode 100644 engine/NBCore/Types.hpp create mode 100644 engine/NBCore/Utils.hpp create mode 100644 engine/NBCore/src/Utils.cpp create mode 100644 engine/NBCore/tests/testUtils.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 8f60158..65af2c9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -48,13 +48,12 @@ if(NB_BUILD_TESTS) include(FetchContent) FetchContent_Declare( gtest - URL https://github.com/google/googletest/archive/refs/tags/release-1.12.1.zip + URL https://github.com/google/googletest/archive/refs/heads/main.zip ) if (WIN32) set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) FetchContent_MakeAvailable(gtest) endif() - include(GoogleTest) set(GTEST_COLOR ON) set(GLFW_BUILD_TESTS ON CACHE BOOL "" FORCE) endif() diff --git a/engine/NBCore/ANSITerm.hpp b/engine/NBCore/ANSITerm.hpp index b74ee7b..b729bac 100644 --- a/engine/NBCore/ANSITerm.hpp +++ b/engine/NBCore/ANSITerm.hpp @@ -2,16 +2,10 @@ #ifndef _NB_ANSI_TERM #define _NB_ANSI_TERM -#include -#include -#include #include #include -#include #include -#include "TypeTraits.hpp" - /* ----------- TECH DEBT ------------ Idk wtf to do here. This was originally to allow me to print diff --git a/engine/NBCore/CMakeLists.txt b/engine/NBCore/CMakeLists.txt index 6b105df..2260d5a 100644 --- a/engine/NBCore/CMakeLists.txt +++ b/engine/NBCore/CMakeLists.txt @@ -1,9 +1,8 @@ -include_directories(./.) - toAbsolutePath(NB_CORE_SOURCE ./src/Errors.cpp - ./src/Processes.cpp ./src/Logger.cpp + ./src/Processes.cpp + ./src/Utils.cpp ) toAbsolutePath(NB_CORE_INCLUDE @@ -15,6 +14,7 @@ toAbsolutePath(NB_CORE_INCLUDE ./ThreadsafeQueue.hpp ./Types.hpp ./TypeTraits.hpp + ./Utils.hpp ) set(NB_CORE_SOURCE ${NB_CORE_SOURCE} PARENT_SCOPE) @@ -22,6 +22,8 @@ set(NB_CORE_INCLUDE ${NB_CORE_INCLUDE} PARENT_SCOPE) add_library(NBCore ${NB_CORE_SOURCE}) +target_include_directories(NBCore PUBLIC ./.) + if (NB_BUILD_TESTS) add_subdirectory(./tests) endif() \ No newline at end of file diff --git a/engine/NBCore/Errors.hpp b/engine/NBCore/Errors.hpp index a893b9b..49bedd1 100644 --- a/engine/NBCore/Errors.hpp +++ b/engine/NBCore/Errors.hpp @@ -3,10 +3,11 @@ #define _NB_ERROR #include -#include +#include #include #include #include +#include "Utils.hpp" #ifndef THROW_WITH_INFO #ifdef CODE_ERROR_LOCATIONS @@ -31,109 +32,173 @@ typedef std::unordered_map ErrorCodeMap; template class ErrorBase : public std::exception { public: - ErrorBase( - const unsigned int code, - unsigned int line=0, - std::string filename="" - ) noexcept : ErrorBase( - code, - ErrorBase::lookup(code), - line, - filename - ) {} - ErrorBase( - const unsigned int code, - const std::exception& trace, - unsigned int line=0, - std::string filename="" - ) noexcept : ErrorBase( - code, - ErrorBase::lookup(code), - trace, - line, - filename - ) {} + ErrorBase(const ErrorBase&) = default; + ErrorBase& operator=(const ErrorBase&) = delete; - static std::string lookup(unsigned int); - unsigned int code() const noexcept { - return static_cast(this)->_code; - }; - virtual const char* what() const noexcept override final { return _msg.c_str(); }; + virtual const char* what() const noexcept override final { + std::string ret = this->msg; + const std::string replace = nb::NEWLINE + "\t"; + if (trace) { + ret += replace + find_and_replace( + std::string(trace->what()), + nb::NEWLINE, + replace + ); + } + const std::string& ret_ref = ret; + return ret_ref.c_str(); + } + + static const std::string type; + static const ErrorCodeMap ErrorMessages; + + const unsigned int code; + const std::string msg; + const std::exception* trace; protected: - ErrorBase() = default; + ErrorBase() = delete; + + template < + typename TraceType=std::exception, + std::enable_if_t, bool> = true + > ErrorBase( - const unsigned int code, - std::string msg, - unsigned int line=0, - std::string filename="" - ) noexcept : _code{code}, _msg{""} { + const unsigned int code_, + std::string msg_, + const TraceType* trace_=nullptr, + unsigned int line_=0, + std::string filename_="" + ) noexcept : + code(code_), + msg(msg_), + trace{static_cast(trace_ ? new TraceType(*trace_) : nullptr) } + { static_assert(std::is_same, decltype(ErrorType::ErrorMessages)>::value, "const std::unordered_map ErrorMessages must be " "a class member." ); - static_assert(std::is_enum_v, "enum ErrorCodes must be a class member."); - static_assert(std::is_same, unsigned int>::value, - "enum ErrorCodes must be of underlying type unsigned int." + static_assert(std::is_enum_v, "enum Codes must be a class member."); + static_assert(std::is_same, unsigned int>::value, + "enum Codes must be of underlying type unsigned int." ); static_assert(std::is_same::value, "const std::string type must be a class member." ); - - _msg += std::string(ErrorType::type); - _msg += "[" + std::to_string(_code) + "]"; - if (line && filename.size()) { - _msg += " in \'" + filename + "\':" + std::to_string(line); - } - _msg += "\n " + msg; - } - ErrorBase( - const unsigned int code, - std::string msg, - const std::exception& trace, - unsigned int line=0, - std::string filename="" - ) noexcept : ErrorBase(code, msg, line, filename) { - std::string what_msg(trace.what()); - std::string::size_type newline_pos=-1; - while((newline_pos=what_msg.find("\n", newline_pos+1))!= std::string::npos) { - what_msg.replace(newline_pos, 1, "\n "); - } - _msg += "\n Trace - " + what_msg; + static_assert(std::is_base_of::value, + "`trace_` must be a pointer to a child object of std::exception." + ); } - - unsigned int _code; - std::string _msg; + + template < + typename TraceType, + std::enable_if_t, bool> = true + > + ErrorBase( + const unsigned int& code_, + const TraceType& trace_, + unsigned int line_=0, + std::string filename_="" + ) noexcept : ErrorBase( + code_, + ErrorType::ErrorMessages.at(code_), + &trace_, + line_, + filename_ + ) {} + + template < + typename TraceType, + std::enable_if_t, bool> = true + > + ErrorBase( + const std::string& msg_, + const TraceType& trace_, + unsigned int line_=0, + std::string filename_="" + ) noexcept : ErrorBase( + 0, + msg_, + &trace_, + line_, + filename_ + ) {} + + ErrorBase( + const unsigned int& code_, + unsigned int line_=0, + std::string filename_="" + ) noexcept : ErrorBase( + code_, + ErrorType::ErrorMessages.at(code_), + static_cast(nullptr), + line_, + filename_ + ) {} + + ErrorBase( + const std::string& msg_, + unsigned int line_=0, + std::string filename_="" + ) noexcept : ErrorBase( + 0, + msg_, + nullptr, + line_, + filename_ + ) {} + +}; +template +const std::string ErrorBase::type = ErrorType::type; +template +const ErrorCodeMap ErrorBase::ErrorMessages = ErrorType::ErrorMessages; + +class DefaultError {DefaultError() = default;}; + +template +class Error; + +template<> +class Error; + +template +class Error : public ErrorBase { + using Base = ErrorBase; +public: + template + Error(Args... T) : Base(T...) {} + + using Base::what; + using Base::code; + using Base::msg; + using Base::trace; + using Base::type; + using Base::ErrorMessages; + + friend ErrorBase; }; -class Error : public ErrorBase { +template<> +class Error : public ErrorBase> { + using Base = ErrorBase>; public: - enum ErrorCodes : unsigned int { + using Base::Base; + Error() : Base(0) {} + + enum Codes : unsigned int { GENERAL, UNDEFINED, BADERRORCODE }; - using ErrorBase::ErrorBase; + using Base::what; + using Base::code; + using Base::msg; + using Base::trace; - friend ErrorBase; - -protected: static const std::string type; static const ErrorCodeMap ErrorMessages; - }; -template -std::string ErrorBase::lookup(unsigned int code) { - for (auto kv : ErrorType::ErrorMessages) { - if (kv.first==code) { - return std::string(kv.second); - } - } - - throw Error(Error::ErrorCodes::BADERRORCODE); -} - } // namespace nb - #endif // _NB_ERROR \ No newline at end of file diff --git a/engine/NBCore/Types.hpp b/engine/NBCore/Types.hpp deleted file mode 100644 index 293bdb5..0000000 --- a/engine/NBCore/Types.hpp +++ /dev/null @@ -1,25 +0,0 @@ -#pragma once -#ifndef _NB_CORE_TYPES -#define _NB_CORE_TYPES - -#include - -namespace nb { - -template -T swapEndian(const T& val) { - T ret; - const int size = sizeof(T); - auto retLoc = static_cast(&ret); - auto valLoc = static_cast(&val); - - for (int i = 0; i < size; ++i) { - memcpy(retLoc+i, valLoc+(size-i-1), 1); - } - return ret; -} - -using ByteVector = std::vector; - -} // namespace nb -#endif // _NB_CORE_TYPES \ No newline at end of file diff --git a/engine/NBCore/Utils.hpp b/engine/NBCore/Utils.hpp new file mode 100644 index 0000000..3151183 --- /dev/null +++ b/engine/NBCore/Utils.hpp @@ -0,0 +1,45 @@ +#pragma once +#ifndef _NB_CORE_TYPES +#define _NB_CORE_TYPES + +#include +#include +#include + +namespace nb { + +#ifdef _NB_TARGET_WINDOWS + const std::string NEWLINE("\r\n"); +#endif // _NB_TARGET_WINDOWS +#ifdef _NB_TARGET_LINUX + const std::string NEWLINE("\n"); +#endif // _NB_TARGET_LINUX + +template +struct ConstexprMap { + template + constexpr ConstexprMap(Input inp) : _data{inp} {} + +protected: + const std::array, N> _data; +}; + +/* template +T swap_endian(const T& val) { + T ret; + const int size = sizeof(T); + auto retLoc = static_cast(&ret); + auto valLoc = static_cast(&val); + + for (int i = 0; i < size; ++i) { + memcpy(retLoc+i, valLoc+(size-i-1), 1); + } + return ret; +} */ + +std::string find_and_replace(const std::string& original, const std::string& find, const std::string& replace); + +// using ByteVector = std::vector; + +} // namespace nb +#endif // _NB_CORE_TYPES \ No newline at end of file diff --git a/engine/NBCore/src/Errors.cpp b/engine/NBCore/src/Errors.cpp index 544346a..952f772 100644 --- a/engine/NBCore/src/Errors.cpp +++ b/engine/NBCore/src/Errors.cpp @@ -2,11 +2,12 @@ namespace nb { -const std::string Error::type = "Error"; -const ErrorCodeMap Error::ErrorMessages = { - {ErrorCodes::GENERAL, "General std::exception."}, - {ErrorCodes::UNDEFINED, "Undefined / general error."}, - {ErrorCodes::BADERRORCODE, "Unrecognized error code."} +const std::string Error::type = "nb::Error"; + +const ErrorCodeMap Error::ErrorMessages = { + {Error::Codes::GENERAL, "General std::exception."}, + {Error::Codes::UNDEFINED, "Undefined / general error."}, + {Error::Codes::BADERRORCODE, "Unrecognized error code."} }; } diff --git a/engine/NBCore/src/Processes.cpp b/engine/NBCore/src/Processes.cpp index dabf222..744d96d 100644 --- a/engine/NBCore/src/Processes.cpp +++ b/engine/NBCore/src/Processes.cpp @@ -7,7 +7,6 @@ #endif // _NB_TARGET_LINUX #include "Processes.hpp" -#include "Types.hpp" namespace nb { diff --git a/engine/NBCore/src/Utils.cpp b/engine/NBCore/src/Utils.cpp new file mode 100644 index 0000000..f060189 --- /dev/null +++ b/engine/NBCore/src/Utils.cpp @@ -0,0 +1,23 @@ +#include +#include "Utils.hpp" + + +std::string nb::find_and_replace(const std::string& original, const std::string& find, const std::string& replace) { + std::string ret = original; + + std::size_t find_len = find.length(); + std::size_t replace_len = replace.length(); + std::size_t currpos = 0; + std::size_t lastpos = 0; + while(true) { + lastpos = currpos; + currpos = original.find(find, lastpos); + if (currpos == std::string::npos) { + break; + } + ret = ret.erase(currpos, find_len); + ret = ret.insert(currpos, replace); + currpos += replace_len; + } + return ret; +} \ No newline at end of file diff --git a/engine/NBCore/tests/CMakeLists.txt b/engine/NBCore/tests/CMakeLists.txt index d3ad479..02c31c7 100644 --- a/engine/NBCore/tests/CMakeLists.txt +++ b/engine/NBCore/tests/CMakeLists.txt @@ -4,8 +4,9 @@ if (NB_BUILD_TESTS) enable_testing() include(GoogleTest) add_executable(TestCore - testErrors.cpp - testProcesses.cpp + ./testErrors.cpp + #./testProcesses.cpp + ./testUtils.cpp ) target_link_libraries(TestCore NBCore diff --git a/engine/NBCore/tests/testErrors.cpp b/engine/NBCore/tests/testErrors.cpp index 7d79ee9..6b1c21f 100644 --- a/engine/NBCore/tests/testErrors.cpp +++ b/engine/NBCore/tests/testErrors.cpp @@ -3,36 +3,35 @@ #include "Errors.hpp" #include #include -#include -#include "Logger.hpp" using namespace nb; -class TestError : public ErrorBase { +class TestError : public Error { + using Base = Error; public: - using ErrorBase::ErrorBase; + using Base::Base; + using Base::what; + using Base::code; + using Base::msg; + using Base::trace; - enum ErrorCodes : unsigned int { + enum Codes : unsigned int { A, B, C, D }; + static const std::string type; - static const ErrorCodeMap ErrorMessages; + static const nb::ErrorCodeMap ErrorMessages; }; const std::string TestError::type="TestError"; const ErrorCodeMap TestError::ErrorMessages{ - {TestError::ErrorCodes::A, "Hey!"}, - {TestError::ErrorCodes::B, "How"}, - {TestError::ErrorCodes::C, "You"}, - {TestError::ErrorCodes::D, "Doin"} + {TestError::Codes::A, "Hey!"}, + {TestError::Codes::B, "How"}, + {TestError::Codes::C, "You"}, + {TestError::Codes::D, "Doin"} }; TEST(ErrorTest, Test) { - EXPECT_EQ(1, 1); - - std::stringstream sstream; - - ASSERT_TRUE(nb::logger.isRunning()); - nb::logger.log("Hey!"); + std::cout << TestError(0, TestError(1, TestError(2))).what(); } \ No newline at end of file diff --git a/engine/NBCore/tests/testProcesses.cpp b/engine/NBCore/tests/testProcesses.cpp index 3e220b8..cee1e90 100644 --- a/engine/NBCore/tests/testProcesses.cpp +++ b/engine/NBCore/tests/testProcesses.cpp @@ -1,8 +1,6 @@ #define CODE_ERROR_LOCATIONS #include - -#include #include "Processes.hpp" #include diff --git a/engine/NBCore/tests/testUtils.cpp b/engine/NBCore/tests/testUtils.cpp new file mode 100644 index 0000000..1ef1969 --- /dev/null +++ b/engine/NBCore/tests/testUtils.cpp @@ -0,0 +1,41 @@ +#define CODE_ERROR_LOCATIONS + +#include "Utils.hpp" +#include + +namespace nb { + +TEST(UtilsTest, Test) { + ASSERT_STREQ( + find_and_replace("Jeff", "e", "efe").c_str(), + "Jefeff" + ); + + auto tmp = find_and_replace("Naif", "a", "afa"); + ASSERT_STREQ( + find_and_replace(tmp, "i", "ifi").c_str(), + "Nafaifif" + ); + + tmp = find_and_replace("aeiou", "a", "afa"); + tmp = find_and_replace(tmp, "e", "efe"); + tmp = find_and_replace(tmp, "i", "ifi"); + tmp = find_and_replace(tmp, "o", "ofo"); + tmp = find_and_replace(tmp, "u", "ufu"); + ASSERT_STREQ( + tmp.c_str(), + "afaefeifiofoufu" + ); + + tmp = find_and_replace(tmp, "afa", "a"); + tmp = find_and_replace(tmp, "efe", "e"); + tmp = find_and_replace(tmp, "ifi", "i"); + tmp = find_and_replace(tmp, "ofo", "o"); + tmp = find_and_replace(tmp, "ufu", "u"); + ASSERT_STREQ( + tmp.c_str(), + "aeiou" + ); +} + +} // namespace nb \ No newline at end of file -- 2.43.0 From fd7d36e4be144cf7941a2fb81e9a4c990e270ca8 Mon Sep 17 00:00:00 2001 From: NaifBanana <30419422+NaifBanana@users.noreply.github.com> Date: Thu, 9 Apr 2026 17:44:19 -0500 Subject: [PATCH 02/11] Added more Util tests and str-wstr related changes to util functions --- engine/NBCore/Utils.hpp | 66 +++++++++++++++++++++---- engine/NBCore/src/Utils.cpp | 31 +++++------- engine/NBCore/tests/testUtils.cpp | 81 +++++++++++++++++++++++++++++-- 3 files changed, 145 insertions(+), 33 deletions(-) diff --git a/engine/NBCore/Utils.hpp b/engine/NBCore/Utils.hpp index 3151183..e51d3f5 100644 --- a/engine/NBCore/Utils.hpp +++ b/engine/NBCore/Utils.hpp @@ -1,4 +1,6 @@ #pragma once +#include +#include #ifndef _NB_CORE_TYPES #define _NB_CORE_TYPES @@ -9,20 +11,65 @@ namespace nb { #ifdef _NB_TARGET_WINDOWS - const std::string NEWLINE("\r\n"); + const std::string NEWLINE; + const std::wstring WNEWLINE; #endif // _NB_TARGET_WINDOWS #ifdef _NB_TARGET_LINUX - const std::string NEWLINE("\n"); + const std::string NEWLINE; + const std::wstring WNEWLINE; #endif // _NB_TARGET_LINUX -template -struct ConstexprMap { - template - constexpr ConstexprMap(Input inp) : _data{inp} {} +template +std::enable_if_t, std::wstring> str_to_wstr(const T& str) { + std::mbstate_t state = std::mbstate_t(); + const char* cstr = std::string(str).c_str(); + std::size_t wlen = 1 + std::mbsrtowcs(nullptr, &cstr, 0, &state); + wchar_t* c_wstr= new wchar_t[wlen]; + std::mbsrtowcs(c_wstr, &cstr, wlen, &state); + std::wstring ret(c_wstr, wlen); + delete[] c_wstr; + return ret; +} -protected: - const std::array, N> _data; -}; +template +std::enable_if_t, std::string> wstr_to_str(const T& wstr) { + const wchar_t* c_wstr = std::wstring(wstr).c_str(); + std::size_t strlen = 1 + std::wcstombs(nullptr, c_wstr, 0); + char* c_str= new char[strlen]; + std::wcstombs(c_str, c_wstr, strlen); + std::string ret(c_str, strlen); + delete[] c_str; + return ret; +} + +template +T find_and_replace( + const A& original, + const B& find, + const C& replace +) { + const T& original_t = T(original); + const T& find_t = T(find); + const T& replace_t = T(replace); + + T ret = original_t; + + std::size_t find_len = find_t.length(); + std::size_t replace_len = replace_t.length(); + std::size_t currpos = 0; + std::size_t lastpos = 0; + while(true) { + lastpos = currpos; + currpos = original_t.find(find_t, lastpos); + if (currpos == T::npos) { + break; + } + ret = ret.erase(currpos, find_len); + ret = ret.insert(currpos, replace_t); + currpos += replace_len; + } + return ret; +} /* template T swap_endian(const T& val) { @@ -37,7 +84,6 @@ T swap_endian(const T& val) { return ret; } */ -std::string find_and_replace(const std::string& original, const std::string& find, const std::string& replace); // using ByteVector = std::vector; diff --git a/engine/NBCore/src/Utils.cpp b/engine/NBCore/src/Utils.cpp index f060189..f94f897 100644 --- a/engine/NBCore/src/Utils.cpp +++ b/engine/NBCore/src/Utils.cpp @@ -1,23 +1,14 @@ +#include +#include #include + #include "Utils.hpp" - -std::string nb::find_and_replace(const std::string& original, const std::string& find, const std::string& replace) { - std::string ret = original; - - std::size_t find_len = find.length(); - std::size_t replace_len = replace.length(); - std::size_t currpos = 0; - std::size_t lastpos = 0; - while(true) { - lastpos = currpos; - currpos = original.find(find, lastpos); - if (currpos == std::string::npos) { - break; - } - ret = ret.erase(currpos, find_len); - ret = ret.insert(currpos, replace); - currpos += replace_len; - } - return ret; -} \ No newline at end of file +#ifdef _NB_TARGET_WINDOWS + const std::string NEWLINE("\r\n"); + const std::wstring WNEWLINE(L"\r\n"); +#endif // _NB_TARGET_WINDOWS +#ifdef _NB_TARGET_LINUX + const std::string NEWLINE("\n"); + const std::wstring WNEWLINE(L"\n"); +#endif // _NB_TARGET_LINUX diff --git a/engine/NBCore/tests/testUtils.cpp b/engine/NBCore/tests/testUtils.cpp index 1ef1969..042e7a0 100644 --- a/engine/NBCore/tests/testUtils.cpp +++ b/engine/NBCore/tests/testUtils.cpp @@ -1,17 +1,20 @@ +#include #define CODE_ERROR_LOCATIONS -#include "Utils.hpp" #include +#include +#include "Utils.hpp" + namespace nb { -TEST(UtilsTest, Test) { +TEST(UtilsTest, TestFindAndReplace) { ASSERT_STREQ( find_and_replace("Jeff", "e", "efe").c_str(), "Jefeff" ); - auto tmp = find_and_replace("Naif", "a", "afa"); + std::string tmp = find_and_replace("Naif", "a", "afa"); ASSERT_STREQ( find_and_replace(tmp, "i", "ifi").c_str(), "Nafaifif" @@ -38,4 +41,76 @@ TEST(UtilsTest, Test) { ); } +TEST(UtilsTest, TestFindAndReplaceWstr) { + ASSERT_STREQ( + find_and_replace(L"Jeff", L"e", L"efe").c_str(), + L"Jefeff" + ); + + std::wstring tmp = find_and_replace(L"Naif", L"a", L"afa"); + ASSERT_STREQ( + find_and_replace(tmp, L"i", L"ifi").c_str(), + L"Nafaifif" + ); + + tmp = find_and_replace(L"aeiou", L"a", L"afa"); + tmp = find_and_replace(tmp, L"e", L"efe"); + tmp = find_and_replace(tmp, L"i", L"ifi"); + tmp = find_and_replace(tmp, L"o", L"ofo"); + tmp = find_and_replace(tmp, L"u", L"ufu"); + ASSERT_STREQ( + tmp.c_str(), + L"afaefeifiofoufu" + ); + + tmp = find_and_replace(tmp, L"afa", L"a"); + tmp = find_and_replace(tmp, L"efe", L"e"); + tmp = find_and_replace(tmp, L"ifi", L"i"); + tmp = find_and_replace(tmp, L"ofo", L"o"); + tmp = find_and_replace(tmp, L"ufu", L"u"); + ASSERT_STREQ( + tmp.c_str(), + L"aeiou" + ); +} + +TEST(UtilsTest, TestWstrToStr) { + ASSERT_STREQ( + nb::wstr_to_str(L"Hi!").c_str(), + "Hi!" + ); + ASSERT_STREQ( + nb::wstr_to_str(L"Naif").c_str(), + "Naif" + ); + ASSERT_STREQ( + nb::wstr_to_str(L"\r\r\r\n").c_str(), + "\r\r\r\n" + ); + ASSERT_STREQ( + nb::wstr_to_str(L"Naif\ttalks\r\ra\t\nlot").c_str(), + "Naif\ttalks\r\ra\t\nlot" + ); +} + +TEST(UtilsTest, TestStrToWstr) { + ASSERT_STREQ( + nb::str_to_wstr("Hi!").c_str(), + L"Hi!" + ); + ASSERT_STREQ( + nb::str_to_wstr("Naif").c_str(), + L"Naif" + ); + ASSERT_STREQ( + nb::str_to_wstr("\r\r\r\n").c_str(), + L"\r\r\r\n" + ); + ASSERT_STREQ( + nb::str_to_wstr("Naif\ttalks\r\ra\t\nlot").c_str(), + L"Naif\ttalks\r\ra\t\nlot" + ); +} + + } // namespace nb \ No newline at end of file -- 2.43.0 From e23e062e5899f3ba12bfd1482f57a1e61a59b55a Mon Sep 17 00:00:00 2001 From: NaifBanana <30419422+NaifBanana@users.noreply.github.com> Date: Fri, 10 Apr 2026 00:31:11 -0500 Subject: [PATCH 03/11] Man im so tired This is wrong but I can taste it, im close --- engine/NBCore/CMakeLists.txt | 2 +- engine/NBCore/Errors.hpp | 98 +++++++++++++++++++++++------- engine/NBCore/TypeTraits.hpp | 40 +++++++++++- engine/NBCore/Utils.hpp | 33 ++++------ engine/NBCore/src/Errors.cpp | 5 +- engine/NBCore/src/Utils.cpp | 16 ++--- engine/NBCore/tests/testErrors.cpp | 14 ++++- engine/NBCore/tests/testUtils.cpp | 33 ++++++++++ 8 files changed, 182 insertions(+), 59 deletions(-) diff --git a/engine/NBCore/CMakeLists.txt b/engine/NBCore/CMakeLists.txt index 2260d5a..b457870 100644 --- a/engine/NBCore/CMakeLists.txt +++ b/engine/NBCore/CMakeLists.txt @@ -1,6 +1,6 @@ toAbsolutePath(NB_CORE_SOURCE ./src/Errors.cpp - ./src/Logger.cpp +# ./src/Logger.cpp ./src/Processes.cpp ./src/Utils.cpp ) diff --git a/engine/NBCore/Errors.hpp b/engine/NBCore/Errors.hpp index 49bedd1..6517341 100644 --- a/engine/NBCore/Errors.hpp +++ b/engine/NBCore/Errors.hpp @@ -1,4 +1,5 @@ #pragma once +#include #ifndef _NB_ERROR #define _NB_ERROR @@ -6,10 +7,11 @@ #include #include #include +#include "TypeTraits.hpp" #include #include "Utils.hpp" -#ifndef THROW_WITH_INFO +/* #ifndef THROW_WITH_INFO #ifdef CODE_ERROR_LOCATIONS #define THROW_WITH_INFO(type, ...) throw type(__VA_ARGS__, __LINE__, __FILE__) #else @@ -23,30 +25,43 @@ #else #define THROW(...) THROW_WITH_INFO(__VA_ARGS__) #endif // LOGGING -#endif // THROW +#endif // THROW */ namespace nb { typedef std::unordered_map ErrorCodeMap; +template +using has_type = decltype(T::type); + +template +struct NBErrorWhatString; + +class ErrorBase_what_str_impl : public std::exception { + template + T what_str() const; + + template <> + virtual std::wstring what_str() const; + + template<> + virtual std::string what_str() const; +}; + template -class ErrorBase : public std::exception { +class ErrorBase : public ErrorBase_what_str_impl { public: ErrorBase(const ErrorBase&) = default; ErrorBase& operator=(const ErrorBase&) = delete; + template + inline const StringType what_str() const noexcept { + return NBErrorWhatString::what(*this); + } + virtual const char* what() const noexcept override final { - std::string ret = this->msg; - const std::string replace = nb::NEWLINE + "\t"; - if (trace) { - ret += replace + find_and_replace( - std::string(trace->what()), - nb::NEWLINE, - replace - ); - } - const std::string& ret_ref = ret; - return ret_ref.c_str(); + const std::string& ret = what_str(); + return ret.c_str(); } static const std::string type; @@ -54,7 +69,8 @@ public: const unsigned int code; const std::string msg; - const std::exception* trace; + const std::shared_ptr trace; + const bool traceIsNBError; protected: ErrorBase() = delete; @@ -72,7 +88,8 @@ protected: ) noexcept : code(code_), msg(msg_), - trace{static_cast(trace_ ? new TraceType(*trace_) : nullptr) } + trace{trace_ ? std::make_shared(*trace_) : nullptr}, + traceIsNBError( trace_ ? is_detected::value : false) { static_assert(std::is_same, decltype(ErrorType::ErrorMessages)>::value, "const std::unordered_map ErrorMessages must be " @@ -148,19 +165,58 @@ protected: filename_ ) {} + std::string (ErrorBase::*_trace_what_str)(); + std::wstring (ErrorBase::*_trace_what_wstr)(); }; template const std::string ErrorBase::type = ErrorType::type; template const ErrorCodeMap ErrorBase::ErrorMessages = ErrorType::ErrorMessages; -class DefaultError {DefaultError() = default;}; +template +struct NBErrorWhatString { + inline static const std::wstring what(const ErrorBase& err) noexcept { + std::wstring ret = nb::str_to_wstr(err.msg); + const std::wstring replace = nb::WNEWLINE + L"┗-"; + if (err.trace) { + std::wstring trace_msg; + if (err.traceIsNBError) { + trace_msg = std::static_pointer_cast(err.trace)->template what_str(); + } else { + trace_msg = nb::str_to_wstr(std::string(err.trace->what())); + } + trace_msg = find_and_replace(trace_msg, L"┗", L"-"); + ret += replace + find_and_replace( + trace_msg, + nb::WNEWLINE, + replace + ); + } + return ret; + } +}; -template +template +struct NBErrorWhatString { + inline static const std::string what(const ErrorBase& err) noexcept { + std::string ret = err.msg; + const std::string replace = nb::NEWLINE+" "; + if (err.trace) { + ret += replace + find_and_replace( + std::string(err.trace->what()), + nb::NEWLINE, + replace + ); + } + return ret; + } +}; + +template class Error; template<> -class Error; +class Error; template class Error : public ErrorBase { @@ -180,8 +236,8 @@ public: }; template<> -class Error : public ErrorBase> { - using Base = ErrorBase>; +class Error : public ErrorBase> { + using Base = ErrorBase>; public: using Base::Base; Error() : Base(0) {} diff --git a/engine/NBCore/TypeTraits.hpp b/engine/NBCore/TypeTraits.hpp index 5226e94..a1e7502 100644 --- a/engine/NBCore/TypeTraits.hpp +++ b/engine/NBCore/TypeTraits.hpp @@ -6,7 +6,43 @@ namespace nb { -template +namespace detail { + template < + class Default, + class AlwaysVoid, + template class Op, + class... Args + > + struct detector { + using value = std::false_type; + using type = Default; + }; + + template < + class Default, + template class Op, + class... Args + > + struct detector>, Op, Args...> { + using value = std::true_type; + using type = Op; + }; +} // namespace detail + +struct NoneType{}; + +template < + template class Op, + class... Args +> +using is_detected = typename detail::detector::value; + +template +void stream(Stream& s, Args&&... args) { + (s << ... << args); +} + +/*template inline typename std::enable_if::type ForEach(std::tuple&, Func) {} @@ -68,7 +104,7 @@ struct PackIsSameType { template struct PackIsSameType { const bool value = std::is_base_of::value && PackIsSameType::value; -}; +};*/ } // namespace nb diff --git a/engine/NBCore/Utils.hpp b/engine/NBCore/Utils.hpp index e51d3f5..96194d3 100644 --- a/engine/NBCore/Utils.hpp +++ b/engine/NBCore/Utils.hpp @@ -4,40 +4,33 @@ #ifndef _NB_CORE_TYPES #define _NB_CORE_TYPES -#include -#include #include namespace nb { #ifdef _NB_TARGET_WINDOWS - const std::string NEWLINE; - const std::wstring WNEWLINE; + const std::string NEWLINE = "\r\n"; + const std::wstring WNEWLINE = L"\r\n"; #endif // _NB_TARGET_WINDOWS #ifdef _NB_TARGET_LINUX - const std::string NEWLINE; - const std::wstring WNEWLINE; + const std::string NEWLINE = "\n"; + const std::wstring WNEWLINE = L"\n"; #endif // _NB_TARGET_LINUX template -std::enable_if_t, std::wstring> str_to_wstr(const T& str) { - std::mbstate_t state = std::mbstate_t(); - const char* cstr = std::string(str).c_str(); - std::size_t wlen = 1 + std::mbsrtowcs(nullptr, &cstr, 0, &state); - wchar_t* c_wstr= new wchar_t[wlen]; - std::mbsrtowcs(c_wstr, &cstr, wlen, &state); - std::wstring ret(c_wstr, wlen); - delete[] c_wstr; +std::enable_if_t, std::wstring> str_to_wstr(const T& in) { + std::string str(in); + std::wstring ret(str.begin(), str.end()); return ret; } template -std::enable_if_t, std::string> wstr_to_str(const T& wstr) { - const wchar_t* c_wstr = std::wstring(wstr).c_str(); - std::size_t strlen = 1 + std::wcstombs(nullptr, c_wstr, 0); - char* c_str= new char[strlen]; - std::wcstombs(c_str, c_wstr, strlen); - std::string ret(c_str, strlen); +std::enable_if_t, std::string> wstr_to_str(const T& in) { + std::wstring wstr(in); + std::size_t wstrlen = wstr.length(); + char* c_str= new char[wstrlen]; + std::wcstombs(c_str, wstr.c_str(), wstrlen); + std::string ret(c_str, wstrlen); delete[] c_str; return ret; } diff --git a/engine/NBCore/src/Errors.cpp b/engine/NBCore/src/Errors.cpp index 952f772..43b6227 100644 --- a/engine/NBCore/src/Errors.cpp +++ b/engine/NBCore/src/Errors.cpp @@ -1,10 +1,11 @@ #include "Errors.hpp" +#include "TypeTraits.hpp" namespace nb { -const std::string Error::type = "nb::Error"; +const std::string Error::type = "nb::Error"; -const ErrorCodeMap Error::ErrorMessages = { +const ErrorCodeMap Error::ErrorMessages = { {Error::Codes::GENERAL, "General std::exception."}, {Error::Codes::UNDEFINED, "Undefined / general error."}, {Error::Codes::BADERRORCODE, "Unrecognized error code."} diff --git a/engine/NBCore/src/Utils.cpp b/engine/NBCore/src/Utils.cpp index f94f897..336d3b6 100644 --- a/engine/NBCore/src/Utils.cpp +++ b/engine/NBCore/src/Utils.cpp @@ -1,14 +1,8 @@ -#include -#include #include - #include "Utils.hpp" -#ifdef _NB_TARGET_WINDOWS - const std::string NEWLINE("\r\n"); - const std::wstring WNEWLINE(L"\r\n"); -#endif // _NB_TARGET_WINDOWS -#ifdef _NB_TARGET_LINUX - const std::string NEWLINE("\n"); - const std::wstring WNEWLINE(L"\n"); -#endif // _NB_TARGET_LINUX +template<> +std::wstring nb::str_to_wstr(const std::string& in) { + std::wstring ret(in.begin(), in.end()); + return ret; +} diff --git a/engine/NBCore/tests/testErrors.cpp b/engine/NBCore/tests/testErrors.cpp index 6b1c21f..6c778b7 100644 --- a/engine/NBCore/tests/testErrors.cpp +++ b/engine/NBCore/tests/testErrors.cpp @@ -1,8 +1,11 @@ #define CODE_ERROR_LOCATIONS -#include "Errors.hpp" #include + +#include "Errors.hpp" #include +#include +#include "TypeTraits.hpp" using namespace nb; @@ -33,5 +36,12 @@ const ErrorCodeMap TestError::ErrorMessages{ TEST(ErrorTest, Test) { - std::cout << TestError(0, TestError(1, TestError(2))).what(); + auto err = TestError(0, TestError(1)); + nb::stream(std::cout, + "len string: ", err.what_str().length(), "\n", + "len wstring: ", err.what_str().length(), "\n" + ); + nb::stream(std::wcout, + err.what_str(), L"\n" + ); } \ No newline at end of file diff --git a/engine/NBCore/tests/testUtils.cpp b/engine/NBCore/tests/testUtils.cpp index 042e7a0..f9188a1 100644 --- a/engine/NBCore/tests/testUtils.cpp +++ b/engine/NBCore/tests/testUtils.cpp @@ -4,6 +4,7 @@ #include #include +#include "TypeTraits.hpp" #include "Utils.hpp" namespace nb { @@ -112,5 +113,37 @@ TEST(UtilsTest, TestStrToWstr) { ); } +struct A { bool x(); }; +struct B { bool y(); }; +struct C { bool x(); bool y; }; +struct D : C {}; + +template +using has_x = decltype(T::x); + +template +using has_y = decltype(T::y); + +TEST(UtilsTest, TestIsDetected) { + auto ret = is_detected::value; + ASSERT_TRUE(ret); + ret = is_detected::value; + ASSERT_FALSE(ret); + + ret = is_detected::value; + ASSERT_TRUE(ret); + ret = is_detected::value; + ASSERT_FALSE(ret); + + ret = is_detected::value; + ASSERT_TRUE(ret); + ret = is_detected::value; + ASSERT_TRUE(ret); + + ret = is_detected::value; + ASSERT_TRUE(ret); + ret = is_detected::value; + ASSERT_TRUE(ret); +} } // namespace nb \ No newline at end of file -- 2.43.0 From e1c456bfe43c7d7bd07ff212af8452583ba02247 Mon Sep 17 00:00:00 2001 From: NaifBanana <30419422+NaifBanana@users.noreply.github.com> Date: Fri, 10 Apr 2026 00:41:01 -0500 Subject: [PATCH 04/11] I mean it compiled --- engine/NBCore/Errors.hpp | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/engine/NBCore/Errors.hpp b/engine/NBCore/Errors.hpp index 6517341..1f636f6 100644 --- a/engine/NBCore/Errors.hpp +++ b/engine/NBCore/Errors.hpp @@ -38,14 +38,9 @@ template struct NBErrorWhatString; class ErrorBase_what_str_impl : public std::exception { - template - T what_str() const; - - template <> - virtual std::wstring what_str() const; - - template<> - virtual std::string what_str() const; +public: + virtual std::string what_str_impl() const = 0; + virtual std::wstring what_wstr_impl() const = 0; }; template @@ -165,8 +160,8 @@ protected: filename_ ) {} - std::string (ErrorBase::*_trace_what_str)(); - std::wstring (ErrorBase::*_trace_what_wstr)(); + std::string what_str_impl() const override final { return what_str(); } + std::wstring what_wstr_impl() const override final { return what_str(); } }; template const std::string ErrorBase::type = ErrorType::type; @@ -181,7 +176,8 @@ struct NBErrorWhatString { if (err.trace) { std::wstring trace_msg; if (err.traceIsNBError) { - trace_msg = std::static_pointer_cast(err.trace)->template what_str(); + // How can I access + trace_msg = std::static_pointer_cast(err.trace)->what_wstr_impl(); } else { trace_msg = nb::str_to_wstr(std::string(err.trace->what())); } -- 2.43.0 From fb695798e795e0468c964bfcce430c640bf0848d Mon Sep 17 00:00:00 2001 From: NaifBanana <30419422+NaifBanana@users.noreply.github.com> Date: Sat, 18 Apr 2026 18:33:33 -0500 Subject: [PATCH 05/11] nb::Error objects now working --- engine/NBCore/Errors.hpp | 166 +++++++++++++++-------------- engine/NBCore/TypeTraits.hpp | 5 - engine/NBCore/Utils.hpp | 36 ++++--- engine/NBCore/tests/testErrors.cpp | 13 +-- engine/NBCore/tests/testUtils.cpp | 1 - 5 files changed, 111 insertions(+), 110 deletions(-) diff --git a/engine/NBCore/Errors.hpp b/engine/NBCore/Errors.hpp index 1f636f6..e406347 100644 --- a/engine/NBCore/Errors.hpp +++ b/engine/NBCore/Errors.hpp @@ -1,11 +1,11 @@ #pragma once -#include #ifndef _NB_ERROR #define _NB_ERROR #include -#include +#include #include +#include #include #include "TypeTraits.hpp" #include @@ -34,44 +34,89 @@ typedef std::unordered_map ErrorCodeMap; template using has_type = decltype(T::type); -template -struct NBErrorWhatString; +template +class ErrorBase; -class ErrorBase_what_str_impl : public std::exception { +template<> +class ErrorBase : public std::exception { public: - virtual std::string what_str_impl() const = 0; - virtual std::wstring what_wstr_impl() const = 0; -}; - -template -class ErrorBase : public ErrorBase_what_str_impl { -public: - ErrorBase(const ErrorBase&) = default; - ErrorBase& operator=(const ErrorBase&) = delete; - - template - inline const StringType what_str() const noexcept { - return NBErrorWhatString::what(*this); - } - - virtual const char* what() const noexcept override final { - const std::string& ret = what_str(); - return ret.c_str(); - } - - static const std::string type; - static const ErrorCodeMap ErrorMessages; - const unsigned int code; const std::string msg; const std::shared_ptr trace; const bool traceIsNBError; + virtual inline std::string str() const noexcept = 0; + + virtual const char* what() const noexcept override final { + const std::string& ret = str(); + return ret.c_str(); + } + protected: - ErrorBase() = delete; + template < + typename TraceType = std::exception, + std::enable_if_t, bool> = true + > + ErrorBase( + const unsigned int& code_, + const std::string& msg_, + const std::shared_ptr trace_, + const unsigned int& line_, + std::string filename_ + ) noexcept : + code(code_), + msg(msg_), + trace{std::dynamic_pointer_cast(trace_)}, + traceIsNBError( trace_ ? is_detected::value : false) + { + static_assert(std::is_base_of::value, + "`trace_` must be a pointer to a child object of std::exception." + ); + } +}; + +template +class ErrorBase : public ErrorBase { + using Base = ErrorBase; +public: + ErrorBase(const ErrorBase&) = default; + ErrorBase& operator=(const ErrorBase&) = delete; + + virtual inline std::string str() const noexcept override { + std::string ret = msg; + if (trace) { + const std::string replace = nb::NEWLINE+" "; + std::string trace_msg; + if (traceIsNBError) { + trace_msg = std::static_pointer_cast(trace)->str(); + trace_msg = std::string(std::string_view(trace_msg).substr( + 0, trace_msg.length()-nb::NEWLINE.length() + )); + } else { + trace_msg = std::string(trace->what()); + } + ret += replace + "Trace: " + find_and_replace( + trace_msg, + nb::NEWLINE, + replace + ); + } + return ret + nb::NEWLINE; + } + + static const std::string type; + static const ErrorCodeMap ErrorMessages; + + using Base::code; + using Base::msg; + using Base::trace; + using Base::traceIsNBError; + +protected: + using Base::Base; template < - typename TraceType=std::exception, + typename TraceType = std::exception, std::enable_if_t, bool> = true > ErrorBase( @@ -80,12 +125,13 @@ protected: const TraceType* trace_=nullptr, unsigned int line_=0, std::string filename_="" - ) noexcept : - code(code_), - msg(msg_), - trace{trace_ ? std::make_shared(*trace_) : nullptr}, - traceIsNBError( trace_ ? is_detected::value : false) - { + ) : Base( + code_, + msg_, + trace_ ? std::make_shared(*trace_) : nullptr, + line_, + filename_ + ) { static_assert(std::is_same, decltype(ErrorType::ErrorMessages)>::value, "const std::unordered_map ErrorMessages must be " "a class member." @@ -97,9 +143,6 @@ protected: static_assert(std::is_same::value, "const std::string type must be a class member." ); - static_assert(std::is_base_of::value, - "`trace_` must be a pointer to a child object of std::exception." - ); } template < @@ -159,55 +202,12 @@ protected: line_, filename_ ) {} - - std::string what_str_impl() const override final { return what_str(); } - std::wstring what_wstr_impl() const override final { return what_str(); } }; template const std::string ErrorBase::type = ErrorType::type; template const ErrorCodeMap ErrorBase::ErrorMessages = ErrorType::ErrorMessages; -template -struct NBErrorWhatString { - inline static const std::wstring what(const ErrorBase& err) noexcept { - std::wstring ret = nb::str_to_wstr(err.msg); - const std::wstring replace = nb::WNEWLINE + L"┗-"; - if (err.trace) { - std::wstring trace_msg; - if (err.traceIsNBError) { - // How can I access - trace_msg = std::static_pointer_cast(err.trace)->what_wstr_impl(); - } else { - trace_msg = nb::str_to_wstr(std::string(err.trace->what())); - } - trace_msg = find_and_replace(trace_msg, L"┗", L"-"); - ret += replace + find_and_replace( - trace_msg, - nb::WNEWLINE, - replace - ); - } - return ret; - } -}; - -template -struct NBErrorWhatString { - inline static const std::string what(const ErrorBase& err) noexcept { - std::string ret = err.msg; - const std::string replace = nb::NEWLINE+" "; - if (err.trace) { - ret += replace + find_and_replace( - std::string(err.trace->what()), - nb::NEWLINE, - replace - ); - } - return ret; - } -}; - template class Error; @@ -221,6 +221,7 @@ public: template Error(Args... T) : Base(T...) {} + using Base::str; using Base::what; using Base::code; using Base::msg; @@ -242,6 +243,7 @@ public: GENERAL, UNDEFINED, BADERRORCODE }; + using Base::str; using Base::what; using Base::code; using Base::msg; diff --git a/engine/NBCore/TypeTraits.hpp b/engine/NBCore/TypeTraits.hpp index a1e7502..5277159 100644 --- a/engine/NBCore/TypeTraits.hpp +++ b/engine/NBCore/TypeTraits.hpp @@ -37,11 +37,6 @@ template < > using is_detected = typename detail::detector::value; -template -void stream(Stream& s, Args&&... args) { - (s << ... << args); -} - /*template inline typename std::enable_if::type ForEach(std::tuple&, Func) {} diff --git a/engine/NBCore/Utils.hpp b/engine/NBCore/Utils.hpp index 96194d3..01d6dac 100644 --- a/engine/NBCore/Utils.hpp +++ b/engine/NBCore/Utils.hpp @@ -1,16 +1,16 @@ #pragma once -#include -#include #ifndef _NB_CORE_TYPES #define _NB_CORE_TYPES +#include #include +#include namespace nb { #ifdef _NB_TARGET_WINDOWS - const std::string NEWLINE = "\r\n"; - const std::wstring WNEWLINE = L"\r\n"; + const std::string NEWLINE = "\n"; + const std::wstring WNEWLINE = L"\n"; #endif // _NB_TARGET_WINDOWS #ifdef _NB_TARGET_LINUX const std::string NEWLINE = "\n"; @@ -18,14 +18,14 @@ namespace nb { #endif // _NB_TARGET_LINUX template -std::enable_if_t, std::wstring> str_to_wstr(const T& in) { +std::enable_if_t, std::wstring> str_to_wstr(T in) { std::string str(in); std::wstring ret(str.begin(), str.end()); return ret; } template -std::enable_if_t, std::string> wstr_to_str(const T& in) { +std::enable_if_t, std::string> wstr_to_str(T in) { std::wstring wstr(in); std::size_t wstrlen = wstr.length(); char* c_str= new char[wstrlen]; @@ -35,11 +35,25 @@ std::enable_if_t, std::string> wst return ret; } +template +void stream(Stream& s, Args&&... args); + +template +void stream(Stream& s, Args&&... args) { + (s << ... << args); +} + +template +void term(Args&&... args) { stream(std::cout, args..., nb::NEWLINE); } + +template +void wterm(Args&&... args) { stream(std::wcout, args..., nb::WNEWLINE); } + template T find_and_replace( - const A& original, - const B& find, - const C& replace + A original, + B find, + C replace ) { const T& original_t = T(original); const T& find_t = T(find); @@ -50,10 +64,8 @@ T find_and_replace( std::size_t find_len = find_t.length(); std::size_t replace_len = replace_t.length(); std::size_t currpos = 0; - std::size_t lastpos = 0; while(true) { - lastpos = currpos; - currpos = original_t.find(find_t, lastpos); + currpos = ret.find(find_t, currpos); if (currpos == T::npos) { break; } diff --git a/engine/NBCore/tests/testErrors.cpp b/engine/NBCore/tests/testErrors.cpp index 6c778b7..81187be 100644 --- a/engine/NBCore/tests/testErrors.cpp +++ b/engine/NBCore/tests/testErrors.cpp @@ -3,9 +3,8 @@ #include #include "Errors.hpp" -#include #include -#include "TypeTraits.hpp" +#include "Utils.hpp" using namespace nb; @@ -36,12 +35,6 @@ const ErrorCodeMap TestError::ErrorMessages{ TEST(ErrorTest, Test) { - auto err = TestError(0, TestError(1)); - nb::stream(std::cout, - "len string: ", err.what_str().length(), "\n", - "len wstring: ", err.what_str().length(), "\n" - ); - nb::stream(std::wcout, - err.what_str(), L"\n" - ); + auto err = TestError(0, TestError(1, TestError(2, TestError(3, TestError(2))))); + ASSERT_STREQ(err.what(), "Hey!\n Trace: How\n Trace: You\n Trace: Doin\n Trace: You\n"); } \ No newline at end of file diff --git a/engine/NBCore/tests/testUtils.cpp b/engine/NBCore/tests/testUtils.cpp index f9188a1..e097788 100644 --- a/engine/NBCore/tests/testUtils.cpp +++ b/engine/NBCore/tests/testUtils.cpp @@ -1,4 +1,3 @@ -#include #define CODE_ERROR_LOCATIONS #include -- 2.43.0 From 40cf079e9db9a188a3ad01c55ccad7aa5b483d6b Mon Sep 17 00:00:00 2001 From: NaifBanana <30419422+NaifBanana@users.noreply.github.com> Date: Sun, 19 Apr 2026 18:08:58 -0500 Subject: [PATCH 06/11] Added type traits and string utils --- engine/NBCore/CMakeLists.txt | 2 + engine/NBCore/DataSink.hpp | 2 +- engine/NBCore/Errors.hpp | 34 ++----- engine/NBCore/Logger.hpp | 40 +++++--- engine/NBCore/StringUtils.hpp | 142 +++++++++++++++++++++++++++++ engine/NBCore/TypeTraits.hpp | 38 +++++++- engine/NBCore/Utils.hpp | 72 --------------- engine/NBCore/src/Logger.cpp | 2 + engine/NBCore/src/StringUtils.cpp | 1 + engine/NBCore/src/Utils.cpp | 7 -- engine/NBCore/tests/testErrors.cpp | 1 - engine/NBCore/tests/testUtils.cpp | 2 +- 12 files changed, 218 insertions(+), 125 deletions(-) create mode 100644 engine/NBCore/StringUtils.hpp create mode 100644 engine/NBCore/src/StringUtils.cpp diff --git a/engine/NBCore/CMakeLists.txt b/engine/NBCore/CMakeLists.txt index b457870..9f67cd0 100644 --- a/engine/NBCore/CMakeLists.txt +++ b/engine/NBCore/CMakeLists.txt @@ -2,6 +2,7 @@ toAbsolutePath(NB_CORE_SOURCE ./src/Errors.cpp # ./src/Logger.cpp ./src/Processes.cpp + ./src/StringUtils.cpp ./src/Utils.cpp ) @@ -11,6 +12,7 @@ toAbsolutePath(NB_CORE_INCLUDE ./Errors.hpp ./Logger.hpp ./Processes.hpp + ./StringUtils.hpp ./ThreadsafeQueue.hpp ./Types.hpp ./TypeTraits.hpp diff --git a/engine/NBCore/DataSink.hpp b/engine/NBCore/DataSink.hpp index 75cbad6..3aa0c50 100644 --- a/engine/NBCore/DataSink.hpp +++ b/engine/NBCore/DataSink.hpp @@ -77,7 +77,7 @@ public: bool isRunning() const noexcept override { return this->_running && (_runningThread!=nullptr); } - bool run() { + bool run() override { if (!type_ptr->isRunning()) { this->_running = true; _runningThread = std::make_shared([&]{ diff --git a/engine/NBCore/Errors.hpp b/engine/NBCore/Errors.hpp index e406347..d36f749 100644 --- a/engine/NBCore/Errors.hpp +++ b/engine/NBCore/Errors.hpp @@ -9,23 +9,7 @@ #include #include "TypeTraits.hpp" #include -#include "Utils.hpp" - -/* #ifndef THROW_WITH_INFO - #ifdef CODE_ERROR_LOCATIONS - #define THROW_WITH_INFO(type, ...) throw type(__VA_ARGS__, __LINE__, __FILE__) - #else - #define THROW_WITH_INFO(type, ...) throw type(__VA_ARGS__) - #endif // CODE_ERROR_LOCATIONS -#endif // THROW_WITH_INFO - -#ifndef THROW - #ifdef LOGGING - #define THROW_WTIH_INFO(type, ...) throw type(__VA_ARGS__, __LINE__, __FILE__) - #else - #define THROW(...) THROW_WITH_INFO(__VA_ARGS__) - #endif // LOGGING -#endif // THROW */ +#include "StringUtils.hpp" namespace nb { @@ -83,9 +67,9 @@ public: ErrorBase& operator=(const ErrorBase&) = delete; virtual inline std::string str() const noexcept override { - std::string ret = msg; + std::string ret = msg + nb::NEWLINE; if (trace) { - const std::string replace = nb::NEWLINE+" "; + const std::string tabover = " "; std::string trace_msg; if (traceIsNBError) { trace_msg = std::static_pointer_cast(trace)->str(); @@ -95,13 +79,9 @@ public: } else { trace_msg = std::string(trace->what()); } - ret += replace + "Trace: " + find_and_replace( - trace_msg, - nb::NEWLINE, - replace - ); + ret += indent_strblock(trace_msg, tabover, tabover+"Trace: ")+nb::NEWLINE; } - return ret + nb::NEWLINE; + return ret; } static const std::string type; @@ -226,6 +206,7 @@ public: using Base::code; using Base::msg; using Base::trace; + using Base::traceIsNBError; using Base::type; using Base::ErrorMessages; @@ -245,10 +226,11 @@ public: using Base::str; using Base::what; + using Base::code; using Base::msg; using Base::trace; - + using Base::traceIsNBError; static const std::string type; static const ErrorCodeMap ErrorMessages; }; diff --git a/engine/NBCore/Logger.hpp b/engine/NBCore/Logger.hpp index e767eea..40919f6 100644 --- a/engine/NBCore/Logger.hpp +++ b/engine/NBCore/Logger.hpp @@ -2,15 +2,28 @@ #ifndef _NB_LOGGER #define _NB_LOGGER -#include #include -#include #include #include -#include #include #include +#ifndef THROW_WITH_INFO + #ifdef CODE_ERROR_LOCATIONS + #define THROW_WITH_INFO(type, ...) throw type(__VA_ARGS__, __LINE__, __FILE__) + #else + #define THROW_WITH_INFO(type, ...) throw type(__VA_ARGS__) + #endif // CODE_ERROR_LOCATIONS +#endif // THROW_WITH_INFO + +#ifndef THROW + #ifdef LOGGING + #define THROW_WTIH_INFO(type, ...) throw type(__VA_ARGS__, __LINE__, __FILE__) + #else + #define THROW(...) THROW_WITH_INFO(__VA_ARGS__) + #endif // LOGGING +#endif // THROW + #include "DataSink.hpp" #include "Processes.hpp" #include "ThreadSafeQueue.hpp" @@ -23,14 +36,6 @@ typedef std::chrono::time_point< std::chrono::nanoseconds > LoggerTimePoint; -struct LogEvent{ - const LoggerTimePoint time; - const unsigned char lvl; - const std::string msg; - const std::thread::id tid; - const uint64_t pid; -}; - typedef std::string (*LogProcessFunction)(const LoggerTimePoint&, const std::string&); typedef std::unordered_map LogProcessFunctionMap; @@ -41,7 +46,7 @@ class LoggerBase using LoggerType = Logger; using Base = MultithreadedDataProcessor; public: - bool run() { + bool run() override { if (!type_ptr->isRunning()) { this->_running = true; this->_runningThread = std::make_shared([&]{ @@ -62,6 +67,14 @@ private: LoggerType* type_ptr = static_cast(this); }; +struct LogEvent{ + const LoggerTimePoint time; + const unsigned char lvl; + const std::string msg; + const std::thread::id tid; + const uint64_t pid; +}; + template class DebugLogger : public LoggerBase>{ using StreamType = std::vector; @@ -90,7 +103,7 @@ public: } void log(const std::exception& err, const uint8_t& lvl=0xFF) { - type_ptr->log(err.what(), lvl); + type_ptr->log(prepend_strblock(err.what(), " "), lvl); } template @@ -104,7 +117,6 @@ protected: private: LoggerType* type_ptr = static_cast(this); - }; class DefaultDebugLogger : public DebugLogger { diff --git a/engine/NBCore/StringUtils.hpp b/engine/NBCore/StringUtils.hpp new file mode 100644 index 0000000..a8cab98 --- /dev/null +++ b/engine/NBCore/StringUtils.hpp @@ -0,0 +1,142 @@ +#pragma once +#ifndef _NB_CORE_TYPES +#define _NB_CORE_TYPES + +#include +#include +#include + +#include "TypeTraits.hpp" + +namespace nb { + +#ifdef _NB_TARGET_WINDOWS + const std::string NEWLINE = "\n"; + const std::wstring WNEWLINE = L"\n"; +#endif // _NB_TARGET_WINDOWS +#ifdef _NB_TARGET_LINUX + const std::string NEWLINE = "\n"; + const std::wstring WNEWLINE = L"\n"; +#endif // _NB_TARGET_LINUX + +template +using StringConvertible = ValidConversion; + +template +using WStringConvertible = ValidConversion; + +template +constexpr bool StringConvertible_v = StringConvertible::value; + +template +constexpr bool WStringConvertible_v = WStringConvertible::value; + +template +using StringConvertible_to = typename StringConvertible::to; + +template +using WStringConvertible_to = typename WStringConvertible::to; + +template +using StringConvertible_from = typename StringConvertible::from; + +template +using WStringConvertible_from = typename WStringConvertible::from; + +template +std::enable_if_t, std::wstring> str_to_wstr(T in) { + std::string str(in); + std::wstring ret(str.begin(), str.end()); + return ret; +} + +template +std::enable_if_t, std::string> wstr_to_str(T in) { + std::wstring wstr(in); + std::size_t wstrlen = wstr.length(); + char* c_str= new char[wstrlen]; + std::wcstombs(c_str, wstr.c_str(), wstrlen); + std::string ret(c_str, wstrlen); + delete[] c_str; + return ret; +} + +template +void stream(Stream& s, Args&&... args); + +template +void stream(Stream& s, Args&&... args) { + (s << ... << args); +} + +template +void term(Args&&... args) { stream(std::cout, args..., nb::NEWLINE); } + +template +void wterm(Args&&... args) { stream(std::wcout, args..., nb::WNEWLINE); } + +template +ValidConversion_to find_and_replace( + A original, + B find, + C replace +) { + const T& find_t = T(find); + const T& replace_t = T(replace); + + T ret(original); + + std::size_t find_len = find_t.length(); + std::size_t replace_len = replace_t.length(); + std::size_t currpos = 0; + while(true) { + currpos = ret.find(find_t, currpos); + if (currpos == T::npos) { + break; + } + ret = ret.erase(currpos, find_len); + ret = ret.insert(currpos, replace_t); + currpos += replace_len; + } + return ret; +} + +template +StringConvertible_to indent_strblock( + A block, + B prepend, + C topIndent +) { + return std::string(topIndent) + find_and_replace( + std::string(block), + nb::NEWLINE, + nb::NEWLINE + std::string(prepend) + ); +} + +template +StringConvertible_to indent_strblock( + A block, + B prepend +) { + return indent_strblock(block, prepend, prepend); +} + +/* template +T swap_endian(const T& val) { + T ret; + const int size = sizeof(T); + auto retLoc = static_cast(&ret); + auto valLoc = static_cast(&val); + + for (int i = 0; i < size; ++i) { + memcpy(retLoc+i, valLoc+(size-i-1), 1); + } + return ret; +} */ + + +// using ByteVector = std::vector; + +} // namespace nb +#endif // _NB_CORE_TYPES \ No newline at end of file diff --git a/engine/NBCore/TypeTraits.hpp b/engine/NBCore/TypeTraits.hpp index 5277159..f92df9a 100644 --- a/engine/NBCore/TypeTraits.hpp +++ b/engine/NBCore/TypeTraits.hpp @@ -2,7 +2,9 @@ #ifndef _NB_TYPE_TRAITS #define _NB_TYPE_TRAITS +#include #include +#include namespace nb { @@ -37,11 +39,41 @@ template < > using is_detected = typename detail::detector::value; -/*template +template +struct ValidConversion; + +template +struct ValidConversion { + typedef std::conjunction< + std::is_constructible, std::is_constructible, std::conjunction...> + > value_type; + static constexpr bool value = value_type::value; + typedef std::enable_if_t to; + +}; + +template +struct ValidConversion { + typedef std::is_constructible value_type; + static constexpr bool value = value_type::value; + typedef std::enable_if_t to; + typedef std::enable_if_t from; +}; + +template +using ValidConversion_v = typename ValidConversion::value; + +template +using ValidConversion_to = typename ValidConversion::to; + +template +using ValidConversion_from = typename ValidConversion::from; + +template inline typename std::enable_if::type ForEach(std::tuple&, Func) {} -template +template inline typename std::enable_if::type ForEach(std::tuple& tup, Func f) { f(N, std::get(tup)); @@ -99,7 +131,7 @@ struct PackIsSameType { template struct PackIsSameType { const bool value = std::is_base_of::value && PackIsSameType::value; -};*/ +}; } // namespace nb diff --git a/engine/NBCore/Utils.hpp b/engine/NBCore/Utils.hpp index 01d6dac..a8d47a5 100644 --- a/engine/NBCore/Utils.hpp +++ b/engine/NBCore/Utils.hpp @@ -2,80 +2,8 @@ #ifndef _NB_CORE_TYPES #define _NB_CORE_TYPES -#include -#include -#include - namespace nb { -#ifdef _NB_TARGET_WINDOWS - const std::string NEWLINE = "\n"; - const std::wstring WNEWLINE = L"\n"; -#endif // _NB_TARGET_WINDOWS -#ifdef _NB_TARGET_LINUX - const std::string NEWLINE = "\n"; - const std::wstring WNEWLINE = L"\n"; -#endif // _NB_TARGET_LINUX - -template -std::enable_if_t, std::wstring> str_to_wstr(T in) { - std::string str(in); - std::wstring ret(str.begin(), str.end()); - return ret; -} - -template -std::enable_if_t, std::string> wstr_to_str(T in) { - std::wstring wstr(in); - std::size_t wstrlen = wstr.length(); - char* c_str= new char[wstrlen]; - std::wcstombs(c_str, wstr.c_str(), wstrlen); - std::string ret(c_str, wstrlen); - delete[] c_str; - return ret; -} - -template -void stream(Stream& s, Args&&... args); - -template -void stream(Stream& s, Args&&... args) { - (s << ... << args); -} - -template -void term(Args&&... args) { stream(std::cout, args..., nb::NEWLINE); } - -template -void wterm(Args&&... args) { stream(std::wcout, args..., nb::WNEWLINE); } - -template -T find_and_replace( - A original, - B find, - C replace -) { - const T& original_t = T(original); - const T& find_t = T(find); - const T& replace_t = T(replace); - - T ret = original_t; - - std::size_t find_len = find_t.length(); - std::size_t replace_len = replace_t.length(); - std::size_t currpos = 0; - while(true) { - currpos = ret.find(find_t, currpos); - if (currpos == T::npos) { - break; - } - ret = ret.erase(currpos, find_len); - ret = ret.insert(currpos, replace_t); - currpos += replace_len; - } - return ret; -} - /* template T swap_endian(const T& val) { T ret; diff --git a/engine/NBCore/src/Logger.cpp b/engine/NBCore/src/Logger.cpp index 1deed87..042fdaf 100644 --- a/engine/NBCore/src/Logger.cpp +++ b/engine/NBCore/src/Logger.cpp @@ -10,6 +10,8 @@ static bool RUN_LOGGER(nb::DefaultDebugLogger& log) { return log.run(); } + + static const bool LOGGER_RUNNING = RUN_LOGGER(logger); } // namespace nb \ No newline at end of file diff --git a/engine/NBCore/src/StringUtils.cpp b/engine/NBCore/src/StringUtils.cpp new file mode 100644 index 0000000..44f97f5 --- /dev/null +++ b/engine/NBCore/src/StringUtils.cpp @@ -0,0 +1 @@ +#include "StringUtils.hpp" diff --git a/engine/NBCore/src/Utils.cpp b/engine/NBCore/src/Utils.cpp index 336d3b6..8b13789 100644 --- a/engine/NBCore/src/Utils.cpp +++ b/engine/NBCore/src/Utils.cpp @@ -1,8 +1 @@ -#include -#include "Utils.hpp" -template<> -std::wstring nb::str_to_wstr(const std::string& in) { - std::wstring ret(in.begin(), in.end()); - return ret; -} diff --git a/engine/NBCore/tests/testErrors.cpp b/engine/NBCore/tests/testErrors.cpp index 81187be..1e919aa 100644 --- a/engine/NBCore/tests/testErrors.cpp +++ b/engine/NBCore/tests/testErrors.cpp @@ -4,7 +4,6 @@ #include "Errors.hpp" #include -#include "Utils.hpp" using namespace nb; diff --git a/engine/NBCore/tests/testUtils.cpp b/engine/NBCore/tests/testUtils.cpp index e097788..24ca054 100644 --- a/engine/NBCore/tests/testUtils.cpp +++ b/engine/NBCore/tests/testUtils.cpp @@ -4,7 +4,7 @@ #include #include "TypeTraits.hpp" -#include "Utils.hpp" +#include "StringUtils.hpp" namespace nb { -- 2.43.0 From 0f62aecfa35c9fd1143df6a4f162ab4b0eb0f72b Mon Sep 17 00:00:00 2001 From: NaifBanana <30419422+NaifBanana@users.noreply.github.com> Date: Sun, 19 Apr 2026 19:19:47 -0500 Subject: [PATCH 07/11] Error logging almost working! --- CMakeLists.txt | 1 + engine/NBCore/CMakeLists.txt | 2 +- engine/NBCore/DataSink.hpp | 7 +++-- engine/NBCore/Errors.hpp | 7 +++-- engine/NBCore/Logger.hpp | 48 ++++++++++++++---------------- engine/NBCore/src/Logger.cpp | 14 +++++++++ engine/NBCore/tests/CMakeLists.txt | 8 +++++ engine/NBCore/tests/testLogger.cpp | 17 +++++++++++ 8 files changed, 73 insertions(+), 31 deletions(-) create mode 100644 engine/NBCore/tests/testLogger.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 65af2c9..9473a5f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -61,6 +61,7 @@ endif() if (NB_LOGGING) message(STATUS "Building with automatic logging") add_compile_definitions(_NB_AUTOLOG) + add_compile_definitions(_NB_CODE_ERROR_LOCATIONS) endif() if (NB_TARGET_WINDOWS) diff --git a/engine/NBCore/CMakeLists.txt b/engine/NBCore/CMakeLists.txt index 9f67cd0..ee3a13b 100644 --- a/engine/NBCore/CMakeLists.txt +++ b/engine/NBCore/CMakeLists.txt @@ -1,6 +1,6 @@ toAbsolutePath(NB_CORE_SOURCE ./src/Errors.cpp -# ./src/Logger.cpp + ./src/Logger.cpp ./src/Processes.cpp ./src/StringUtils.cpp ./src/Utils.cpp diff --git a/engine/NBCore/DataSink.hpp b/engine/NBCore/DataSink.hpp index 3aa0c50..d3c5d25 100644 --- a/engine/NBCore/DataSink.hpp +++ b/engine/NBCore/DataSink.hpp @@ -2,6 +2,7 @@ #ifndef _NB_DATASINK #define _NB_DATASINK +#include #include #include "ThreadSafeQueue.hpp" @@ -34,9 +35,9 @@ class BufferedDataProcessor : public DataSink { public: using Base::Base; - bool stop() noexcept { return type_ptr->stop(); } - bool run() { return type_ptr->run(); } - bool in(const DataType& val) { return type_ptr->in(val); } + virtual bool stop() noexcept override { return type_ptr->stop(); } + virtual bool run() override { return type_ptr->run(); } + virtual bool in(const DataType& val) override { return type_ptr->in(val); } protected: unsigned int count() const { diff --git a/engine/NBCore/Errors.hpp b/engine/NBCore/Errors.hpp index d36f749..35d94db 100644 --- a/engine/NBCore/Errors.hpp +++ b/engine/NBCore/Errors.hpp @@ -178,7 +178,7 @@ protected: ) noexcept : ErrorBase( 0, msg_, - nullptr, + static_cast(nullptr), line_, filename_ ) {} @@ -199,7 +199,7 @@ class Error : public ErrorBase { using Base = ErrorBase; public: template - Error(Args... T) : Base(T...) {} + Error(Args... args) : Base(args...) {} using Base::str; using Base::what; @@ -219,6 +219,9 @@ class Error : public ErrorBase> { public: using Base::Base; Error() : Base(0) {} + + template + Error(Args... args) : Base(args...) {} enum Codes : unsigned int { GENERAL, UNDEFINED, BADERRORCODE diff --git a/engine/NBCore/Logger.hpp b/engine/NBCore/Logger.hpp index 40919f6..2c332bf 100644 --- a/engine/NBCore/Logger.hpp +++ b/engine/NBCore/Logger.hpp @@ -8,22 +8,6 @@ #include #include -#ifndef THROW_WITH_INFO - #ifdef CODE_ERROR_LOCATIONS - #define THROW_WITH_INFO(type, ...) throw type(__VA_ARGS__, __LINE__, __FILE__) - #else - #define THROW_WITH_INFO(type, ...) throw type(__VA_ARGS__) - #endif // CODE_ERROR_LOCATIONS -#endif // THROW_WITH_INFO - -#ifndef THROW - #ifdef LOGGING - #define THROW_WTIH_INFO(type, ...) throw type(__VA_ARGS__, __LINE__, __FILE__) - #else - #define THROW(...) THROW_WITH_INFO(__VA_ARGS__) - #endif // LOGGING -#endif // THROW - #include "DataSink.hpp" #include "Processes.hpp" #include "ThreadSafeQueue.hpp" @@ -87,7 +71,7 @@ public: ~DebugLogger() { type_ptr->stop(); } - void log(const std::string& msg, const uint8_t& lvl=0xFF) { + void log(const std::string& msg, const uint8_t& lvl=0x00) { type_ptr->push(LogEvent{ std::chrono::system_clock::now(), lvl, @@ -98,12 +82,12 @@ public: } template - void log(char const(&msg) [N], const uint8_t& lvl=0xFF) { + void log(char const(&msg) [N], const uint8_t& lvl=0x00) { type_ptr->log(std::string(msg), lvl); } void log(const std::exception& err, const uint8_t& lvl=0xFF) { - type_ptr->log(prepend_strblock(err.what(), " "), lvl); + type_ptr->log(err.what(), lvl); } template @@ -139,17 +123,31 @@ public: protected: using Base::_ostream; - bool process(const LogEvent& msg) { - for (const auto os : this->_ostream) { - *os << msg.lvl << "\t|\t" << msg.msg << "\n"; - } - return true; - } + bool process(const LogEvent& msg); }; +#ifndef _NB_NO_LOGGER extern DefaultDebugLogger logger; +#endif // _NB_NO_LOGGER // Taking Charge of Adult ADHD by Russell Barkley } // namespace nb + +#ifndef CONSTRUCT_ERROR + #ifdef _NB_CODE_ERROR_LOCATIONS + #define CONSTRUCT_ERROR(type, ...) type(# __VA_ARGS__, __LINE__, __FILE__) + #else + #define CONSTRUCT_ERROR(type, ...) type(__VA_ARGS__) + #endif // _NB_CODE_ERROR_LOCATIONS +#endif // CONSTRUCT_ERROR + +#ifndef THROW + #ifdef _NB_AUTOLOG + #define THROW(type, ...) {auto x = CONSTRUCT_ERROR(type, ## __VA_ARGS__); nb::logger.error(x); throw x;} + #else + #define THROW(type, ...) throw CONSTRUCT_ERROR(type, __VA_ARGS__) + #endif // _NB_AUTOLOG +#endif // THROW + #endif // _NB_LOGGER \ No newline at end of file diff --git a/engine/NBCore/src/Logger.cpp b/engine/NBCore/src/Logger.cpp index 042fdaf..b9353a4 100644 --- a/engine/NBCore/src/Logger.cpp +++ b/engine/NBCore/src/Logger.cpp @@ -1,10 +1,24 @@ #include #include "Logger.hpp" +#include "StringUtils.hpp" namespace nb { +#ifndef _NB_NO_LOGGER nb::DefaultDebugLogger logger(std::cout); +#endif // _NB_NO_LOGGER + +bool nb::DefaultDebugLogger::process(const LogEvent& msg) { + for (const auto os : this->_ostream) { + *os << indent_strblock( + msg.msg, + std::string(10, ' '), + "[ "+std::to_string(msg.lvl)+" ] : " + ) << nb::NEWLINE; + } + return true; +} static bool RUN_LOGGER(nb::DefaultDebugLogger& log) { return log.run(); diff --git a/engine/NBCore/tests/CMakeLists.txt b/engine/NBCore/tests/CMakeLists.txt index 02c31c7..34476ff 100644 --- a/engine/NBCore/tests/CMakeLists.txt +++ b/engine/NBCore/tests/CMakeLists.txt @@ -12,5 +12,13 @@ if (NB_BUILD_TESTS) NBCore GTest::gtest_main ) + + add_executable(LoggerTest + ./testLogger.cpp + ) + target_link_libraries(LoggerTest + NBCore + ) + gtest_discover_tests(TestCore) endif() \ No newline at end of file diff --git a/engine/NBCore/tests/testLogger.cpp b/engine/NBCore/tests/testLogger.cpp new file mode 100644 index 0000000..da6fb99 --- /dev/null +++ b/engine/NBCore/tests/testLogger.cpp @@ -0,0 +1,17 @@ +#include + +#include "Errors.hpp" +#include "Logger.hpp" + + + +int main() { + nb::logger.log("Whoop!"); + try { + THROW(nb::Error, "Hiii!"); + } catch (nb::Error e){ + nb::logger.log("Winner winner chicken dinner!"); + } + + return 0; +} \ No newline at end of file -- 2.43.0 From 58121bdf2818c113af3441a11557663c15e0b603 Mon Sep 17 00:00:00 2001 From: NaifBanana <30419422+NaifBanana@users.noreply.github.com> Date: Sat, 2 May 2026 01:50:53 -0500 Subject: [PATCH 08/11] Got logging and errors basically all working the way I want --- engine/NBCore/Errors.hpp | 331 ++++++++++++++++------------- engine/NBCore/Logger.hpp | 168 ++++++++++++--- engine/NBCore/StringUtils.hpp | 117 +++------- engine/NBCore/TypeTraits.hpp | 18 ++ engine/NBCore/src/Errors.cpp | 7 +- engine/NBCore/src/Logger.cpp | 16 +- engine/NBCore/src/StringUtils.cpp | 28 +++ engine/NBCore/tests/testErrors.cpp | 2 +- engine/NBCore/tests/testLogger.cpp | 35 ++- engine/NBCore/tests/testUtils.cpp | 34 +-- 10 files changed, 465 insertions(+), 291 deletions(-) diff --git a/engine/NBCore/Errors.hpp b/engine/NBCore/Errors.hpp index 35d94db..2e38434 100644 --- a/engine/NBCore/Errors.hpp +++ b/engine/NBCore/Errors.hpp @@ -5,7 +5,6 @@ #include #include #include -#include #include #include "TypeTraits.hpp" #include @@ -15,103 +14,87 @@ namespace nb { typedef std::unordered_map ErrorCodeMap; +template +constexpr bool IsValidException_v = std::is_base_of_v; template -using has_type = decltype(T::type); +using IsValidException = std::enable_if_t, bool>; -template +template class ErrorBase; +template +class Error; + +template +constexpr bool IsValidNBError_v = std::is_base_of_v, T>; +template +using IsValidNBError = std::enable_if_t, bool>; + + template<> -class ErrorBase : public std::exception { +class ErrorBase { public: const unsigned int code; const std::string msg; - const std::shared_ptr trace; + const std::string type; + const std::shared_ptr trace; const bool traceIsNBError; - virtual inline std::string str() const noexcept = 0; - - virtual const char* what() const noexcept override final { - const std::string& ret = str(); - return ret.c_str(); - } - + virtual std::string what() const noexcept = 0; + virtual std::shared_ptr make_shared() const noexcept = 0; + protected: - template < - typename TraceType = std::exception, - std::enable_if_t, bool> = true - > + template + ErrorBase(const ErrorBase& err) : ErrorBase(std::move(err)) {} + + template + ErrorBase(ErrorBase&& err) : ErrorBase( + err.code, + err.msg, + err.type, + (err.traceIsNBError) + ? static_cast(err.trace.get()) + : static_cast(err.trace.get()) + ) {} + ErrorBase( - const unsigned int& code_, - const std::string& msg_, - const std::shared_ptr trace_, - const unsigned int& line_, - std::string filename_ + unsigned int code_, + std::string msg_, + std::string type_, + const std::exception* trace_ ) noexcept : code(code_), msg(msg_), - trace{std::dynamic_pointer_cast(trace_)}, - traceIsNBError( trace_ ? is_detected::value : false) - { - static_assert(std::is_base_of::value, - "`trace_` must be a pointer to a child object of std::exception." - ); - } + type(type_), + trace{ trace_ ? + std::static_pointer_cast( + std::make_shared>(*trace_)) + : nullptr, + }, + traceIsNBError(false) + {} + + template, bool> = true> + ErrorBase( + unsigned int code_, + std::string msg_, + std::string type_, + const T* trace_ + ) noexcept : + code(code_), + msg(msg_), + type(type_), + trace{trace_ ? trace_->make_shared() : nullptr}, + traceIsNBError(true) + {} }; + template class ErrorBase : public ErrorBase { +private: using Base = ErrorBase; -public: - ErrorBase(const ErrorBase&) = default; - ErrorBase& operator=(const ErrorBase&) = delete; - - virtual inline std::string str() const noexcept override { - std::string ret = msg + nb::NEWLINE; - if (trace) { - const std::string tabover = " "; - std::string trace_msg; - if (traceIsNBError) { - trace_msg = std::static_pointer_cast(trace)->str(); - trace_msg = std::string(std::string_view(trace_msg).substr( - 0, trace_msg.length()-nb::NEWLINE.length() - )); - } else { - trace_msg = std::string(trace->what()); - } - ret += indent_strblock(trace_msg, tabover, tabover+"Trace: ")+nb::NEWLINE; - } - return ret; - } - - static const std::string type; - static const ErrorCodeMap ErrorMessages; - - using Base::code; - using Base::msg; - using Base::trace; - using Base::traceIsNBError; - -protected: - using Base::Base; - - template < - typename TraceType = std::exception, - std::enable_if_t, bool> = true - > - ErrorBase( - const unsigned int code_, - std::string msg_, - const TraceType* trace_=nullptr, - unsigned int line_=0, - std::string filename_="" - ) : Base( - code_, - msg_, - trace_ ? std::make_shared(*trace_) : nullptr, - line_, - filename_ - ) { + void inline check_asserts() { static_assert(std::is_same, decltype(ErrorType::ErrorMessages)>::value, "const std::unordered_map ErrorMessages must be " "a class member." @@ -125,83 +108,117 @@ protected: ); } - template < - typename TraceType, - std::enable_if_t, bool> = true - > - ErrorBase( - const unsigned int& code_, - const TraceType& trace_, - unsigned int line_=0, - std::string filename_="" - ) noexcept : ErrorBase( - code_, - ErrorType::ErrorMessages.at(code_), - &trace_, - line_, - filename_ - ) {} +public: + template + ErrorBase(const ErrorBase& cpy) : Base(cpy) { check_asserts(); } - template < - typename TraceType, - std::enable_if_t, bool> = true - > + virtual std::shared_ptr make_shared() const noexcept override { + return std::static_pointer_cast( + std::make_shared(*this) + ); + } + + virtual std::string what() const noexcept override { + std::string ret = msg; + if (trace) { + std::string trace_msg; + if (traceIsNBError) { + trace_msg = std::static_pointer_cast(trace)->what(); + } else { + trace_msg = std::string(std::static_pointer_cast(trace)->what()); + } + ret += nb::NEWLINE + indent_strblock( + trace_msg, + nb::TABOVER, + nb::TABOVER+"Trace: " + ); + } + return ret; + } + + static const std::string type; + static const ErrorCodeMap ErrorMessages; + + using Base::code; + using Base::msg; + using Base::trace; + using Base::traceIsNBError; + + friend ErrorType; + friend Error; + +protected: + using Base::Base; + + template ErrorBase( - const std::string& msg_, - const TraceType& trace_, - unsigned int line_=0, - std::string filename_="" - ) noexcept : ErrorBase( - 0, + unsigned int code_, + std::string msg_, + std::string type_, + const T* trace_ + ) : Base( + code_, msg_, - &trace_, - line_, - filename_ - ) {} - - ErrorBase( - const unsigned int& code_, - unsigned int line_=0, - std::string filename_="" - ) noexcept : ErrorBase( - code_, - ErrorType::ErrorMessages.at(code_), - static_cast(nullptr), - line_, - filename_ - ) {} - - ErrorBase( - const std::string& msg_, - unsigned int line_=0, - std::string filename_="" - ) noexcept : ErrorBase( - 0, - msg_, - static_cast(nullptr), - line_, - filename_ - ) {} + type_, + trace_ + ) { check_asserts(); } }; template const std::string ErrorBase::type = ErrorType::type; template const ErrorCodeMap ErrorBase::ErrorMessages = ErrorType::ErrorMessages; -template -class Error; - -template<> -class Error; template class Error : public ErrorBase { using Base = ErrorBase; -public: - template - Error(Args... args) : Base(args...) {} +public: + template + Error( + unsigned int code_, + const T& trace_ + ) noexcept : Base( + code_, + ErrorType::ErrorMessages.at(code_), + ErrorType::type, + &trace_ + ) {} + + template + Error( + std::string msg_, + const ErrorBase& trace_ + ) noexcept : Base( + 0, + msg_, + ErrorType::type, + &trace_ + ) {} + + Error( + std::string msg_, + const std::exception& trace_ + ) noexcept : Base( + 0, + msg_, + ErrorType::type, + &trace_ + ) {} + + Error(unsigned int code_) noexcept : Base( + code_, + ErrorType::ErrorMessages.at(code_), + ErrorType::type, + NULLPTR + ) {} + + Error(std::string msg_) noexcept : Base( + 0, + msg_, + ErrorType::type, + NULLPTR + ) {} - using Base::str; using Base::what; using Base::code; using Base::msg; @@ -210,24 +227,43 @@ public: using Base::type; using Base::ErrorMessages; - friend ErrorBase; +protected: + using Base::Base; + }; + template<> class Error : public ErrorBase> { using Base = ErrorBase>; public: using Base::Base; - Error() : Base(0) {} - template - Error(Args... args) : Base(args...) {} + Error(unsigned int code_=1) noexcept : Base( + code_, + ErrorMessages.at(code_), + type, + NULLPTR + ) {} + + Error(const std::exception& err) : Base( + Codes::STANDARD, + std::string(err.what()), + "std::exception", + nullptr + ) {} + + Error(std::string msg_) noexcept : Base( + Codes::UNDEFINED, + msg_, + type, + NULLPTR + ) {} enum Codes : unsigned int { - GENERAL, UNDEFINED, BADERRORCODE + STANDARD, UNDEFINED }; - using Base::str; using Base::what; using Base::code; @@ -238,6 +274,7 @@ public: static const ErrorCodeMap ErrorMessages; }; + } // namespace nb #endif // _NB_ERROR \ No newline at end of file diff --git a/engine/NBCore/Logger.hpp b/engine/NBCore/Logger.hpp index 2c332bf..e0f1f19 100644 --- a/engine/NBCore/Logger.hpp +++ b/engine/NBCore/Logger.hpp @@ -9,6 +9,7 @@ #include #include "DataSink.hpp" +#include "Errors.hpp" #include "Processes.hpp" #include "ThreadSafeQueue.hpp" #include "TypeTraits.hpp" @@ -31,24 +32,21 @@ class LoggerBase using Base = MultithreadedDataProcessor; public: bool run() override { - if (!type_ptr->isRunning()) { + if (!static_cast(this)->isRunning()) { this->_running = true; this->_runningThread = std::make_shared([&]{ - while(type_ptr->isRunning()) { - type_ptr->flush(); + while(static_cast(this)->isRunning()) { + static_cast(this)->flush(); } - type_ptr->flush(); + static_cast(this)->flush(); }); } - return type_ptr->isRunning(); + return static_cast(this)->isRunning(); } protected: LoggerBase() = default; StreamType _ostream; - -private: - LoggerType* type_ptr = static_cast(this); }; struct LogEvent{ @@ -57,6 +55,8 @@ struct LogEvent{ const std::string msg; const std::thread::id tid; const uint64_t pid; + const std::string file=""; + const unsigned int line=0; }; template @@ -69,38 +69,73 @@ public: template DebugLogger(ST&... streams) : _ostream(nb::RefPackToPtrVec(streams...).vec) {} - ~DebugLogger() { type_ptr->stop(); } + ~DebugLogger() { static_cast(this)->stop(); } - void log(const std::string& msg, const uint8_t& lvl=0x00) { - type_ptr->push(LogEvent{ + void log( + std::string msg, + uint8_t lvl=0x00, + std::string file="", + unsigned int line=0 + ) { + static_cast(this)->push(LogEvent{ std::chrono::system_clock::now(), lvl, msg, std::this_thread::get_id(), GetPID(), + file, + line }); } template - void log(char const(&msg) [N], const uint8_t& lvl=0x00) { - type_ptr->log(std::string(msg), lvl); + void log( + char const(&msg) [N], + uint8_t lvl=0x00, + std::string file="", + unsigned int line=0 + ) { + static_cast(this)->log(std::string(msg), lvl, file, line); } - void log(const std::exception& err, const uint8_t& lvl=0xFF) { - type_ptr->log(err.what(), lvl); + template + void log( + const ErrorBase& err, + uint8_t lvl=0xFF, + std::string file="", + unsigned int line=0 + ) { + static_cast(this)->log(err.what(), lvl, file, line); + } + + template + std::enable_if_t, void> log( + const T& err, + uint8_t lvl=0xFF, + std::string file="", + unsigned int line=0 + ) { + static_cast(this)->log(std::string(err.what()), lvl, file, line); } template - void warn(const U& val, const uint8_t& lvl=0x01) { type_ptr->log(val, lvl); } + void warn( + U val, + uint8_t lvl=0x01, + std::string file="", + unsigned int line=0 + ) { static_cast(this)->log(val, lvl, file, line); } template - void error(const U& val) { type_ptr->log(val, 0xFF); } + void error( + U val, + std::string file="", + unsigned int line=0 + ) { static_cast(this)->log(val, 0xFF, file, line); } protected: std::vector _ostream; -private: - LoggerType* type_ptr = static_cast(this); }; class DefaultDebugLogger : public DebugLogger { @@ -132,22 +167,103 @@ extern DefaultDebugLogger logger; // Taking Charge of Adult ADHD by Russell Barkley +/* template +struct NB_DEFAULT_LOGGER_THROW; + +template<> +struct NB_DEFAULT_LOGGER_THROW { + template + NB_DEFAULT_LOGGER_THROW(T arg) { + #ifdef _NB_AUTOLOG + logger.error(arg); + #endif // _NB_AUTLOG + throw arg; + } +}; + +template +struct NB_DEFAULT_LOGGER_THROW { + template + NB_DEFAULT_LOGGER_THROW(Args&&... args) { + std::shared_ptr error_ptr; + #ifdef _NB_AUTOLOG + #ifdef _NB_CODE_ERROR_LOCATIONS + error_ptr = std::make_shared(args..., __LINE__, __FILE__); + #else + error_ptr = std::make_shared(args...); + #endif // _NB_CODE_ERROR_LOCATIONS + logger.error(*error_ptr); + #endif // _NB_AUTLOG + throw *error_ptr; + } +}; */ + +/* template +void NB_DEFAULT_LOGGER_THROW(Args&& ... args) { + std::shared_ptr error_ptr; + #ifdef _NB_AUTOLOG + #ifdef _NB_CODE_ERROR_LOCATIONS + error_ptr = std::make_shared(args..., __LINE__, __FILE__); + #else + error_ptr = std::make_shared(args...); + #endif // _NB_CODE_ERROR_LOCATIONS + logger.error(*error_ptr); + #endif // _NB_AUTLOG + throw *error_ptr; +} + +template +void NB_DEFAULT_LOGGER_THROW(const Arg& arg) { + #ifdef _NB_AUTOLOG + logger.error(arg); + #endif // _NB_AUTLOG + throw arg; +} */ + +template +void NB_DEFAULT_LOGGER_THROW(const T& err, std::string file="", unsigned int line = 0) { + #ifdef _NB_AUTOLOG + if (file.empty()) { + logger.error(err); + } else { + logger.error(err, file, line); + } + #endif // _NB_AUTLOG + throw err; +} + } // namespace nb -#ifndef CONSTRUCT_ERROR +#ifdef _NB_AUTOLOG #ifdef _NB_CODE_ERROR_LOCATIONS - #define CONSTRUCT_ERROR(type, ...) type(# __VA_ARGS__, __LINE__, __FILE__) + #ifndef LOG + #define LOG(args...) nb::logger.log(args, __FILE__, __LINE__) + #endif // LOG + #ifndef WARN + #define WARN(args...) nb::logger.warn(args, __FILE__, __LINE__) + #endif // WARN + #ifndef ERROR + #define ERROR(args...) nb::logger.error(args, __FILE__, __LINE__) + #endif // ERROR #else - #define CONSTRUCT_ERROR(type, ...) type(__VA_ARGS__) + #ifndef LOG + #define LOG(args...) nb::logger.log(args) + #endif // LOG + #ifndef WARN + #define WARN(args...) nb::logger.warn(args) + #endif // WARN + #ifndef ERROR + #define ERROR(args...) nb::logger.error(args) + #endif // ERROR #endif // _NB_CODE_ERROR_LOCATIONS -#endif // CONSTRUCT_ERROR +#endif // _NB_AUTOLOG #ifndef THROW #ifdef _NB_AUTOLOG - #define THROW(type, ...) {auto x = CONSTRUCT_ERROR(type, ## __VA_ARGS__); nb::logger.error(x); throw x;} + #define THROW(args...) ERROR(args); throw args #else - #define THROW(type, ...) throw CONSTRUCT_ERROR(type, __VA_ARGS__) - #endif // _NB_AUTOLOG + #define THROW(args...) throw args + #endif // _NB_CODE_ERROR_LOCATIONS #endif // THROW #endif // _NB_LOGGER \ No newline at end of file diff --git a/engine/NBCore/StringUtils.hpp b/engine/NBCore/StringUtils.hpp index a8cab98..9b709e1 100644 --- a/engine/NBCore/StringUtils.hpp +++ b/engine/NBCore/StringUtils.hpp @@ -4,7 +4,7 @@ #include #include -#include +#include #include "TypeTraits.hpp" @@ -19,53 +19,17 @@ namespace nb { const std::wstring WNEWLINE = L"\n"; #endif // _NB_TARGET_LINUX -template -using StringConvertible = ValidConversion; +const std::string TABOVER = " "; -template -using WStringConvertible = ValidConversion; +// std::wstring str_to_wstr(std::string in); -template -constexpr bool StringConvertible_v = StringConvertible::value; - -template -constexpr bool WStringConvertible_v = WStringConvertible::value; - -template -using StringConvertible_to = typename StringConvertible::to; - -template -using WStringConvertible_to = typename WStringConvertible::to; - -template -using StringConvertible_from = typename StringConvertible::from; - -template -using WStringConvertible_from = typename WStringConvertible::from; - -template -std::enable_if_t, std::wstring> str_to_wstr(T in) { - std::string str(in); - std::wstring ret(str.begin(), str.end()); - return ret; -} - -template -std::enable_if_t, std::string> wstr_to_str(T in) { - std::wstring wstr(in); - std::size_t wstrlen = wstr.length(); - char* c_str= new char[wstrlen]; - std::wcstombs(c_str, wstr.c_str(), wstrlen); - std::string ret(c_str, wstrlen); - delete[] c_str; - return ret; -} +// std::string wstr_to_str(std::wstring in); template -void stream(Stream& s, Args&&... args); +void stream(const Stream& s, Args&&... args); template -void stream(Stream& s, Args&&... args) { +void stream(const Stream& s, Args&&... args) { (s << ... << args); } @@ -75,68 +39,41 @@ void term(Args&&... args) { stream(std::cout, args..., nb::NEWLINE); } template void wterm(Args&&... args) { stream(std::wcout, args..., nb::WNEWLINE); } -template -ValidConversion_to find_and_replace( - A original, - B find, - C replace +template +std::basic_string find_and_replace( + ExplicitType_t> original, + ExplicitType_t> find, + ExplicitType_t> replace ) { - const T& find_t = T(find); - const T& replace_t = T(replace); + using StringType = std::basic_string; - T ret(original); + StringType ret(original); - std::size_t find_len = find_t.length(); - std::size_t replace_len = replace_t.length(); + std::size_t find_len = find.length(); + std::size_t replace_len = replace.length(); std::size_t currpos = 0; while(true) { - currpos = ret.find(find_t, currpos); - if (currpos == T::npos) { + currpos = ret.find(find, currpos); + if (currpos == StringType::npos) { break; } ret = ret.erase(currpos, find_len); - ret = ret.insert(currpos, replace_t); + ret = ret.insert(currpos, replace); currpos += replace_len; } return ret; } -template -StringConvertible_to indent_strblock( - A block, - B prepend, - C topIndent -) { - return std::string(topIndent) + find_and_replace( - std::string(block), - nb::NEWLINE, - nb::NEWLINE + std::string(prepend) - ); -} +std::string indent_strblock( + std::string block, + std::string prepend, + std::string topIndent +); -template -StringConvertible_to indent_strblock( - A block, - B prepend -) { - return indent_strblock(block, prepend, prepend); -} - -/* template -T swap_endian(const T& val) { - T ret; - const int size = sizeof(T); - auto retLoc = static_cast(&ret); - auto valLoc = static_cast(&val); - - for (int i = 0; i < size; ++i) { - memcpy(retLoc+i, valLoc+(size-i-1), 1); - } - return ret; -} */ - - -// using ByteVector = std::vector; +std::string indent_strblock( + std::string block, + std::string prepend +); } // namespace nb #endif // _NB_CORE_TYPES \ No newline at end of file diff --git a/engine/NBCore/TypeTraits.hpp b/engine/NBCore/TypeTraits.hpp index f92df9a..fb990fe 100644 --- a/engine/NBCore/TypeTraits.hpp +++ b/engine/NBCore/TypeTraits.hpp @@ -69,6 +69,24 @@ using ValidConversion_to = typename ValidConversion::to; template using ValidConversion_from = typename ValidConversion::from; +template +struct ExplicitType { using type=T; }; + +template +using ExplicitType_t = typename ExplicitType::type; + +template +T* NULLPTR = static_cast(nullptr); + +template +struct RunAndOutput { + using type = T; + T value; + RunAndOutput(Func func, T val) : value(val) { + func(); + } +}; + template inline typename std::enable_if::type ForEach(std::tuple&, Func) {} diff --git a/engine/NBCore/src/Errors.cpp b/engine/NBCore/src/Errors.cpp index 43b6227..e5b22fa 100644 --- a/engine/NBCore/src/Errors.cpp +++ b/engine/NBCore/src/Errors.cpp @@ -3,12 +3,11 @@ namespace nb { -const std::string Error::type = "nb::Error"; +const std::string Error<>::type = "nb::Error"; const ErrorCodeMap Error::ErrorMessages = { - {Error::Codes::GENERAL, "General std::exception."}, - {Error::Codes::UNDEFINED, "Undefined / general error."}, - {Error::Codes::BADERRORCODE, "Unrecognized error code."} + {Error::Codes::STANDARD, "std::exception"}, + {Error::Codes::UNDEFINED, "Error"} }; } diff --git a/engine/NBCore/src/Logger.cpp b/engine/NBCore/src/Logger.cpp index b9353a4..795136d 100644 --- a/engine/NBCore/src/Logger.cpp +++ b/engine/NBCore/src/Logger.cpp @@ -10,11 +10,21 @@ nb::DefaultDebugLogger logger(std::cout); #endif // _NB_NO_LOGGER bool nb::DefaultDebugLogger::process(const LogEvent& msg) { + constexpr size_t level_field_width = 3; + constexpr size_t msg_prompt_length = level_field_width+6; for (const auto os : this->_ostream) { + *os << "["; + os->width(level_field_width); + (*os << std::to_string(msg.lvl)).width(level_field_width); + *os << "] :: "; + std::string fileloc=""; + if (!msg.file.empty()) { + fileloc += "(" + msg.file + ":" + std::to_string(msg.line) + ") - "; + } *os << indent_strblock( - msg.msg, - std::string(10, ' '), - "[ "+std::to_string(msg.lvl)+" ] : " + fileloc + msg.msg, + std::string(15 - msg_prompt_length, ' '), + "" ) << nb::NEWLINE; } return true; diff --git a/engine/NBCore/src/StringUtils.cpp b/engine/NBCore/src/StringUtils.cpp index 44f97f5..1946c3c 100644 --- a/engine/NBCore/src/StringUtils.cpp +++ b/engine/NBCore/src/StringUtils.cpp @@ -1 +1,29 @@ #include "StringUtils.hpp" + +/* std::string nb::wstr_to_str(std::wstring in) { + std::size_t wstrlen = in.length(); + char* c_str= new char[wstrlen]; + std::wcstombs(c_str, in.c_str(), wstrlen); + std::string ret(c_str, wstrlen); + delete[] c_str; + return ret; +} */ + +std::string nb::indent_strblock( + std::string block, + std::string prepend, + std::string topIndent +) { + return topIndent + nb::find_and_replace( + block, + nb::NEWLINE, + nb::NEWLINE + prepend + ); +} + +std::string nb::indent_strblock( + std::string block, + std::string prepend +) { + return nb::indent_strblock(block, prepend, prepend); +} diff --git a/engine/NBCore/tests/testErrors.cpp b/engine/NBCore/tests/testErrors.cpp index 1e919aa..0c7be49 100644 --- a/engine/NBCore/tests/testErrors.cpp +++ b/engine/NBCore/tests/testErrors.cpp @@ -35,5 +35,5 @@ const ErrorCodeMap TestError::ErrorMessages{ TEST(ErrorTest, Test) { auto err = TestError(0, TestError(1, TestError(2, TestError(3, TestError(2))))); - ASSERT_STREQ(err.what(), "Hey!\n Trace: How\n Trace: You\n Trace: Doin\n Trace: You\n"); + ASSERT_STREQ(err.what().c_str(), "Hey!\n Trace: How\n Trace: You\n Trace: Doin\n Trace: You"); } \ No newline at end of file diff --git a/engine/NBCore/tests/testLogger.cpp b/engine/NBCore/tests/testLogger.cpp index da6fb99..451a01f 100644 --- a/engine/NBCore/tests/testLogger.cpp +++ b/engine/NBCore/tests/testLogger.cpp @@ -3,14 +3,43 @@ #include "Errors.hpp" #include "Logger.hpp" +class TestError : public nb::Error { + using Base = Error; +public: + using Base::Base; + using Base::what; + using Base::code; + using Base::msg; + using Base::trace; + enum Codes : unsigned int { + A, B, C, D + }; + + static const std::string type; + static const nb::ErrorCodeMap ErrorMessages; +}; + +const std::string TestError::type="TestError"; +const nb::ErrorCodeMap TestError::ErrorMessages{ + {TestError::Codes::A, "Hey!"}, + {TestError::Codes::B, "How"}, + {TestError::Codes::C, "You"}, + {TestError::Codes::D, "Doin"} +}; int main() { nb::logger.log("Whoop!"); try { - THROW(nb::Error, "Hiii!"); - } catch (nb::Error e){ - nb::logger.log("Winner winner chicken dinner!"); + THROW(nb::Error(1)); + } catch (nb::Error<> e){ + nb::logger.log("nb::Error was thrown!"); + } + + try { + THROW(std::exception()); + } catch (std::exception e){ + nb::logger.log("std::exception was thrown!"); } return 0; diff --git a/engine/NBCore/tests/testUtils.cpp b/engine/NBCore/tests/testUtils.cpp index 24ca054..a726369 100644 --- a/engine/NBCore/tests/testUtils.cpp +++ b/engine/NBCore/tests/testUtils.cpp @@ -43,38 +43,38 @@ TEST(UtilsTest, TestFindAndReplace) { TEST(UtilsTest, TestFindAndReplaceWstr) { ASSERT_STREQ( - find_and_replace(L"Jeff", L"e", L"efe").c_str(), + find_and_replace(L"Jeff", L"e", L"efe").c_str(), L"Jefeff" ); - std::wstring tmp = find_and_replace(L"Naif", L"a", L"afa"); + std::wstring tmp = find_and_replace(L"Naif", L"a", L"afa"); ASSERT_STREQ( - find_and_replace(tmp, L"i", L"ifi").c_str(), + find_and_replace(tmp, L"i", L"ifi").c_str(), L"Nafaifif" ); - tmp = find_and_replace(L"aeiou", L"a", L"afa"); - tmp = find_and_replace(tmp, L"e", L"efe"); - tmp = find_and_replace(tmp, L"i", L"ifi"); - tmp = find_and_replace(tmp, L"o", L"ofo"); - tmp = find_and_replace(tmp, L"u", L"ufu"); + tmp = find_and_replace(L"aeiou", L"a", L"afa"); + tmp = find_and_replace(tmp, L"e", L"efe"); + tmp = find_and_replace(tmp, L"i", L"ifi"); + tmp = find_and_replace(tmp, L"o", L"ofo"); + tmp = find_and_replace(tmp, L"u", L"ufu"); ASSERT_STREQ( tmp.c_str(), L"afaefeifiofoufu" ); - tmp = find_and_replace(tmp, L"afa", L"a"); - tmp = find_and_replace(tmp, L"efe", L"e"); - tmp = find_and_replace(tmp, L"ifi", L"i"); - tmp = find_and_replace(tmp, L"ofo", L"o"); - tmp = find_and_replace(tmp, L"ufu", L"u"); + tmp = find_and_replace(tmp, L"afa", L"a"); + tmp = find_and_replace(tmp, L"efe", L"e"); + tmp = find_and_replace(tmp, L"ifi", L"i"); + tmp = find_and_replace(tmp, L"ofo", L"o"); + tmp = find_and_replace(tmp, L"ufu", L"u"); ASSERT_STREQ( tmp.c_str(), L"aeiou" ); } -TEST(UtilsTest, TestWstrToStr) { +/* TEST(UtilsTest, TestWstrToStr) { ASSERT_STREQ( nb::wstr_to_str(L"Hi!").c_str(), "Hi!" @@ -91,9 +91,9 @@ TEST(UtilsTest, TestWstrToStr) { nb::wstr_to_str(L"Naif\ttalks\r\ra\t\nlot").c_str(), "Naif\ttalks\r\ra\t\nlot" ); -} +} */ -TEST(UtilsTest, TestStrToWstr) { +/* TEST(UtilsTest, TestStrToWstr) { ASSERT_STREQ( nb::str_to_wstr("Hi!").c_str(), L"Hi!" @@ -110,7 +110,7 @@ TEST(UtilsTest, TestStrToWstr) { nb::str_to_wstr("Naif\ttalks\r\ra\t\nlot").c_str(), L"Naif\ttalks\r\ra\t\nlot" ); -} +} */ struct A { bool x(); }; struct B { bool y(); }; -- 2.43.0 From 13ef940b2de76ac6f6d7bd5d587f1a60d9003cf0 Mon Sep 17 00:00:00 2001 From: NaifBanana <30419422+NaifBanana@users.noreply.github.com> Date: Sat, 2 May 2026 03:37:06 -0500 Subject: [PATCH 09/11] Formatting tweaks --- engine/NBCore/src/Logger.cpp | 9 ++++----- engine/NBCore/tests/testLogger.cpp | 6 +++--- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/engine/NBCore/src/Logger.cpp b/engine/NBCore/src/Logger.cpp index 795136d..f2d0c8e 100644 --- a/engine/NBCore/src/Logger.cpp +++ b/engine/NBCore/src/Logger.cpp @@ -10,20 +10,19 @@ nb::DefaultDebugLogger logger(std::cout); #endif // _NB_NO_LOGGER bool nb::DefaultDebugLogger::process(const LogEvent& msg) { - constexpr size_t level_field_width = 3; - constexpr size_t msg_prompt_length = level_field_width+6; + constexpr size_t level_field_width = 5; + constexpr size_t msg_prompt_length = level_field_width+7; for (const auto os : this->_ostream) { *os << "["; os->width(level_field_width); - (*os << std::to_string(msg.lvl)).width(level_field_width); - *os << "] :: "; + *os << std::to_string(msg.lvl) << "] :: "; std::string fileloc=""; if (!msg.file.empty()) { fileloc += "(" + msg.file + ":" + std::to_string(msg.line) + ") - "; } *os << indent_strblock( fileloc + msg.msg, - std::string(15 - msg_prompt_length, ' '), + std::string(20 - msg_prompt_length, ' '), "" ) << nb::NEWLINE; } diff --git a/engine/NBCore/tests/testLogger.cpp b/engine/NBCore/tests/testLogger.cpp index 451a01f..27da8da 100644 --- a/engine/NBCore/tests/testLogger.cpp +++ b/engine/NBCore/tests/testLogger.cpp @@ -31,8 +31,8 @@ const nb::ErrorCodeMap TestError::ErrorMessages{ int main() { nb::logger.log("Whoop!"); try { - THROW(nb::Error(1)); - } catch (nb::Error<> e){ + THROW(TestError(0, TestError(1, TestError(2, TestError(3, TestError(2)))))); + } catch (TestError e){ nb::logger.log("nb::Error was thrown!"); } @@ -41,6 +41,6 @@ int main() { } catch (std::exception e){ nb::logger.log("std::exception was thrown!"); } - + ERROR("hello there!"); return 0; } \ No newline at end of file -- 2.43.0 From cff7164d27b9a855bd36a6fc351051ade2a916ca Mon Sep 17 00:00:00 2001 From: NaifBanana <30419422+NaifBanana@users.noreply.github.com> Date: Thu, 11 Jun 2026 04:23:29 -0500 Subject: [PATCH 10/11] Mild cleanup --- engine/NBCore/Errors.hpp | 38 +++++++++++- engine/NBCore/Logger.hpp | 106 +++----------------------------- engine/NBCore/Processes.hpp | 2 + engine/NBCore/StringUtils.hpp | 6 +- engine/NBCore/Utils.hpp | 78 +++++++++++++++++++---- engine/NBCore/src/Logger.cpp | 2 - engine/NBCore/src/Processes.cpp | 9 ++- engine/NBCore/src/Utils.cpp | 26 ++++++++ 8 files changed, 148 insertions(+), 119 deletions(-) diff --git a/engine/NBCore/Errors.hpp b/engine/NBCore/Errors.hpp index 2e38434..89cc13b 100644 --- a/engine/NBCore/Errors.hpp +++ b/engine/NBCore/Errors.hpp @@ -6,9 +6,11 @@ #include #include #include -#include "TypeTraits.hpp" #include + +#include "Logger.hpp" #include "StringUtils.hpp" +#include "TypeTraits.hpp" namespace nb { @@ -273,8 +275,38 @@ public: static const std::string type; static const ErrorCodeMap ErrorMessages; }; - - } // namespace nb +#ifdef _NB_AUTOLOG + #ifdef _NB_CODE_ERROR_LOCATIONS + #ifndef LOG + #define LOG(args...) nb::logger.log(args, __FILE__, __LINE__) + #endif // LOG + #ifndef WARN + #define WARN(args...) nb::logger.warn(args, __FILE__, __LINE__) + #endif // WARN + #ifndef ERROR + #define ERROR(args...) nb::logger.error(args, __FILE__, __LINE__) + #endif // ERROR + #else + #ifndef LOG + #define LOG(args...) nb::logger.log(args) + #endif // LOG + #ifndef WARN + #define WARN(args...) nb::logger.warn(args) + #endif // WARN + #ifndef ERROR + #define ERROR(args...) nb::logger.error(args) + #endif // ERROR + #endif // _NB_CODE_ERROR_LOCATIONS +#endif // _NB_AUTOLOG + +#ifndef THROW + #ifdef _NB_AUTOLOG + #define THROW(args...) ERROR(args); throw args + #else + #define THROW(args...) throw args + #endif // _NB_CODE_ERROR_LOCATIONS +#endif // THROW + #endif // _NB_ERROR \ No newline at end of file diff --git a/engine/NBCore/Logger.hpp b/engine/NBCore/Logger.hpp index e0f1f19..2d64198 100644 --- a/engine/NBCore/Logger.hpp +++ b/engine/NBCore/Logger.hpp @@ -9,13 +9,15 @@ #include #include "DataSink.hpp" -#include "Errors.hpp" #include "Processes.hpp" #include "ThreadSafeQueue.hpp" #include "TypeTraits.hpp" namespace nb { +template +class ErrorBase; + typedef std::chrono::time_point< std::chrono::system_clock, std::chrono::nanoseconds @@ -131,7 +133,10 @@ public: U val, std::string file="", unsigned int line=0 - ) { static_cast(this)->log(val, 0xFF, file, line); } + ) { + static_cast(this)->log(val, 0xFF, file, line); + static_cast(this)->flush(); + } protected: std::vector _ostream; @@ -167,103 +172,6 @@ extern DefaultDebugLogger logger; // Taking Charge of Adult ADHD by Russell Barkley -/* template -struct NB_DEFAULT_LOGGER_THROW; - -template<> -struct NB_DEFAULT_LOGGER_THROW { - template - NB_DEFAULT_LOGGER_THROW(T arg) { - #ifdef _NB_AUTOLOG - logger.error(arg); - #endif // _NB_AUTLOG - throw arg; - } -}; - -template -struct NB_DEFAULT_LOGGER_THROW { - template - NB_DEFAULT_LOGGER_THROW(Args&&... args) { - std::shared_ptr error_ptr; - #ifdef _NB_AUTOLOG - #ifdef _NB_CODE_ERROR_LOCATIONS - error_ptr = std::make_shared(args..., __LINE__, __FILE__); - #else - error_ptr = std::make_shared(args...); - #endif // _NB_CODE_ERROR_LOCATIONS - logger.error(*error_ptr); - #endif // _NB_AUTLOG - throw *error_ptr; - } -}; */ - -/* template -void NB_DEFAULT_LOGGER_THROW(Args&& ... args) { - std::shared_ptr error_ptr; - #ifdef _NB_AUTOLOG - #ifdef _NB_CODE_ERROR_LOCATIONS - error_ptr = std::make_shared(args..., __LINE__, __FILE__); - #else - error_ptr = std::make_shared(args...); - #endif // _NB_CODE_ERROR_LOCATIONS - logger.error(*error_ptr); - #endif // _NB_AUTLOG - throw *error_ptr; -} - -template -void NB_DEFAULT_LOGGER_THROW(const Arg& arg) { - #ifdef _NB_AUTOLOG - logger.error(arg); - #endif // _NB_AUTLOG - throw arg; -} */ - -template -void NB_DEFAULT_LOGGER_THROW(const T& err, std::string file="", unsigned int line = 0) { - #ifdef _NB_AUTOLOG - if (file.empty()) { - logger.error(err); - } else { - logger.error(err, file, line); - } - #endif // _NB_AUTLOG - throw err; -} - } // namespace nb -#ifdef _NB_AUTOLOG - #ifdef _NB_CODE_ERROR_LOCATIONS - #ifndef LOG - #define LOG(args...) nb::logger.log(args, __FILE__, __LINE__) - #endif // LOG - #ifndef WARN - #define WARN(args...) nb::logger.warn(args, __FILE__, __LINE__) - #endif // WARN - #ifndef ERROR - #define ERROR(args...) nb::logger.error(args, __FILE__, __LINE__) - #endif // ERROR - #else - #ifndef LOG - #define LOG(args...) nb::logger.log(args) - #endif // LOG - #ifndef WARN - #define WARN(args...) nb::logger.warn(args) - #endif // WARN - #ifndef ERROR - #define ERROR(args...) nb::logger.error(args) - #endif // ERROR - #endif // _NB_CODE_ERROR_LOCATIONS -#endif // _NB_AUTOLOG - -#ifndef THROW - #ifdef _NB_AUTOLOG - #define THROW(args...) ERROR(args); throw args - #else - #define THROW(args...) throw args - #endif // _NB_CODE_ERROR_LOCATIONS -#endif // THROW - #endif // _NB_LOGGER \ No newline at end of file diff --git a/engine/NBCore/Processes.hpp b/engine/NBCore/Processes.hpp index 87ee029..87c16ee 100644 --- a/engine/NBCore/Processes.hpp +++ b/engine/NBCore/Processes.hpp @@ -7,6 +7,8 @@ namespace nb { uint64_t GetPID(); +uint64_t getTID(); + } // namespace nb diff --git a/engine/NBCore/StringUtils.hpp b/engine/NBCore/StringUtils.hpp index 9b709e1..b8d9778 100644 --- a/engine/NBCore/StringUtils.hpp +++ b/engine/NBCore/StringUtils.hpp @@ -1,6 +1,6 @@ #pragma once -#ifndef _NB_CORE_TYPES -#define _NB_CORE_TYPES +#ifndef _NB_STRING_UTILS +#define _NB_STRING_UTILS #include #include @@ -76,4 +76,4 @@ std::string indent_strblock( ); } // namespace nb -#endif // _NB_CORE_TYPES \ No newline at end of file +#endif // _NB_STRING_UTILS \ No newline at end of file diff --git a/engine/NBCore/Utils.hpp b/engine/NBCore/Utils.hpp index a8d47a5..b7a477d 100644 --- a/engine/NBCore/Utils.hpp +++ b/engine/NBCore/Utils.hpp @@ -2,23 +2,79 @@ #ifndef _NB_CORE_TYPES #define _NB_CORE_TYPES +#include +#include + +#include "Errors.hpp" + namespace nb { -/* template -T swap_endian(const T& val) { - T ret; - const int size = sizeof(T); - auto retLoc = static_cast(&ret); - auto valLoc = static_cast(&val); +using ByteVector = std::vector; - for (int i = 0; i < size; ++i) { - memcpy(retLoc+i, valLoc+(size-i-1), 1); +class ObjectManagerError : public Error { + using Base = Error; + + public: + using Base::Base; + + enum Codes : unsigned int { + UNDEFINED, NO_MANAGER, MANAGER_MISMATCH, LOCK_OVERFLOW, BAD_THREAD + }; + + static const std::string type; + static const ErrorCodeMap ErrorMessages; +}; + +template +class ThreadsafeObjectLock; + +template +class ThreadsafeObject { + using Codes = ObjectManagerError::Codes; + + public: + ThreadsafeObject(T&& obj) + : _obj(std::make_shared(obj)) {} + + ThreadsafeObjectLock lock() { + return ThreadsafeObjectLock(this); } - return ret; -} */ + friend ThreadsafeObjectLock; -// using ByteVector = std::vector; + protected: + std::shared_ptr _obj; + mutable std::recursive_mutex _mutex; + +}; + +template +class ThreadsafeObjectLock { + public: + ThreadsafeObjectLock(const ThreadsafeObjectLock&) = delete; + ThreadsafeObjectLock operator=(const ThreadsafeObjectLock&) = delete; + ~ThreadsafeObjectLock() { + _manager->_mutex.unlock(); + } + + T* operator->() { + return _manager->_obj.get(); + } + + friend ThreadsafeObject; + + protected: + ThreadsafeObjectLock( + ThreadsafeObject* const manager_ + ) : _manager(manager_) { + if (!_manager) { + using Codes = ObjectManagerError::Codes; + THROW(ObjectManagerError(Codes::NO_MANAGER)); + } + _manager->_mutex.lock(); + } + ThreadsafeObject* const _manager; +}; } // namespace nb #endif // _NB_CORE_TYPES \ No newline at end of file diff --git a/engine/NBCore/src/Logger.cpp b/engine/NBCore/src/Logger.cpp index f2d0c8e..8af8796 100644 --- a/engine/NBCore/src/Logger.cpp +++ b/engine/NBCore/src/Logger.cpp @@ -33,8 +33,6 @@ static bool RUN_LOGGER(nb::DefaultDebugLogger& log) { return log.run(); } - - static const bool LOGGER_RUNNING = RUN_LOGGER(logger); } // namespace nb \ No newline at end of file diff --git a/engine/NBCore/src/Processes.cpp b/engine/NBCore/src/Processes.cpp index 744d96d..f0aec20 100644 --- a/engine/NBCore/src/Processes.cpp +++ b/engine/NBCore/src/Processes.cpp @@ -15,8 +15,15 @@ uint64_t GetPID() { return GetCurrentProcessId(); } #endif // _NB_TARGET_WINDOWS - #ifdef _NB_TARGET_LINUX #endif // _NB_TARGET_LINUX +#ifdef _NB_TARGET_WINDOWS +uint64_t GetTID() { + return GetCurrentThreadId(); +} +#endif // _NB_TARGET_WINDOWS +#ifdef _NB_TARGET_LINUX +#endif // _NB_TARGET_LINUX + } // namespace nb \ No newline at end of file diff --git a/engine/NBCore/src/Utils.cpp b/engine/NBCore/src/Utils.cpp index 8b13789..39fc680 100644 --- a/engine/NBCore/src/Utils.cpp +++ b/engine/NBCore/src/Utils.cpp @@ -1 +1,27 @@ +#include "Utils.hpp" +namespace nb { + +using ObjectManagerCodes = ObjectManagerError::Codes; +const std::string ObjectManagerError::type = "nb::ObjectManagerError"; +const ErrorCodeMap ObjectManagerError::ErrorMessages({ + {ObjectManagerCodes::UNDEFINED, "Error"}, + { + ObjectManagerCodes::NO_MANAGER, + "Attempting to create object lock without lock manager" + }, + { + ObjectManagerCodes::MANAGER_MISMATCH, + "Attempting to delete object lock from mismatched lock manager" + }, + { + ObjectManagerCodes::LOCK_OVERFLOW, + "Too many object locks allocated" + }, + { + ObjectManagerCodes::BAD_THREAD, + "Attempting operation from a bad thread" + } +}); + +}; // namespace nb -- 2.43.0 From e4b164f29a78555506efaa299f633ac295c740c3 Mon Sep 17 00:00:00 2001 From: NaifBanana <30419422+NaifBanana@users.noreply.github.com> Date: Fri, 26 Jun 2026 02:43:16 -0500 Subject: [PATCH 11/11] Error system simplification --- engine/NBCore/CMakeLists.txt | 3 +- engine/NBCore/DataSink.hpp | 6 +- engine/NBCore/Errors.hpp | 275 +------------------------------ engine/NBCore/ErrorsImpl.hpp | 175 ++++++++++++++++++++ engine/NBCore/Logger.hpp | 83 +++++----- engine/NBCore/Utils.hpp | 38 +++++ engine/NBCore/src/Errors.cpp | 13 -- engine/NBCore/src/ErrorsImpl.cpp | 16 ++ engine/NBCore/src/Logger.cpp | 2 +- 9 files changed, 279 insertions(+), 332 deletions(-) create mode 100644 engine/NBCore/ErrorsImpl.hpp delete mode 100644 engine/NBCore/src/Errors.cpp create mode 100644 engine/NBCore/src/ErrorsImpl.cpp diff --git a/engine/NBCore/CMakeLists.txt b/engine/NBCore/CMakeLists.txt index ee3a13b..76e9249 100644 --- a/engine/NBCore/CMakeLists.txt +++ b/engine/NBCore/CMakeLists.txt @@ -1,5 +1,5 @@ toAbsolutePath(NB_CORE_SOURCE - ./src/Errors.cpp + ./src/ErrorsImpl.cpp ./src/Logger.cpp ./src/Processes.cpp ./src/StringUtils.cpp @@ -10,6 +10,7 @@ toAbsolutePath(NB_CORE_INCLUDE ./ANSITerm.hpp ./DataSink.hpp ./Errors.hpp + ./ErrorsImpl.hpp ./Logger.hpp ./Processes.hpp ./StringUtils.hpp diff --git a/engine/NBCore/DataSink.hpp b/engine/NBCore/DataSink.hpp index d3c5d25..155c48a 100644 --- a/engine/NBCore/DataSink.hpp +++ b/engine/NBCore/DataSink.hpp @@ -72,11 +72,11 @@ template class MultithreadedDataProcessor : public BufferedDataProcessor, ProcessorType> { using Base = BufferedDataProcessor, ProcessorType>; -public: + public: ~MultithreadedDataProcessor() { type_ptr->stop(); } bool isRunning() const noexcept override { - return this->_running && (_runningThread!=nullptr); + return this->_running; } bool run() override { if (!type_ptr->isRunning()) { @@ -98,7 +98,7 @@ public: return !type_ptr->isRunning(); } -protected: + protected: using Base::Base; unsigned int count() const { diff --git a/engine/NBCore/Errors.hpp b/engine/NBCore/Errors.hpp index 89cc13b..8a6db60 100644 --- a/engine/NBCore/Errors.hpp +++ b/engine/NBCore/Errors.hpp @@ -2,281 +2,11 @@ #ifndef _NB_ERROR #define _NB_ERROR -#include -#include -#include -#include -#include - +#include "ErrorsImpl.hpp" #include "Logger.hpp" -#include "StringUtils.hpp" -#include "TypeTraits.hpp" namespace nb { -typedef std::unordered_map ErrorCodeMap; - -template -constexpr bool IsValidException_v = std::is_base_of_v; -template -using IsValidException = std::enable_if_t, bool>; - -template -class ErrorBase; - -template -class Error; - -template -constexpr bool IsValidNBError_v = std::is_base_of_v, T>; -template -using IsValidNBError = std::enable_if_t, bool>; - - -template<> -class ErrorBase { -public: - const unsigned int code; - const std::string msg; - const std::string type; - const std::shared_ptr trace; - const bool traceIsNBError; - - virtual std::string what() const noexcept = 0; - virtual std::shared_ptr make_shared() const noexcept = 0; - -protected: - template - ErrorBase(const ErrorBase& err) : ErrorBase(std::move(err)) {} - - template - ErrorBase(ErrorBase&& err) : ErrorBase( - err.code, - err.msg, - err.type, - (err.traceIsNBError) - ? static_cast(err.trace.get()) - : static_cast(err.trace.get()) - ) {} - - ErrorBase( - unsigned int code_, - std::string msg_, - std::string type_, - const std::exception* trace_ - ) noexcept : - code(code_), - msg(msg_), - type(type_), - trace{ trace_ ? - std::static_pointer_cast( - std::make_shared>(*trace_)) - : nullptr, - }, - traceIsNBError(false) - {} - - template, bool> = true> - ErrorBase( - unsigned int code_, - std::string msg_, - std::string type_, - const T* trace_ - ) noexcept : - code(code_), - msg(msg_), - type(type_), - trace{trace_ ? trace_->make_shared() : nullptr}, - traceIsNBError(true) - {} -}; - - -template -class ErrorBase : public ErrorBase { -private: - using Base = ErrorBase; - void inline check_asserts() { - static_assert(std::is_same, decltype(ErrorType::ErrorMessages)>::value, - "const std::unordered_map ErrorMessages must be " - "a class member." - ); - static_assert(std::is_enum_v, "enum Codes must be a class member."); - static_assert(std::is_same, unsigned int>::value, - "enum Codes must be of underlying type unsigned int." - ); - static_assert(std::is_same::value, - "const std::string type must be a class member." - ); - } - -public: - template - ErrorBase(const ErrorBase& cpy) : Base(cpy) { check_asserts(); } - - virtual std::shared_ptr make_shared() const noexcept override { - return std::static_pointer_cast( - std::make_shared(*this) - ); - } - - virtual std::string what() const noexcept override { - std::string ret = msg; - if (trace) { - std::string trace_msg; - if (traceIsNBError) { - trace_msg = std::static_pointer_cast(trace)->what(); - } else { - trace_msg = std::string(std::static_pointer_cast(trace)->what()); - } - ret += nb::NEWLINE + indent_strblock( - trace_msg, - nb::TABOVER, - nb::TABOVER+"Trace: " - ); - } - return ret; - } - - static const std::string type; - static const ErrorCodeMap ErrorMessages; - - using Base::code; - using Base::msg; - using Base::trace; - using Base::traceIsNBError; - - friend ErrorType; - friend Error; - -protected: - using Base::Base; - - template - ErrorBase( - unsigned int code_, - std::string msg_, - std::string type_, - const T* trace_ - ) : Base( - code_, - msg_, - type_, - trace_ - ) { check_asserts(); } -}; -template -const std::string ErrorBase::type = ErrorType::type; -template -const ErrorCodeMap ErrorBase::ErrorMessages = ErrorType::ErrorMessages; - - -template -class Error : public ErrorBase { - using Base = ErrorBase; -public: - template - Error( - unsigned int code_, - const T& trace_ - ) noexcept : Base( - code_, - ErrorType::ErrorMessages.at(code_), - ErrorType::type, - &trace_ - ) {} - - template - Error( - std::string msg_, - const ErrorBase& trace_ - ) noexcept : Base( - 0, - msg_, - ErrorType::type, - &trace_ - ) {} - - Error( - std::string msg_, - const std::exception& trace_ - ) noexcept : Base( - 0, - msg_, - ErrorType::type, - &trace_ - ) {} - - Error(unsigned int code_) noexcept : Base( - code_, - ErrorType::ErrorMessages.at(code_), - ErrorType::type, - NULLPTR - ) {} - - Error(std::string msg_) noexcept : Base( - 0, - msg_, - ErrorType::type, - NULLPTR - ) {} - - using Base::what; - using Base::code; - using Base::msg; - using Base::trace; - using Base::traceIsNBError; - using Base::type; - using Base::ErrorMessages; - -protected: - using Base::Base; - -}; - - -template<> -class Error : public ErrorBase> { - using Base = ErrorBase>; -public: - using Base::Base; - - Error(unsigned int code_=1) noexcept : Base( - code_, - ErrorMessages.at(code_), - type, - NULLPTR - ) {} - - Error(const std::exception& err) : Base( - Codes::STANDARD, - std::string(err.what()), - "std::exception", - nullptr - ) {} - - Error(std::string msg_) noexcept : Base( - Codes::UNDEFINED, - msg_, - type, - NULLPTR - ) {} - - enum Codes : unsigned int { - STANDARD, UNDEFINED - }; - - using Base::what; - - using Base::code; - using Base::msg; - using Base::trace; - using Base::traceIsNBError; - static const std::string type; - static const ErrorCodeMap ErrorMessages; -}; -} // namespace nb - #ifdef _NB_AUTOLOG #ifdef _NB_CODE_ERROR_LOCATIONS #ifndef LOG @@ -303,10 +33,11 @@ public: #ifndef THROW #ifdef _NB_AUTOLOG - #define THROW(args...) ERROR(args); throw args + #define THROW(args...) ERROR(args); nb::logger.stop(); throw args #else #define THROW(args...) throw args #endif // _NB_CODE_ERROR_LOCATIONS #endif // THROW +} // namespace nb #endif // _NB_ERROR \ No newline at end of file diff --git a/engine/NBCore/ErrorsImpl.hpp b/engine/NBCore/ErrorsImpl.hpp new file mode 100644 index 0000000..c5b8589 --- /dev/null +++ b/engine/NBCore/ErrorsImpl.hpp @@ -0,0 +1,175 @@ +#pragma once +#ifndef _NB_ERRORS_IMPL +#define _NB_ERRORS_IMPL + +#include +#include +#include +#include +#include + +#include "StringUtils.hpp" +#include "TypeTraits.hpp" + +namespace nb { + +typedef std::unordered_map ErrorCodeMap; + +template +class Error; + +class ErrorBase { + protected: + + public: + const unsigned int code; + const std::string msg; + const std::string type; + const std::shared_ptr trace; + + ErrorBase(const ErrorBase&) = default; + ErrorBase(const std::exception&) noexcept; + virtual std::string what() const noexcept { + std::string ret = msg; + if (trace) { + std::string trace_msg = msg; + ret += nb::NEWLINE + indent_strblock( + trace_msg, + nb::TABOVER, + nb::TABOVER+"Trace: " + ); + } + return ret; + } + + protected: + ErrorBase( + unsigned int code_, + std::string msg_, + std::string type_, + std::shared_ptr trace_ +) noexcept : + code(code_), + msg(msg_), + type(type_), + trace{trace_} +{} +}; + +template +class Error : public ErrorBase { + private: + void inline check_asserts() { + static_assert(std::is_same::value, + "const std::unordered_map ErrorMessages must be " + "a class member." + ); + static_assert(std::is_enum_v, "enum Codes must be a class member."); + static_assert(std::is_same, unsigned int>::value, + "enum Codes must be of underlying type unsigned int." + ); + static_assert(std::is_same::value, + "const std::string type must be a class member." + ); + } + + protected: + using ErrorBase::ErrorBase; + + public: + Error( + unsigned int code_, + const ErrorBase& trace_ + ) noexcept : ErrorBase( + code_, + ErrorType::ErrorMessages.at(code_), + ErrorType::type, + std::make_shared(trace_) + ) { check_asserts(); } + + Error( + std::string msg_, + const ErrorBase& trace_ + ) noexcept : ErrorBase( + 0, + msg_, + ErrorType::type, + std::make_shared(trace_) + ) { check_asserts(); } + + Error(unsigned int code_) noexcept : ErrorBase( + code_, + ErrorType::ErrorMessages.at(code_), + ErrorType::type, + nullptr + ) { check_asserts(); } + + Error(std::string msg_) noexcept : ErrorBase( + 0, + msg_, + ErrorType::type, + nullptr + ) { check_asserts(); } + + Error( + unsigned int code_, + const std::string& note_, + const ErrorBase& trace_ + ) noexcept : ErrorBase( + code_, + ErrorType::ErrorMessages.at(code_) + " (" + note_ + ")", + ErrorType::type, + std::make_shared(trace_) + ) { check_asserts(); } + + Error(unsigned int code_, const std::string& note_) noexcept : ErrorBase( + code_, + ErrorType::ErrorMessages.at(code_) + " (" + note_ + ")", + ErrorType::type, + nullptr + ) { check_asserts(); } + + using ErrorBase::what; + using ErrorBase::code; + using ErrorBase::msg; + using ErrorBase::trace; + using ErrorBase::type; +}; + + +template<> +class Error : public Error> { + using Base = Error>; + + public: + using Base::Base; + + Error(unsigned int code_=1) noexcept : Base(code_) {} + + Error(const std::exception& err) : Base( + Codes::STANDARD, + std::string(err.what()), + "std::exception", + nullptr + ) {} + + // fix + Error(std::string msg_) noexcept : Base( + Codes::UNDEFINED, + msg_ + ) {} + + enum Codes : unsigned int { + STANDARD, UNDEFINED + }; + + using Base::what; + using Base::code; + using Base::msg; + using Base::trace; + static const std::string type; + static const ErrorCodeMap ErrorMessages; +}; +} // namespace nb + +#endif // _NB_ERRORS_IMPL \ No newline at end of file diff --git a/engine/NBCore/Logger.hpp b/engine/NBCore/Logger.hpp index 2d64198..f4e79be 100644 --- a/engine/NBCore/Logger.hpp +++ b/engine/NBCore/Logger.hpp @@ -9,13 +9,13 @@ #include #include "DataSink.hpp" +#include "ErrorsImpl.hpp" #include "Processes.hpp" #include "ThreadSafeQueue.hpp" #include "TypeTraits.hpp" namespace nb { -template class ErrorBase; typedef std::chrono::time_point< @@ -32,7 +32,8 @@ class LoggerBase using StreamType = ST; using LoggerType = Logger; using Base = MultithreadedDataProcessor; -public: + + public: bool run() override { if (!static_cast(this)->isRunning()) { this->_running = true; @@ -45,7 +46,9 @@ public: } return static_cast(this)->isRunning(); } -protected: + using Base::flush; + + protected: LoggerBase() = default; StreamType _ostream; @@ -73,7 +76,33 @@ public: ~DebugLogger() { static_cast(this)->stop(); } + template void log( + U val, + std::string file="", + unsigned int line=0 + ) { static_cast(this)->write_message(val, 0x00, file, line); } + + template + void warn( + U val, + uint8_t lvl=0x01, + std::string file="", + unsigned int line=0 + ) { static_cast(this)->write_message(val, lvl, file, line); } + + void error( + const ErrorBase& val, + std::string file="", + unsigned int line=0 + ) { + static_cast(this)->write_message(val, 0xFF, file, line); + static_cast(this)->flush(); + } + + protected: + std::vector _ostream; + void write_message( std::string msg, uint8_t lvl=0x00, std::string file="", @@ -91,56 +120,24 @@ public: } template - void log( + void write_message( char const(&msg) [N], uint8_t lvl=0x00, std::string file="", unsigned int line=0 ) { - static_cast(this)->log(std::string(msg), lvl, file, line); + static_cast(this)->write_message(std::string(msg), lvl, file, line); } - template - void log( - const ErrorBase& err, - uint8_t lvl=0xFF, + void write_message( + const ErrorBase& err, + uint8_t lvl=0x00, std::string file="", unsigned int line=0 ) { - static_cast(this)->log(err.what(), lvl, file, line); + static_cast(this)->write_message(err.what(), lvl, file, line); } - template - std::enable_if_t, void> log( - const T& err, - uint8_t lvl=0xFF, - std::string file="", - unsigned int line=0 - ) { - static_cast(this)->log(std::string(err.what()), lvl, file, line); - } - - template - void warn( - U val, - uint8_t lvl=0x01, - std::string file="", - unsigned int line=0 - ) { static_cast(this)->log(val, lvl, file, line); } - - template - void error( - U val, - std::string file="", - unsigned int line=0 - ) { - static_cast(this)->log(val, 0xFF, file, line); - static_cast(this)->flush(); - } - -protected: - std::vector _ostream; - }; class DefaultDebugLogger : public DebugLogger { @@ -150,7 +147,7 @@ class DefaultDebugLogger : public DebugLogger { template struct LogRow; -public: + public: using Base::Base; ~DefaultDebugLogger() { stop(); } @@ -166,6 +163,8 @@ protected: bool process(const LogEvent& msg); }; +extern const bool LOGGER_RUNNING; + #ifndef _NB_NO_LOGGER extern DefaultDebugLogger logger; #endif // _NB_NO_LOGGER diff --git a/engine/NBCore/Utils.hpp b/engine/NBCore/Utils.hpp index b7a477d..76ae1ed 100644 --- a/engine/NBCore/Utils.hpp +++ b/engine/NBCore/Utils.hpp @@ -9,6 +9,12 @@ namespace nb { +template +using SharedVector = std::vector>; + +template +using RValueVector = std::vector; + using ByteVector = std::vector; class ObjectManagerError : public Error { @@ -25,6 +31,38 @@ class ObjectManagerError : public Error { static const ErrorCodeMap ErrorMessages; }; +template +ByteVector vectorToBytes(const std::vector& vec) { + unsigned int num_bytes = vec.size() * sizeof(T); + ByteVector ret(num_bytes); + memcpy(ret.data(), vec.data(), num_bytes); + return ret; +} + +template +ByteVector concatVectorBytes(const std::vector& vec1, const std::vector& vec2) { + ByteVector vec1_raw = vectorToBytes(vec1); + ByteVector vec2_raw = vectorToBytes(vec2); + unsigned int vec1_raw_size = vec1_raw.size(); + unsigned int vec2_raw_size = vec2_raw.size(); + ByteVector ret(vec1_raw_size + vec2_raw_size); + memcpy(ret.data(), vec1_raw.data(), vec1_raw_size); + memcpy(ret.data() + vec1_raw_size, vec2_raw.data(), vec2_raw_size); + return ret; +} + +template +std::vector bytesToVector(const ByteVector& vec) { + if (vec.size() % sizeof(T) != 0) { + THROW(std::runtime_error("Data size does not align to std::vector<" + std::string(typeid(T).name()) + ">.")); + } + unsigned int num_elmts = vec.size() / sizeof(T); + std::vector ret(num_elmts); + memcpy(ret.data(), vec.data(), vec.size()); + + return ret; +} + template class ThreadsafeObjectLock; diff --git a/engine/NBCore/src/Errors.cpp b/engine/NBCore/src/Errors.cpp deleted file mode 100644 index e5b22fa..0000000 --- a/engine/NBCore/src/Errors.cpp +++ /dev/null @@ -1,13 +0,0 @@ -#include "Errors.hpp" -#include "TypeTraits.hpp" - -namespace nb { - -const std::string Error<>::type = "nb::Error"; - -const ErrorCodeMap Error::ErrorMessages = { - {Error::Codes::STANDARD, "std::exception"}, - {Error::Codes::UNDEFINED, "Error"} -}; - -} diff --git a/engine/NBCore/src/ErrorsImpl.cpp b/engine/NBCore/src/ErrorsImpl.cpp new file mode 100644 index 0000000..a36b110 --- /dev/null +++ b/engine/NBCore/src/ErrorsImpl.cpp @@ -0,0 +1,16 @@ +#include "ErrorsImpl.hpp" + +namespace nb { + +const std::string Error<>::type = "nb::Error"; +const ErrorCodeMap Error<>::ErrorMessages = { + {Error::Codes::STANDARD, "std::exception"}, + {Error::Codes::UNDEFINED, "Error"} +}; + +//ErrorBase:: + +ErrorBase::ErrorBase(const std::exception& exception_) noexcept +: ErrorBase(Error(exception_)) {} + +} diff --git a/engine/NBCore/src/Logger.cpp b/engine/NBCore/src/Logger.cpp index 8af8796..70c8ff8 100644 --- a/engine/NBCore/src/Logger.cpp +++ b/engine/NBCore/src/Logger.cpp @@ -33,6 +33,6 @@ static bool RUN_LOGGER(nb::DefaultDebugLogger& log) { return log.run(); } -static const bool LOGGER_RUNNING = RUN_LOGGER(logger); +const bool LOGGER_RUNNING = RUN_LOGGER(logger); } // namespace nb \ No newline at end of file -- 2.43.0