summaryrefslogtreecommitdiff
path: root/forstio/core/error.h
blob: a8d299ba5e53fefa1d30b4cd941cf6f9a163a9fa (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
#pragma once

#include <string>
#include <string_view>
#include <variant>
#include <vector>

#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:
	using code = uint32_t;
private:
	std::variant<std::string_view, std::string> error_message_;
	code error_code_;

public:
	error();
	error(error::code id);
	error(error::code id, const std::string_view &msg);
	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;

	/**
	 * Replaces the copy constructor. We need this since we want to explicitly copy and not implicitly
	 */
	error copy_error() const;

	code get_id() const;
};

namespace impl {

class error_registry {
private:
	struct error_info {
		std::string_view description;
	};

	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(), 

		);

		if( find != find.end() ){
			
		}
	}
};

error_registry& get_error_registry();

template<typename T>
error::code get_template_id(){
	static error::code id = 0;

	if(id == 0){
		auto& reg = get_error_registry();
		id = reg.search_or_register_id(typename T::description);
	}

	return id;
}

template<typename T> error make_error(const std::string_view& generic){
	auto id = get_template_id<T>();

	return error{id};
}

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