Changed error system to CRTP, rough draft
This commit is contained in:
parent
a7428ef55f
commit
9024cce1b4
@ -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
|
||||||
|
|||||||
@ -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;
|
|
||||||
} */
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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;
|
||||||
}
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user