diff options
-rw-r--r-- | forstio/core/buffer.cpp | 10 | ||||
-rw-r--r-- | forstio/core/error.cpp | 90 | ||||
-rw-r--r-- | forstio/core/error.h | 112 |
3 files changed, 140 insertions, 72 deletions
diff --git a/forstio/core/buffer.cpp b/forstio/core/buffer.cpp index 2f1a6b5..ad471d7 100644 --- a/forstio/core/buffer.cpp +++ b/forstio/core/buffer.cpp @@ -13,7 +13,7 @@ error buffer::push(const uint8_t &value) { write() = value; write_advance(1); } else { - return recoverable_error("Buffer too small"); + return make_error<err::buffer_exhausted>(); } return no_error(); } @@ -39,7 +39,7 @@ error buffer::pop(uint8_t &value) { value = read(); read_advance(1); } else { - return recoverable_error("Buffer too small"); + return make_error<err::buffer_exhausted>(); } return no_error(); } @@ -55,7 +55,7 @@ error buffer::pop(uint8_t &buffer, size_t size) { buffer_ptr += segment; } } else { - return recoverable_error("Buffer too small"); + return make_error<err::buffer_exhausted>(); } return no_error(); } @@ -348,7 +348,7 @@ const uint8_t &ring_buffer::write(size_t i) const { error ring_buffer::write_require_length(size_t bytes) { size_t write_remain = write_composite_length(); if (bytes > write_remain) { - return recoverable_error("Buffer too small"); + return make_error<err::buffer_exhausted>(); } return no_error(); } @@ -426,7 +426,7 @@ const uint8_t &array_buffer::write(size_t i) const { error array_buffer::write_require_length(size_t bytes) { size_t write_remain = write_composite_length(); if (bytes > write_remain) { - return recoverable_error("Buffer too small"); + return make_error<err::buffer_exhausted>(); } return no_error(); } diff --git a/forstio/core/error.cpp b/forstio/core/error.cpp index 757e6a8..727ca95 100644 --- a/forstio/core/error.cpp +++ b/forstio/core/error.cpp @@ -1,17 +1,19 @@ #include "error.h" namespace saw { -error::error() : error_{static_cast<error::code>(0)} {} +error::error(error::code code_, bool is_critical__) + : error_code_{static_cast<error::code>(code_)}, is_critical_{is_critical__} {} -error::error(const std::string_view &msg, error::code code) - : error_message_{msg}, error_{static_cast<error::code>(code)} {} - -error::error(std::string &&msg, error::code code) - : error_message_{std::move(msg)}, error_{static_cast<error::code>(code)} {} +error::error(error::code code_, bool is_critical__, const std::string_view &msg) + : + error_code_{static_cast<error::code>(code_)} + , is_critical_{is_critical__}, error_message_{msg}{} error::error(error &&error) - : error_message_{std::move(error.error_message_)}, error_{std::move( - error.error_)} {} + : + error_code_{std::move(error.error_code_)} + , is_critical_{std::move(error.is_critical_)} + , error_message_{std::move(error.error_message_)}{} const std::string_view error::message() const { @@ -31,43 +33,89 @@ const std::string_view error::message() const { } bool error::failed() const { - return static_cast<std::underlying_type_t<error::code>>(error_) != 0; + return this->is_error<err::no_error>(); } bool error::is_critical() const { - return static_cast<std::underlying_type_t<error::code>>(error_) < 0; + return is_critical_; } bool error::is_recoverable() const { - return static_cast<std::underlying_type_t<error::code>>(error_) > 0; + return !is_critical_; } error error::copy_error() const { - error error; - error.error_ = error_; + auto copy_error_code = error_code_; + error error{copy_error_code, is_critical_}; + try { error.error_message_ = error_message_; } catch (const std::bad_alloc &) { error.error_message_ = std::string_view{"Error while copying Error string. Out of memory"}; } + return error; } -error::code error::id() const { return static_cast<error::code>(error_); } +error::code error::get_id() const { return error_code_; } + +namespace impl { +error_registry& get_error_registry() { + static own<error_registry> reg = nullptr; + if(!reg){ + reg = heap<error_registry>(); + } -error make_error(const std::string_view &generic, error::code code) { - return error{generic, code}; + assert(reg); + return *reg; +} } -error critical_error(const std::string_view &generic, error::code c) { - return make_error(generic, c); +error no_error(){ + return make_error<err::no_error>(); } -error recoverable_error(const std::string_view &generic, error::code c) { - return make_error(generic, c); +namespace impl { +error_or<error::code> error_registry::search_id(const std::string_view& desc)const{ + /** + * Search the index in the vector + */ + size_t i{}; + size_t info_max_size = std::min<std::size_t>(infos.size(), std::numeric_limits<error::code>::max()); + for(i = 0; i < info_max_size; ++i){ + if(infos.at(i).description == desc){ + break; + } + } + + if(i == info_max_size){ + return make_error<err::not_found>(); + } + + return static_cast<error::code>(i); } -error no_error() { return error{}; } +error_or<error::code> error_registry::search_or_register_id(const std::string_view& desc, bool is_critical){ + auto err_or_id = search_id(desc); + + if(err_or_id.is_value()){ + return err_or_id.get_value(); + } + + auto& err = err_or_id.get_error(); + + if(err.is_error<err::not_found>()){ + size_t new_index = infos.size(); + if(new_index == std::numeric_limits<error::code>::max()){ + return make_error<err::out_of_memory>("Error registry ids are exhausted"); + } + infos.emplace_back(error_info{desc, is_critical}); + return static_cast<error::code>(new_index); + } + + return std::move(err); +} +} } // namespace saw diff --git a/forstio/core/error.h b/forstio/core/error.h index a8d299b..304b375 100644 --- a/forstio/core/error.h +++ b/forstio/core/error.h @@ -1,5 +1,7 @@ #pragma once +#include <algorithm> +#include <limits> #include <string> #include <string_view> #include <variant> @@ -19,13 +21,13 @@ class error { public: using code = uint32_t; private: - std::variant<std::string_view, std::string> error_message_; code error_code_; + bool is_critical_; + std::variant<std::string_view, std::string> error_message_; public: - error(); - error(error::code id); - error(error::code id, const std::string_view &msg); + 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); @@ -44,82 +46,94 @@ public: error copy_error() const; code get_id() const; + + template<typename T> + bool is_error() const; }; +template<typename T> +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<error_info> infos; public: - error::code search_or_register_id(const std::string_view& desc){ - auto find = std::find_if(infos.begin(), infos.end(), - - ); + error_or<error::code> search_id(const std::string_view& desc) const; - if( find != find.end() ){ - - } - } + error_or<error::code> search_or_register_id(const std::string_view& desc, bool is_critical); }; error_registry& get_error_registry(); template<typename T> error::code get_template_id(){ - static error::code id = 0; + static error::code id = std::numeric_limits<error::code>::max(); - if(id == 0){ + if(id == std::numeric_limits<error::code>::max()){ auto& reg = get_error_registry(); - id = reg.search_or_register_id(typename T::description); + + auto err_or_id = reg.search_or_register_id(T::description, T::is_critical); + if(err_or_id.is_error()){ + return std::numeric_limits<error::code>::max(); + } + + id = err_or_id.get_value(); } return id; } +} template<typename T> error make_error(const std::string_view& generic){ - auto id = get_template_id<T>(); + error::code id = impl::get_template_id<T>(); - return error{id}; + return error{id, T::is_critical, generic}; } -error make_error(const std::string_view &generic, error::code c); +template<typename T> error make_error(){ + error::code id = impl::get_template_id<T>(); -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}; - } + return error{id, T::is_critical}; } -error critical_error(const std::string_view &generic, - error::code c = error::code::GenericCritical); +error make_error(error::code code, const std::string_view &generic); -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); +namespace err { +struct no_error { + static constexpr std::string_view description = "No error has occured"; + static constexpr bool is_critical = false; +}; + +struct buffer_exhausted { + static constexpr std::string_view description = "Buffer is too small"; + static constexpr bool is_critical = false; +}; + +struct not_found { + static constexpr std::string_view description = "Not found"; + static constexpr bool is_critical = false; +}; -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); +struct out_of_memory { + static constexpr std::string_view description = "Out of memory"; + static constexpr bool is_critical = true; +}; } +/** + * Shorthand for no error happened + */ error no_error(); /** @@ -165,17 +179,17 @@ public: return std::holds_alternative<class error>(value_or_error_); } - class error &error() { + class error &get_error() { return std::get<class error>(value_or_error_); } - const class error &error() const { + const class error &get_error() const { return std::get<class error>(value_or_error_); } - fix_void<T> &value() { return std::get<fix_void<T>>(value_or_error_); } + fix_void<T> &get_value() { return std::get<fix_void<T>>(value_or_error_); } - const fix_void<T> &value() const { + const fix_void<T> &get_value() const { return std::get<fix_void<T>>(value_or_error_); } }; @@ -185,4 +199,10 @@ private: error_or() = delete; }; +template<typename T> +bool error::is_error() const { + + return error_code_ == impl::get_template_id<T>(); +} + } // namespace saw |