From a14896f9ed209dd3f9597722e5a5697bd7dbf531 Mon Sep 17 00:00:00 2001 From: "Claudius \"keldu\" Holeksa" Date: Mon, 4 Dec 2023 12:18:14 +0100 Subject: meta: Renamed folder containing source --- modules/core/error.h | 248 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 248 insertions(+) create mode 100644 modules/core/error.h (limited to 'modules/core/error.h') diff --git a/modules/core/error.h b/modules/core/error.h new file mode 100644 index 0000000..e816734 --- /dev/null +++ b/modules/core/error.h @@ -0,0 +1,248 @@ +#pragma once + +#include +#include +#include +#include +#include +#include + +#include + +#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: + using code = uint32_t; +private: + code error_code_; + bool is_critical_; + std::variant error_message_; + +public: + error(error::code id, bool is_critical); + error(error::code id, bool is_critical, const std::string_view &msg); + error(error &&error); + + SAW_FORBID_COPY(error); + + error &operator=(error &&) = default; + + const std::string_view get_message() const; + + const std::string_view get_category() const; + + bool failed() const; + + bool is_critical() const; + bool is_recoverable() const; + + /** + * Replaces the copy constructor. We need this since we want to explicitly copy and not implicitly + */ + error copy_error() const; + + code get_id() const; + + template + bool is_type() const; +}; + +template +class error_or; + +namespace impl { + +class error_registry { +private: + struct error_info { + error_info() = delete; + error_info(const std::string_view& d_, bool critical_):description{d_}, is_critical{critical_}{} + + std::string_view description; + bool is_critical; + }; + + std::vector infos_; +public: + error_registry(); + + SAW_FORBID_COPY(error_registry); + SAW_FORBID_MOVE(error_registry); + + error_or search_category(const error::code& id) const; + + error_or search_id(const std::string_view& desc) const; + + error_or search_or_register_id(const std::string_view& desc, bool is_critical); +}; + +error_registry& get_error_registry(); + +template +error::code get_template_id(){ + static error::code id = std::numeric_limits::max(); + + if(id == std::numeric_limits::max()){ + auto& reg = get_error_registry(); + + auto err_or_id = reg.search_or_register_id(T::description, T::is_critical); + if(err_or_id.is_error()){ + return std::numeric_limits::max(); + } + + id = err_or_id.get_value(); + } + + return id; +} +} + +template error make_error(const std::string_view& generic){ + error::code id = impl::get_template_id(); + + return error{id, T::is_critical, generic}; +} + +template error make_error(){ + error::code id = impl::get_template_id(); + + return error{id, T::is_critical}; +} + +error make_error(error::code code, const std::string_view &generic); + + +namespace err { +struct no_error { + static constexpr std::string_view description = "No error has occured"; + static constexpr bool is_critical = false; +}; + +struct recoverable { + static constexpr std::string_view description = "Generic recoverable error"; + static constexpr bool is_critical = false; +}; + +struct critical { + static constexpr std::string_view description = "Generic critical error"; + static constexpr bool is_critical = true; +}; + +struct buffer_exhausted { + static constexpr std::string_view description = "Buffer Exhausted"; + static constexpr bool is_critical = false; +}; + +struct not_found { + static constexpr std::string_view description = "Not found"; + static constexpr bool is_critical = false; +}; + +struct out_of_memory { + static constexpr std::string_view description = "Out of memory"; + static constexpr bool is_critical = true; +}; + +struct invalid_state { + static constexpr std::string_view description = "Invalid state"; + static constexpr bool is_critical = true; +}; + +struct not_supported { + static constexpr std::string_view description = "Not supported"; + static constexpr bool is_critical = false; +}; + +struct not_implemented { + static constexpr std::string_view description = "Not implemented"; + static constexpr bool is_critical = true; +}; + +struct already_exists { + static constexpr std::string_view description = "Already exists"; + static constexpr bool is_critical = false; +}; +} + +/** + * Shorthand for no error happened + */ +error no_error(); + +/** + * Exception alternative. Since I code without exceptions this class is + * essentially a kind of exception replacement. + */ +template class error_or; + +class error_or_value { +public: + virtual ~error_or_value() = default; + + template error_or> &as() { + return static_cast> &>(*this); + } + + template const error_or> &as() const { + return static_cast> &>(*this); + } +}; + +template class error_or final : public error_or_value { +private: + std::variant> value_or_error_; + + static_assert(!std::is_same_v, + "Don't use internal private types"); + +public: + error_or():value_or_error_{fix_void{}}{} + error_or(const fix_void &value) : value_or_error_{value} {} + + error_or(fix_void &&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>(value_or_error_); + } + + bool is_error() const { + return std::holds_alternative(value_or_error_); + } + + class error &get_error() { + return std::get(value_or_error_); + } + + const class error &get_error() const { + return std::get(value_or_error_); + } + + fix_void &get_value() { return std::get>(value_or_error_); } + + const fix_void &get_value() const { + return std::get>(value_or_error_); + } +}; + +template class error_or> { +private: + error_or() = delete; +}; + +template +bool error::is_type() const { + + return error_code_ == impl::get_template_id(); +} + +} // namespace saw -- cgit v1.2.3