diff --git a/include/Errors.hpp b/include/Errors.hpp index a85a4ac..2aa9abb 100644 --- a/include/Errors.hpp +++ b/include/Errors.hpp @@ -5,48 +5,84 @@ #include #include #include +#include #include namespace nb { typedef std::unordered_map ErrorCodeMap; -class Error : public std::exception { +template +class ErrorBase : public std::exception { public: - Error(const unsigned int code=0, std::exception* const trace=nullptr) noexcept; - Error(std::string, std::exception* const=nullptr) noexcept; - Error(const Error&) noexcept; + static std::string lookup(unsigned int); + + virtual const char* what() const noexcept override final { + return static_cast(this)->_msg.c_str(); + }; + unsigned int code() const noexcept { + return static_cast(this)->_code; + }; - unsigned int code() const noexcept; - virtual const char* type() const noexcept final; - virtual const char* what() const noexcept override final; - - template - friend const char* ErrorCodeLookup(unsigned int); protected: - static const ErrorCodeMap ErrorCodes; - Error( - const unsigned int, - std::string, - std::exception* const, + ErrorBase() = default; + ErrorBase( + const unsigned int code, + std::string msg, + std::exception* const trace, unsigned int line=0, std::string filename="" - ) noexcept; + ) noexcept : _code{code} { + 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_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\t" + msg; + if (trace) { + _msg += "\nTraceback - " + std::string(trace->what()); + } + } - const char* _type; const unsigned int _code; std::string _msg; }; -template -const char* ErrorCodeLookup(unsigned int code) { - for (auto kv : NBError::ErrorCodes) { - if (kv.first == code) { - return kv.second; - } + +class Error : public ErrorBase { +public: + Error(unsigned int code, std::exception* const trace=nullptr) + : ErrorBase(code, ErrorBase::lookup(code), trace) {} + + enum ErrorCodes : unsigned int { + UNDEFINED, BADERRORCODE + }; + 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(666); + throw Error(Error::ErrorCodes::BADERRORCODE); } } // namespace nb diff --git a/src/NBCoreUtils/Errors.cpp b/src/NBCoreUtils/Errors.cpp index 6b00e62..88c5124 100644 --- a/src/NBCoreUtils/Errors.cpp +++ b/src/NBCoreUtils/Errors.cpp @@ -3,56 +3,11 @@ namespace nb { // class Error -const ErrorCodeMap Error::ErrorCodes = { - {0, "Undefined error."}, - {666, "Unrecognized error code."} + +const std::string Error::type = "Error"; +const ErrorCodeMap Error::ErrorMessages = ErrorCodeMap{ + {ErrorCodes::UNDEFINED, "Undefined / general error."}, + {ErrorCodes::BADERRORCODE, "Unrecognized error code."} }; -Error::Error( - const unsigned int code, - std::string msg, - std::exception* const trace, - unsigned int line, - std::string filename -) noexcept : _code{code} { - _msg = std::string(type()); - _msg += ":" + std::to_string(code); - if (line && filename.size()) { - _msg += " in \'" + filename + "\':" + std::to_string(line); - } - _msg += "\n\t" + msg; - if (trace) { - _msg += "\nTraceback - " + std::string(trace->what()); - } -} - -Error::Error(const unsigned int code, std::exception* const trace) noexcept -: Error(code, ErrorCodeLookup(code), trace) {} - -Error::Error(std::string msg, std::exception* const trace) noexcept -: Error(0, msg, trace) {} - -Error::Error(const Error& cp) noexcept -: _type{cp._type}, _code{cp._code}, _msg{cp._msg} {} - -unsigned int Error::code() const noexcept { return _code; } - -const char* Error::type() const noexcept { return this->_type; } - -const char* Error::what() const noexcept { return _msg.c_str(); } - -/* constexpr const char* Error::lookup(unsigned int code) noexcept { - char* ret = new char[512]; - switch(code) { - case 0: - strcpy(ret, "General "); - strcat(ret, this->type()); - break; - default: - strcpy(ret, this->lookup(code)); - break; - } - return ret; -} */ - } diff --git a/tests/ErrorTest/main.cpp b/tests/ErrorTest/main.cpp index 699a8ac..c382f0e 100644 --- a/tests/ErrorTest/main.cpp +++ b/tests/ErrorTest/main.cpp @@ -3,29 +3,32 @@ using namespace nb; -class TestError : public nb::Error { +class TestError : public ErrorBase { public: - TestError(unsigned int code, nb::Error* const trace=nullptr) : _type("nb::TestError"), Error(code, ErrorCodeLookup(code), trace) {} - - friend const char* ErrorCodeLookup(unsigned int); - -protected: - static const nb::ErrorCodeMap ErrorCodes; - const char* _type; + TestError(unsigned int code, std::exception* const trace=nullptr) + : ErrorBase(code, ErrorBase::lookup(code), trace) {} + + enum ErrorCodes : unsigned int { + A, B, C, D + }; + static const std::string type; + static const ErrorCodeMap ErrorMessages; }; -const ErrorCodeMap TestError::ErrorCodes{ - {0, "Hey!"}, - {1, "How"}, - {2, "You"}, - {3, "Doin"} +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"} }; int main() { - TestError a(0); - TestError b(1, &a); - TestError c(2, &b); - throw TestError(3, &c); + TestError d(TestError::ErrorCodes::D); + TestError c(TestError::ErrorCodes::C, &d); + TestError b(TestError::ErrorCodes::B, &c); + TestError a(TestError::ErrorCodes::A, &b); + throw Error(Error::ErrorCodes::UNDEFINED, &a); return 0; } \ No newline at end of file