src/zserio/CppRuntimeException.h
Line | Count | Source |
1 | | #ifndef ZSERIO_CPP_RUNTIME_EXCEPTION_H_INC |
2 | | #define ZSERIO_CPP_RUNTIME_EXCEPTION_H_INC |
3 | | |
4 | | #include <array> |
5 | | #include <exception> |
6 | | #include <string> |
7 | | #include <string_view> |
8 | | #include <type_traits> |
9 | | #include <vector> |
10 | | |
11 | | #include "zserio/StringConvertUtil.h" |
12 | | |
13 | | namespace zserio |
14 | | { |
15 | | |
16 | | /** |
17 | | * Exception thrown when an error within the Zserio C++ runtime library occurs. |
18 | | */ |
19 | | class CppRuntimeException : public std::exception |
20 | | { |
21 | | public: |
22 | | /** |
23 | | * Constructor. |
24 | | * |
25 | | * \param message Description of the error. |
26 | | */ |
27 | | explicit CppRuntimeException(const char* message = ""); |
28 | | |
29 | | /** |
30 | | * Method generated by default. |
31 | | * \{ |
32 | | */ |
33 | 3.07k | ~CppRuntimeException() override = default; |
34 | | |
35 | | CppRuntimeException(const CppRuntimeException& other) = default; |
36 | 103 | CppRuntimeException& operator=(const CppRuntimeException& other) = default; |
37 | | |
38 | 1.45k | CppRuntimeException(CppRuntimeException&& other) = default; |
39 | 2 | CppRuntimeException& operator=(CppRuntimeException&& other) = default; |
40 | | /** |
41 | | * \} |
42 | | */ |
43 | | |
44 | | const char* what() const noexcept override; |
45 | | |
46 | | /** |
47 | | * Appends a message to the description. |
48 | | * |
49 | | * \param message Description of the error to append. |
50 | | */ |
51 | | void append(const char* message); |
52 | | |
53 | | /** |
54 | | * Appends a message of a known length to the description. |
55 | | * |
56 | | * \param message Description of the error to append. |
57 | | * \param messageLen Length of the message. |
58 | | */ |
59 | | void append(const char* message, size_t messageLen); |
60 | | |
61 | | private: |
62 | | void appendImpl(std::string_view message); |
63 | | |
64 | | std::array<char, 512> m_buffer; // note fixed sized array is deeply copied on copy operations and it's OK |
65 | | size_t m_len = 0; |
66 | | }; |
67 | | |
68 | | /** |
69 | | * Appends a message to the exception's description. |
70 | | * |
71 | | * \param exception Exception to modify. |
72 | | * \param message Description of the error to append. |
73 | | * |
74 | | * \return Reference to the exception to allow operator chaining. |
75 | | */ |
76 | | CppRuntimeException& operator<<(CppRuntimeException& exception, const char* message); |
77 | | |
78 | | /** |
79 | | * Appends a bool value to the exception's description. |
80 | | * |
81 | | * \param exception Exception to modify. |
82 | | * \param value Bool value to append. |
83 | | * |
84 | | * \return Reference to the exception to allow operator chaining. |
85 | | */ |
86 | | CppRuntimeException& operator<<(CppRuntimeException& exception, bool value); |
87 | | |
88 | | /** |
89 | | * Appends a float value to the exception's description. |
90 | | * |
91 | | * \param exception Exception to modify. |
92 | | * \param value Float value to append. |
93 | | * |
94 | | * \return Reference to the exception to allow operator chaining. |
95 | | */ |
96 | | CppRuntimeException& operator<<(CppRuntimeException& exception, float value); |
97 | | |
98 | | /** |
99 | | * Appends a double value to the exception's description. |
100 | | * |
101 | | * \param exception Exception to modify. |
102 | | * \param value Double value to append. |
103 | | * |
104 | | * \return Reference to the exception to allow operator chaining. |
105 | | */ |
106 | | CppRuntimeException& operator<<(CppRuntimeException& exception, double value); |
107 | | |
108 | | /** |
109 | | * Appends a string_view to the exception's description. |
110 | | * |
111 | | * \param exception Exception to modify. |
112 | | * \param value String view to append. |
113 | | * |
114 | | * \return Reference to the exception to allow operator chaining. |
115 | | */ |
116 | | CppRuntimeException& operator<<(CppRuntimeException& exception, std::string_view value); |
117 | | |
118 | | /** |
119 | | * Appends an integral value to the exception's description. |
120 | | * |
121 | | * \param exception Exception to modify. |
122 | | * \param value Integral value to append. |
123 | | * |
124 | | * \return Reference to the exception to allow operator chaining. |
125 | | */ |
126 | | template <typename T, typename std::enable_if<std::is_integral<T>::value, int>::type = 0> |
127 | | CppRuntimeException& operator<<(CppRuntimeException& exception, T value) |
128 | 3.57k | { |
129 | 3.57k | std::array<char, 24> buffer = {}; |
130 | 3.57k | const char* stringValue = convertIntToString(buffer, value); |
131 | 3.57k | return exception << stringValue; |
132 | 3.57k | } |
133 | | |
134 | | /** |
135 | | * Appends a string value to the exception's description. |
136 | | * |
137 | | * \param exception Exception to modify. |
138 | | * \param value String value to append. |
139 | | * |
140 | | * \return Reference to the exception to allow operator chaining. |
141 | | */ |
142 | | template <typename ALLOC> |
143 | | CppRuntimeException& operator<<( |
144 | | CppRuntimeException& exception, const std::basic_string<char, std::char_traits<char>, ALLOC>& value) |
145 | 3 | { |
146 | 3 | exception.append(value.c_str(), value.size()); |
147 | 3 | return exception; |
148 | 3 | } |
149 | | |
150 | | /** |
151 | | * Appends a vector value to the exception's description. |
152 | | * |
153 | | * \param exception Exception to modify. |
154 | | * \param value Vector value to append. |
155 | | * |
156 | | * \return Reference to the exception to allow operator chaining. |
157 | | */ |
158 | | template <typename T, typename ALLOC> |
159 | | CppRuntimeException& operator<<(CppRuntimeException& exception, const std::vector<T, ALLOC>& value) |
160 | 1 | { |
161 | 1 | return exception << "vector([...], " << value.size() << ")"; |
162 | 1 | } |
163 | | |
164 | | namespace detail |
165 | | { |
166 | | |
167 | | // inspired by C++ ostreams - see https://cplusplus.github.io/LWG/issue1203 |
168 | | // note that e.g. in gcc implementation of ostreams there are two constraints, but the second one: |
169 | | // typename = decltype(std::declval<EXCEPTION&>() << std::declval<const VALUE&>()) |
170 | | // is probably unnecessary and since it caused a compilation error in MSVC 2017 Conformance Mode, |
171 | | // we intentionally skipped it (even though it was probably a compiler bug) |
172 | | template <typename EXCEPTION, typename VALUE, |
173 | | typename = typename std::enable_if<std::is_base_of<CppRuntimeException, EXCEPTION>::value, int>::type> |
174 | | using CppRuntimeExceptionRValueInsertion = EXCEPTION&&; |
175 | | |
176 | | } // namespace detail |
177 | | |
178 | | /** |
179 | | * Appends any value for which operator<< is implemented to the exception's description. |
180 | | * |
181 | | * Overload for rvalue to enable operator<< on a temporary object, .e.g. CppRuntimeException() << "value". |
182 | | * Moreover note that this overload preserves the concrete type of the exception! |
183 | | * |
184 | | * \param exception Exception to modify. |
185 | | * \param value Value to append. |
186 | | * |
187 | | * \return R-value reference to the original exception to allow operator chaining. |
188 | | */ |
189 | | template <typename CPP_RUNTIME_EXCEPTION, typename T> |
190 | | detail::CppRuntimeExceptionRValueInsertion<CPP_RUNTIME_EXCEPTION, T> operator<<( |
191 | | CPP_RUNTIME_EXCEPTION&& exception, const T& value) |
192 | 7.17k | { |
193 | 7.17k | exception << value; |
194 | 7.17k | return std::forward<CPP_RUNTIME_EXCEPTION>(exception); |
195 | 7.17k | } |
196 | | |
197 | | } // namespace zserio |
198 | | |
199 | | #endif // ifndef ZSERIO_CPP_RUNTIME_EXCEPTION_H_INC |