Changed error system to CRTP, rough draft

This commit is contained in:
NaifBanana 2025-11-06 02:03:49 -06:00
parent a7428ef55f
commit 9024cce1b4
3 changed files with 85 additions and 91 deletions

View File

@ -5,48 +5,84 @@
#include <exception> #include <exception>
#include <string.h> #include <string.h>
#include <string> #include <string>
#include <type_traits>
#include <unordered_map> #include <unordered_map>
namespace nb { namespace nb {
typedef std::unordered_map<unsigned int, const char*> ErrorCodeMap; typedef std::unordered_map<unsigned int, const char*> ErrorCodeMap;
class Error : public std::exception { template<class ErrorType>
class ErrorBase : public std::exception {
public: public:
Error(const unsigned int code=0, std::exception* const trace=nullptr) noexcept; static std::string lookup(unsigned int);
Error(std::string, std::exception* const=nullptr) noexcept;
Error(const Error&) noexcept; virtual const char* what() const noexcept override final {
return static_cast<const ErrorType*>(this)->_msg.c_str();
};
unsigned int code() const noexcept {
return static_cast<const ErrorType*>(this)->_code;
};
unsigned int code() const noexcept;
virtual const char* type() const noexcept final;
virtual const char* what() const noexcept override final;
template<typename NBError>
friend const char* ErrorCodeLookup(unsigned int);
protected: protected:
static const ErrorCodeMap ErrorCodes; ErrorBase() = default;
Error( ErrorBase(
const unsigned int, const unsigned int code,
std::string, std::string msg,
std::exception* const, std::exception* const trace,
unsigned int line=0, unsigned int line=0,
std::string filename="" std::string filename=""
) noexcept; ) noexcept : _code{code} {
static_assert(std::is_same<const std::unordered_map<unsigned int, const char*>, decltype(ErrorType::ErrorMessages)>::value,
"const std::unordered_map<unsigned int, const char*> ErrorMessages must be "
"a class member."
);
static_assert(std::is_enum_v<typename ErrorType::ErrorCodes>, "enum ErrorCodes must be a class member.");
static_assert(std::is_same<std::underlying_type_t<typename ErrorType::ErrorCodes>, unsigned int>::value,
"enum ErrorCodes must be of underlying type unsigned int."
);
static_assert(std::is_same<const std::string, decltype(ErrorType::type)>::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; const unsigned int _code;
std::string _msg; std::string _msg;
}; };
template<typename NBError>
const char* ErrorCodeLookup(unsigned int code) { class Error : public ErrorBase<Error> {
for (auto kv : NBError::ErrorCodes) { public:
if (kv.first == code) { Error(unsigned int code, std::exception* const trace=nullptr)
return kv.second; : ErrorBase<Error>(code, ErrorBase<Error>::lookup(code), trace) {}
}
enum ErrorCodes : unsigned int {
UNDEFINED, BADERRORCODE
};
static const std::string type;
static const ErrorCodeMap ErrorMessages;
};
template<class ErrorType>
std::string ErrorBase<ErrorType>::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 } // namespace nb

View File

@ -3,56 +3,11 @@
namespace nb { namespace nb {
// class Error // class Error
const ErrorCodeMap Error::ErrorCodes = {
{0, "Undefined error."}, const std::string Error::type = "Error";
{666, "Unrecognized error code."} 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<Error>(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;
} */
} }

View File

@ -3,29 +3,32 @@
using namespace nb; using namespace nb;
class TestError : public nb::Error { class TestError : public ErrorBase<TestError> {
public: public:
TestError(unsigned int code, nb::Error* const trace=nullptr) : _type("nb::TestError"), Error(code, ErrorCodeLookup<TestError>(code), trace) {} TestError(unsigned int code, std::exception* const trace=nullptr)
: ErrorBase<TestError>(code, ErrorBase<TestError>::lookup(code), trace) {}
friend const char* ErrorCodeLookup<TestError>(unsigned int);
enum ErrorCodes : unsigned int {
protected: A, B, C, D
static const nb::ErrorCodeMap ErrorCodes; };
const char* _type; static const std::string type;
static const ErrorCodeMap ErrorMessages;
}; };
const ErrorCodeMap TestError::ErrorCodes{ const std::string TestError::type="TestError";
{0, "Hey!"}, const ErrorCodeMap TestError::ErrorMessages{
{1, "How"}, {TestError::ErrorCodes::A, "Hey!"},
{2, "You"}, {TestError::ErrorCodes::B, "How"},
{3, "Doin"} {TestError::ErrorCodes::C, "You"},
{TestError::ErrorCodes::D, "Doin"}
}; };
int main() { int main() {
TestError a(0); TestError d(TestError::ErrorCodes::D);
TestError b(1, &a); TestError c(TestError::ErrorCodes::C, &d);
TestError c(2, &b); TestError b(TestError::ErrorCodes::B, &c);
throw TestError(3, &c); TestError a(TestError::ErrorCodes::A, &b);
throw Error(Error::ErrorCodes::UNDEFINED, &a);
return 0; return 0;
} }