HikoGUI
A low latency retained GUI
Loading...
Searching...
No Matches
exceptions.hpp
1// Copyright 2019 Pokitec
2// All rights reserved.
3
4#pragma once
5
6#include "TTauri/Foundation/logger.hpp"
7#include "TTauri/Foundation/counters.hpp"
8#include "TTauri/Foundation/datum.hpp"
9#include "TTauri/Foundation/required.hpp"
10#include "TTauri/Foundation/string_tag.hpp"
11#include "TTauri/Foundation/tagged_map.hpp"
12#include "TTauri/Foundation/parse_location.hpp"
13#include <fmt/format.h>
14#include <fmt/ostream.h>
15#include <exception>
16#include <string>
17#include <atomic>
18#include <unordered_map>
19#include <optional>
20#include <ostream>
21#include <utility>
22
23namespace tt {
24
25struct url_tag {};
26struct line_tag {};
27struct column_tag {};
28struct vk_result_tag {};
29struct errno_tag {};
31struct key_tag {};
32
33class error {
34protected:
35 std::string _message;
36
37private:
38 virtual error &set(std::type_index info_tag, datum const &info_value) noexcept = 0;
39
40 virtual error &set(std::type_index info_tag, datum &&info_value) noexcept = 0;
41
42 virtual datum &get(std::type_index info_tag) noexcept = 0;
43
44 virtual datum const &get(std::type_index info_tag) const noexcept = 0;
45
46 virtual bool has(std::type_index info_tag) const noexcept = 0;
47
48
49public:
50 template<typename Fmt, typename... Args>
51 error(Fmt const &fmt, Args &&... args) noexcept {
52 if constexpr (sizeof...(args) == 0) {
53 _message = fmt;
54 } else {
55 _message = fmt::format(fmt, std::forward<Args>(args)...);
56 }
57 }
58
59 virtual std::type_index tag() const noexcept = 0;
60 virtual std::string error_info_string() const noexcept = 0;
61
64 std::string name() const noexcept {
65 return tag_name(tag());
66 }
67
68 std::string string() const noexcept {
69 return fmt::format("{}: {}. {}",
70 name(),
71 _message,
72 error_info_string()
73 );
74 }
75
76 [[nodiscard]] std::string message() const noexcept {
77 return _message;
78 }
79
80 error &caused_by(error const &other) noexcept {
81 _message = fmt::format("{}\nCaused by: {}", _message, other.string());
82 return *this;
83 }
84
89 template<typename InfoTag, typename InfoValueType>
90 error &set(InfoValueType &&info_value) noexcept {
91 return set(std::type_index(typeid(InfoTag)), datum{std::forward<InfoValueType>(info_value)});
92 }
93
94 error &set_location(parse_location const &location) noexcept {
95 if (location.has_file()) {
96 set<url_tag>(location.file());
97 }
98 set<line_tag>(location.line());
99 set<column_tag>(location.column());
100 return *this;
101 }
102
106 error &merge_location(parse_location statement_location) noexcept {
107 ttlet line = static_cast<int>(get<line_tag>());
108 ttlet column = static_cast<int>(get<column_tag>());
109
110 auto expression_location = parse_location{line, column};
111 if (has<url_tag>()) {
112 ttlet url = static_cast<URL>(get<url_tag>());
113 expression_location.set_file(std::move(url));
114 }
115
116 statement_location += expression_location;
117
118 if (statement_location.has_file()) {
119 set<url_tag>(statement_location.file());
120 }
121 set<line_tag>(statement_location.line());
122 set<column_tag>(statement_location.column());
123 return *this;
124 }
125
126
127 template<typename InfoTag>
128 datum &get() noexcept {
129 return get(std::type_index(typeid(InfoTag)));
130 }
131
132 template<typename InfoTag>
133 datum const &get() const noexcept {
134 return get(std::type_index(typeid(InfoTag)));
135 }
136
137 template<typename InfoTag>
138 bool has() const noexcept {
139 return has(std::type_index(typeid(InfoTag)));
140 }
141
142 friend std::string to_string(error const &rhs) {
143 return rhs.string();
144 }
145
146 friend std::ostream &operator<<(std::ostream &os, error const &rhs) {
147 return os << to_string(rhs);
148 }
149
150};
151
152
153template<typename Tag, typename... InfoTags>
154class sub_error final : public error {
155 tagged_map<datum,InfoTags...> error_info = {};
156
157 error &set(std::type_index info_tag, datum const &info_value) noexcept override {
158 if (error_info.has(info_tag) == 1) {
159 error_info.get(info_tag) = info_value;
160 } else {
161 LOG_WARNING("Unknown error_info '{}' on error '{}'", info_tag.name(), std::type_index(typeid(Tag)).name());
162 }
163 return *this;
164 }
165
166 error &set(std::type_index info_tag, datum &&info_value) noexcept override {
167 if (error_info.has(info_tag) == 1) {
168 error_info.get(info_tag) = std::move(info_value);
169 } else {
170 LOG_WARNING("Unknown error_info '{}' on error '{}'", info_tag.name(), std::type_index(typeid(Tag)).name());
171 }
172 return *this;
173 }
174
175 datum &get(std::type_index info_tag) noexcept override {
176 tt_assert(error_info.has(info_tag) == 1);
177 return error_info.get(info_tag);
178 }
179
180 datum const &get(std::type_index info_tag) const noexcept override {
181 tt_assert(error_info.has(info_tag) == 1);
182 return error_info.get(info_tag);
183 }
184
185 bool has(std::type_index info_tag) const noexcept override {
186 if (error_info.has(info_tag) == 0) {
187 return false;
188 } else {
189 return !error_info.get(info_tag).is_undefined();
190 }
191 }
192
193
194public:
195 using TAG = Tag;
196
197 std::type_index tag() const noexcept override { return std::type_index(typeid(Tag)); }
198
199 template<typename Fmt, typename... Args>
200 sub_error(Fmt const &fmt, Args &&... args) noexcept :
201 error(fmt, std::forward<Args>(args)...) {}
202
203 sub_error &caused_by(error const &other) noexcept {
204 _message = fmt::format("{}\nCaused by: {}", _message, other.string());
205 return *this;
206 }
207
212 template<typename InfoTag, typename InfoValueType>
213 sub_error &set(InfoValueType &&info_value) noexcept {
214 static_assert(has_tag<InfoTag,InfoTags...>(), "Unknown tag of error info value.");
215 error_info.template get<InfoTag>() = std::forward<InfoValueType>(info_value);
216 return *this;
217 }
218
219 sub_error &set_location(parse_location const &location) noexcept {
220 if (location.has_file()) {
221 set<url_tag>(location.file());
222 }
223 set<line_tag>(location.line());
224 set<column_tag>(location.column());
225 return *this;
226 }
227
228 template<typename InfoTag>
229 datum &get() noexcept {
230 static_assert(has_tag<InfoTag,InfoTags...>(), "Unknown tag of error info value.");
231 return error_info.template get<InfoTag>();
232 }
233
234 template<typename InfoTag>
235 datum const &get() const noexcept {
236 static_assert(has_tag<InfoTag,InfoTags...>(), "Unknown tag of error info value.");
237 return error_info.template get<InfoTag>();
238 }
239
240 template<typename InfoTag>
241 bool has() const noexcept {
242 static_assert(has_tag<InfoTag,InfoTags...>(), "Unknown tag of error info value.");
243 return !((error_info.template get<InfoTag>()).is_undefined());
244 }
245
246 sub_error &log(char const *source_file, int source_line) {
247 logger.log<log_level::Exception>(cpu_counter_clock::now(), "{}", *this, source_code_ptr(source_file, source_line));
248 increment_counter<Tag>();
249 return *this;
250 }
251
252 std::string error_info_string() const noexcept override {
253 std::string r;
254
255 for (size_t i = 0; i < error_info.size(); i++) {
256 if (i > 0) {
257 r += ", ";
258 };
259
260 r += fmt::format("{}={}",
261 tag_name(error_info.get_tag(i)),
262 error_info[i].repr()
263 );
264 }
265 return r;
266 }
267};
268
269
281
287
290struct io_error_tag {};
300
301
302#define TTAURI_THROW(x) throw std::move((x).log(__FILE__, __LINE__));
303
304#define parse_assert(x) if (!(x)) { TTAURI_THROW(parse_error("{}", #x )); }
305#define parse_assert2(x, ...) if (!(x)) { TTAURI_THROW(parse_error(__VA_ARGS__)); }
306
307#define hresult_assert_or_throw(x) ([](HRESULT result) {\
308 if (tt_unlikely(FAILED(result))) {\
309 TTAURI_THROW(io_error("Call to '{}' failed with {:08x}", #x, result));\
310 }\
311 return result;\
312 }(x))
313
314
315}
Definition exceptions.hpp:25
Definition exceptions.hpp:26
Definition exceptions.hpp:27
Definition exceptions.hpp:28
Definition exceptions.hpp:29
Definition exceptions.hpp:30
Definition exceptions.hpp:31
Definition exceptions.hpp:33
error & merge_location(parse_location statement_location) noexcept
Definition exceptions.hpp:106
error & set(InfoValueType &&info_value) noexcept
Definition exceptions.hpp:90
std::string name() const noexcept
Definition exceptions.hpp:64
Definition exceptions.hpp:154
sub_error & set(InfoValueType &&info_value) noexcept
Definition exceptions.hpp:213
Definition exceptions.hpp:279
Error to throw when an operation can not be executed due to the type of its operants.
Definition exceptions.hpp:285
Definition exceptions.hpp:288
Definition exceptions.hpp:290
Definition exceptions.hpp:292
Definition exceptions.hpp:294
Definition exceptions.hpp:296
Definition exceptions.hpp:298
Definition parse_location.hpp:15
Definition tagged_map.hpp:14
Definition URL.hpp:45
T move(T... args)
T name(T... args)