diff options
author | Claudius Holeksa <mail@keldu.de> | 2023-04-18 18:34:29 +0200 |
---|---|---|
committer | Claudius Holeksa <mail@keldu.de> | 2023-04-18 18:34:29 +0200 |
commit | c4033b8c2028efeb9bac236e6b279bdcd8efec34 (patch) | |
tree | fa5a336d0870240604e9037c37e63414764be7e1 /forstio/core/error.h |
First commit to restructure the forstio repo
Diffstat (limited to 'forstio/core/error.h')
-rw-r--r-- | forstio/core/error.h | 149 |
1 files changed, 149 insertions, 0 deletions
diff --git a/forstio/core/error.h b/forstio/core/error.h new file mode 100644 index 0000000..d8a5ae2 --- /dev/null +++ b/forstio/core/error.h @@ -0,0 +1,149 @@ +#pragma once + +#include <string> +#include <string_view> +#include <variant> + +#include <cassert> + +#include "common.h" + +namespace saw { +/** + * Utility class for generating errors. Has a base distinction between + * critical and recoverable errors. Additional code ids can be provided to the + * constructor if additional distinctions are necessary. + */ +class error { +public: + enum class code : int16_t { + GenericCritical = -1, + GenericRecoverable = 1, + Disconnected = -99, + Exhausted = -98 + }; + +private: + std::variant<std::string_view, std::string> error_message_; + code error_; + +public: + error(); + error(const std::string_view &msg, error::code id); + error(std::string &&msg, error::code id); + error(error &&error); + + SAW_FORBID_COPY(error); + + error &operator=(error &&) = default; + + const std::string_view message() const; + bool failed() const; + + bool is_critical() const; + bool is_recoverable() const; + + error copy_error() const; + + code id() const; +}; + +error make_error(const std::string_view &generic, error::code c); + +template <typename Formatter> +error make_error(const Formatter &formatter, error::code code, + const std::string_view &generic) { + try { + std::string error_msg = formatter(); + return error{std::move(error_msg), code}; + } catch (std::bad_alloc &) { + return error{generic, code}; + } +} + +error critical_error(const std::string_view &generic, + error::code c = error::code::GenericCritical); + +template <typename Formatter> +error critical_error(const Formatter &formatter, + const std::string_view &generic, + error::code c = error::code::GenericCritical) { + return make_error(formatter, c, generic); +} + +error recoverable_error(const std::string_view &generic, + error::code c = error::code::GenericRecoverable); + +template <typename Formatter> +error recoverable_error(const Formatter &formatter, + const std::string_view &generic, + error::code c = error::code::GenericRecoverable) { + return make_error(formatter, c, generic); +} + +error no_error(); + +/** + * Exception alternative. Since I code without exceptions this class is + * essentially a kind of exception replacement. + */ +template <typename T> class error_or; + +class error_or_value { +public: + virtual ~error_or_value() = default; + + template <typename T> error_or<unfix_void<T>> &as() { + return static_cast<error_or<unfix_void<T>> &>(*this); + } + + template <typename T> const error_or<unfix_void<T>> &as() const { + return static_cast<const error_or<unfix_void<T>> &>(*this); + } +}; + +template <typename T> class error_or final : public error_or_value { +private: + std::variant<error, fix_void<T>> value_or_error_; + + static_assert(!std::is_same_v<T, void_t>, + "Don't use internal private types"); + +public: + error_or() = default; + error_or(const fix_void<T> &value) : value_or_error_{value} {} + + error_or(fix_void<T> &&value) : value_or_error_{std::move(value)} {} + + error_or(const error &error) : value_or_error_{error} {} + error_or(error &&error) : value_or_error_{std::move(error)} {} + + bool is_value() const { + return std::holds_alternative<fix_void<T>>(value_or_error_); + } + + bool is_error() const { + return std::holds_alternative<class error>(value_or_error_); + } + + class error &error() { + return std::get<class error>(value_or_error_); + } + + const class error &error() const { + return std::get<class error>(value_or_error_); + } + + fix_void<T> &value() { return std::get<fix_void<T>>(value_or_error_); } + + const fix_void<T> &value() const { + return std::get<fix_void<T>>(value_or_error_); + } +}; + +template <typename T> class error_or<error_or<T>> { +private: + error_or() = delete; +}; + +} // namespace saw |