libGimbal 0.1.0
C17-Based Extended Standard Library and Cross-Language Runtime Framework
Loading...
Searching...
No Matches
gimbal_exception.hpp
1#ifndef GIMBAL_EXCEPTION_HPP
2#define GIMBAL_EXCEPTION_HPP
3
4#include <exception>
5#include <concepts>
6#include "../core/gimbal_call_stack.hpp"
7#include "../core/gimbal_api_generators.hpp"
8#include "../types/gimbal_result.hpp"
9#include "../core/gimbal_api_frame.h"
10
11namespace gbl {
12
13class Exception: public CallRecord {
14public:
15
16
17 using CallRecord::CallRecord;
18 Exception(const CallRecord& record) noexcept:
19 CallRecord(record) {}
20 Exception(CallRecord&& record) noexcept:
21 CallRecord(std::move(record)) {}
22
23 virtual const char* what(void) const noexcept {
24 return getMessage();
25 }
26
27 virtual const std::exception& asStdException(void) const = 0;
28 virtual std::exception& asStdException(void) = 0;
29
30 static const CallRecord& throwException(const CallRecord& record);
31
32 static const CallRecord& checkThrow(const CallRecord& record) {
33 if(record.getResult().isError()) {
34 GBL_API_CLEAR_LAST_RECORD();
35 return throwException(record);
36 }
37 return record;
38 }
39
40 static const CallRecord& checkThrow(std::invocable auto fn) {
41 const GblCallRecord* pRecord = nullptr;
42 GblThread_callRecordSet(NULL, NULL);
43 fn();
44 pRecord = GblThread_callRecord(NULL);
45 return Exception::checkThrow(*pRecord);
46 }
47
48
49 static CallRecord tryCatchRecord(std::invocable auto fn, SourceLocation loc=SourceLocation(SRC_FILE, nullptr, SRC_LN, SRC_COL)) noexcept;
50
51 class TryBlock {
52 private:
53 CallRecord record_;
54 public:
55
56 TryBlock(SourceLocation src=SourceLocation(SRC_FILE, "TryBlock::TryBlock()", SRC_LN, SRC_COL)):
57 record_(Result::Success, "Success", nullptr, src) {}
58
59 TryBlock& operator=(std::invocable auto fn) {
60 record_ = Exception::tryCatchRecord(std::forward<decltype(fn)>(fn), std::move(getRecord().getSource()));
61 return *this;
62 }
63
64 const CallRecord& getRecord(void) const { return record_; }
65 Result getResult(void) const { return getRecord().getResult(); }
66 const SourceLocation& getSource(void) const {return getRecord().getSource(); }
67 const char* getMessage(void) const { return getRecord().getMessage(); }
68
69 operator bool() const { return getRecord().getResult().isSuccess(); }
70 };
71};
72
73
74template<typename StdType>
75class StdException: public Exception, public StdType {
76public:
77
78 template<typename V>
80 !std::is_constructible_v<StdType, const char*>)
81 StdException(V&& v) noexcept:
82 Exception(std::move(v)) {}
83
84 template<typename V1, typename V2>
86 StdException(V1&& v1, V2&& v2) noexcept:
88 StdType(std::forward<V2>(v2)) {}
89
90 template<typename V>
92 StdException(V&& v) noexcept:
95
96 virtual ~StdException(void) override = default;
97
98 virtual const char* what(void) const noexcept override {
99 return Exception::what();
100 }
101
102 virtual const std::exception& asStdException(void) const override {
103 return *this;
104 }
105
106 virtual std::exception& asStdException(void) override {
107 return *this;
108 }
109};
110
111
112inline CallRecord Exception::tryCatchRecord(std::invocable auto fn, SourceLocation loc) noexcept {
113 try {
114 fn();
115 } catch(const Exception& gblExcept) {
116 return gblExcept;
117 } catch(const std::underflow_error& ex) {
118 return { Result::ErrorUnderflow, ex.what() };
119 } catch(const std::overflow_error& ex) {
120 return { Result::ErrorOverflow, ex.what() };
121 } catch(const std::out_of_range& ex) {
122 return { Result::ErrorOutOfRange, ex.what() };
123 } catch(const std::invalid_argument& ex) {
124 return { Result::ErrorInvalidArg, ex.what() };
125 } catch(const std::bad_alloc& ex) {
126 return { Result::ErrorMemAlloc, ex.what() };
127 } catch(const std::exception& stdEx) {
128 return { Result::ErrorUnhandledException, stdEx.what() };
129 } catch(...) {
130 return { Result::ErrorUnhandledException, "Unknown Exception Type!" };
131 }
132 return Result::Success;
133}
134
135inline const CallRecord& Exception::throwException(const CallRecord& record) {
136 switch(record.getResult().getValue()) {
137 case Result::ErrorUnderflow: throw StdException<std::underflow_error>(record);
138 case Result::ErrorOverflow: throw StdException<std::overflow_error>(record);
139 case Result::ErrorOutOfRange: throw StdException<std::out_of_range>(record);
140 case Result::ErrorInvalidArg: throw StdException<std::invalid_argument>(record);
141 case Result::ErrorMemAlloc:
142 case Result::ErrorMemRealloc: throw StdException<std::bad_alloc>(record);
143 default: throw StdException<std::exception>(record);
144 }
145 return record;
146}
147
148
149
150}
151
152
153#endif // GIMBAL_EXCEPTION_HPP