summaryrefslogtreecommitdiff
path: root/forstio/core/error.h
diff options
context:
space:
mode:
authorClaudius Holeksa <mail@keldu.de>2023-04-18 18:34:29 +0200
committerClaudius Holeksa <mail@keldu.de>2023-04-18 18:34:29 +0200
commitc4033b8c2028efeb9bac236e6b279bdcd8efec34 (patch)
treefa5a336d0870240604e9037c37e63414764be7e1 /forstio/core/error.h
First commit to restructure the forstio repo
Diffstat (limited to 'forstio/core/error.h')
-rw-r--r--forstio/core/error.h149
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