/src/simdjson/include/simdjson/error.h
Line | Count | Source (jump to first uncovered line) |
1 | | #ifndef SIMDJSON_ERROR_H |
2 | | #define SIMDJSON_ERROR_H |
3 | | |
4 | | #include "simdjson/base.h" |
5 | | |
6 | | #include <string> |
7 | | #include <ostream> |
8 | | |
9 | | namespace simdjson { |
10 | | |
11 | | /** |
12 | | * All possible errors returned by simdjson. These error codes are subject to change |
13 | | * and not all simdjson kernel returns the same error code given the same input: it is not |
14 | | * well defined which error a given input should produce. |
15 | | * |
16 | | * Only SUCCESS evaluates to false as a Boolean. All other error codes will evaluate |
17 | | * to true as a Boolean. |
18 | | */ |
19 | | enum error_code { |
20 | | SUCCESS = 0, ///< No error |
21 | | CAPACITY, ///< This parser can't support a document that big |
22 | | MEMALLOC, ///< Error allocating memory, most likely out of memory |
23 | | TAPE_ERROR, ///< Something went wrong, this is a generic error. Fatal/unrecoverable error. |
24 | | DEPTH_ERROR, ///< Your document exceeds the user-specified depth limitation |
25 | | STRING_ERROR, ///< Problem while parsing a string |
26 | | T_ATOM_ERROR, ///< Problem while parsing an atom starting with the letter 't' |
27 | | F_ATOM_ERROR, ///< Problem while parsing an atom starting with the letter 'f' |
28 | | N_ATOM_ERROR, ///< Problem while parsing an atom starting with the letter 'n' |
29 | | NUMBER_ERROR, ///< Problem while parsing a number |
30 | | BIGINT_ERROR, ///< The integer value exceeds 64 bits |
31 | | UTF8_ERROR, ///< the input is not valid UTF-8 |
32 | | UNINITIALIZED, ///< unknown error, or uninitialized document |
33 | | EMPTY, ///< no structural element found |
34 | | UNESCAPED_CHARS, ///< found unescaped characters in a string. |
35 | | UNCLOSED_STRING, ///< missing quote at the end |
36 | | UNSUPPORTED_ARCHITECTURE, ///< unsupported architecture |
37 | | INCORRECT_TYPE, ///< JSON element has a different type than user expected |
38 | | NUMBER_OUT_OF_RANGE, ///< JSON number does not fit in 64 bits |
39 | | INDEX_OUT_OF_BOUNDS, ///< JSON array index too large |
40 | | NO_SUCH_FIELD, ///< JSON field not found in object |
41 | | IO_ERROR, ///< Error reading a file |
42 | | INVALID_JSON_POINTER, ///< Invalid JSON pointer syntax |
43 | | INVALID_URI_FRAGMENT, ///< Invalid URI fragment |
44 | | UNEXPECTED_ERROR, ///< indicative of a bug in simdjson |
45 | | PARSER_IN_USE, ///< parser is already in use. |
46 | | OUT_OF_ORDER_ITERATION, ///< tried to iterate an array or object out of order (checked when SIMDJSON_DEVELOPMENT_CHECKS=1) |
47 | | INSUFFICIENT_PADDING, ///< The JSON doesn't have enough padding for simdjson to safely parse it. |
48 | | INCOMPLETE_ARRAY_OR_OBJECT, ///< The document ends early. Fatal/unrecoverable error. |
49 | | SCALAR_DOCUMENT_AS_VALUE, ///< A scalar document is treated as a value. |
50 | | OUT_OF_BOUNDS, ///< Attempted to access location outside of document. |
51 | | TRAILING_CONTENT, ///< Unexpected trailing content in the JSON input |
52 | | NUM_ERROR_CODES |
53 | | }; |
54 | | |
55 | | /** |
56 | | * Some errors are fatal and invalidate the document. This function returns true if the |
57 | | * error is fatal. It returns true for TAPE_ERROR and INCOMPLETE_ARRAY_OR_OBJECT. |
58 | | * Once a fatal error is encountered, the on-demand document is no longer valid and |
59 | | * processing should stop. |
60 | | */ |
61 | | inline bool is_fatal(error_code error) noexcept; |
62 | | |
63 | | /** |
64 | | * It is the convention throughout the code that the macro SIMDJSON_DEVELOPMENT_CHECKS determines whether |
65 | | * we check for OUT_OF_ORDER_ITERATION. The logic behind it is that these errors only occurs when the code |
66 | | * that was written while breaking some simdjson::ondemand requirement. They should not occur in released |
67 | | * code after these issues were fixed. |
68 | | */ |
69 | | |
70 | | /** |
71 | | * Get the error message for the given error code. |
72 | | * |
73 | | * dom::parser parser; |
74 | | * dom::element doc; |
75 | | * auto error = parser.parse("foo",3).get(doc); |
76 | | * if (error) { printf("Error: %s\n", error_message(error)); } |
77 | | * |
78 | | * @return The error message. |
79 | | */ |
80 | | inline const char *error_message(error_code error) noexcept; |
81 | | |
82 | | /** |
83 | | * Write the error message to the output stream |
84 | | */ |
85 | | inline std::ostream& operator<<(std::ostream& out, error_code error) noexcept; |
86 | | |
87 | | /** |
88 | | * Exception thrown when an exception-supporting simdjson method is called |
89 | | */ |
90 | | struct simdjson_error : public std::exception { |
91 | | /** |
92 | | * Create an exception from a simdjson error code. |
93 | | * @param error The error code |
94 | | */ |
95 | 0 | simdjson_error(error_code error) noexcept : _error{error} { } |
96 | | /** The error message */ |
97 | 0 | const char *what() const noexcept override { return error_message(error()); } |
98 | | /** The error code */ |
99 | 0 | error_code error() const noexcept { return _error; } |
100 | | private: |
101 | | /** The error code that was used */ |
102 | | error_code _error; |
103 | | }; |
104 | | |
105 | | namespace internal { |
106 | | |
107 | | /** |
108 | | * The result of a simdjson operation that could fail. |
109 | | * |
110 | | * Gives the option of reading error codes, or throwing an exception by casting to the desired result. |
111 | | * |
112 | | * This is a base class for implementations that want to add functions to the result type for |
113 | | * chaining. |
114 | | * |
115 | | * Override like: |
116 | | * |
117 | | * struct simdjson_result<T> : public internal::simdjson_result_base<T> { |
118 | | * simdjson_result() noexcept : internal::simdjson_result_base<T>() {} |
119 | | * simdjson_result(error_code error) noexcept : internal::simdjson_result_base<T>(error) {} |
120 | | * simdjson_result(T &&value) noexcept : internal::simdjson_result_base<T>(std::forward(value)) {} |
121 | | * simdjson_result(T &&value, error_code error) noexcept : internal::simdjson_result_base<T>(value, error) {} |
122 | | * // Your extra methods here |
123 | | * } |
124 | | * |
125 | | * Then any method returning simdjson_result<T> will be chainable with your methods. |
126 | | */ |
127 | | template<typename T> |
128 | | struct simdjson_result_base : protected std::pair<T, error_code> { |
129 | | |
130 | | /** |
131 | | * Create a new empty result with error = UNINITIALIZED. |
132 | | */ |
133 | | simdjson_inline simdjson_result_base() noexcept; |
134 | | |
135 | | /** |
136 | | * Create a new error result. |
137 | | */ |
138 | | simdjson_inline simdjson_result_base(error_code error) noexcept; |
139 | | |
140 | | /** |
141 | | * Create a new successful result. |
142 | | */ |
143 | | simdjson_inline simdjson_result_base(T &&value) noexcept; |
144 | | |
145 | | /** |
146 | | * Create a new result with both things (use if you don't want to branch when creating the result). |
147 | | */ |
148 | | simdjson_inline simdjson_result_base(T &&value, error_code error) noexcept; |
149 | | |
150 | | /** |
151 | | * Move the value and the error to the provided variables. |
152 | | * |
153 | | * @param value The variable to assign the value to. May not be set if there is an error. |
154 | | * @param error The variable to assign the error to. Set to SUCCESS if there is no error. |
155 | | */ |
156 | | simdjson_inline void tie(T &value, error_code &error) && noexcept; |
157 | | |
158 | | /** |
159 | | * Move the value to the provided variable. |
160 | | * |
161 | | * @param value The variable to assign the value to. May not be set if there is an error. |
162 | | */ |
163 | | simdjson_inline error_code get(T &value) && noexcept; |
164 | | |
165 | | /** |
166 | | * The error. |
167 | | */ |
168 | | simdjson_inline error_code error() const noexcept; |
169 | | |
170 | | #if SIMDJSON_EXCEPTIONS |
171 | | |
172 | | /** |
173 | | * Get the result value. |
174 | | * |
175 | | * @throw simdjson_error if there was an error. |
176 | | */ |
177 | | simdjson_inline T& value() & noexcept(false); |
178 | | |
179 | | /** |
180 | | * Take the result value (move it). |
181 | | * |
182 | | * @throw simdjson_error if there was an error. |
183 | | */ |
184 | | simdjson_inline T&& value() && noexcept(false); |
185 | | |
186 | | /** |
187 | | * Take the result value (move it). |
188 | | * |
189 | | * @throw simdjson_error if there was an error. |
190 | | */ |
191 | | simdjson_inline T&& take_value() && noexcept(false); |
192 | | |
193 | | /** |
194 | | * Cast to the value (will throw on error). |
195 | | * |
196 | | * @throw simdjson_error if there was an error. |
197 | | */ |
198 | | simdjson_inline operator T&&() && noexcept(false); |
199 | | |
200 | | #endif // SIMDJSON_EXCEPTIONS |
201 | | |
202 | | /** |
203 | | * Get the result value. This function is safe if and only |
204 | | * the error() method returns a value that evaluates to false. |
205 | | */ |
206 | | simdjson_inline const T& value_unsafe() const& noexcept; |
207 | | |
208 | | /** |
209 | | * Take the result value (move it). This function is safe if and only |
210 | | * the error() method returns a value that evaluates to false. |
211 | | */ |
212 | | simdjson_inline T&& value_unsafe() && noexcept; |
213 | | |
214 | | }; // struct simdjson_result_base |
215 | | |
216 | | } // namespace internal |
217 | | |
218 | | /** |
219 | | * The result of a simdjson operation that could fail. |
220 | | * |
221 | | * Gives the option of reading error codes, or throwing an exception by casting to the desired result. |
222 | | */ |
223 | | template<typename T> |
224 | | struct simdjson_result : public internal::simdjson_result_base<T> { |
225 | | /** |
226 | | * @private Create a new empty result with error = UNINITIALIZED. |
227 | | */ |
228 | | simdjson_inline simdjson_result() noexcept; |
229 | | /** |
230 | | * @private Create a new successful result. |
231 | | */ |
232 | | simdjson_inline simdjson_result(T &&value) noexcept; |
233 | | /** |
234 | | * @private Create a new error result. |
235 | | */ |
236 | | simdjson_inline simdjson_result(error_code error_code) noexcept; |
237 | | /** |
238 | | * @private Create a new result with both things (use if you don't want to branch when creating the result). |
239 | | */ |
240 | | simdjson_inline simdjson_result(T &&value, error_code error) noexcept; |
241 | | |
242 | | /** |
243 | | * Move the value and the error to the provided variables. |
244 | | * |
245 | | * @param value The variable to assign the value to. May not be set if there is an error. |
246 | | * @param error The variable to assign the error to. Set to SUCCESS if there is no error. |
247 | | */ |
248 | | simdjson_inline void tie(T &value, error_code &error) && noexcept; |
249 | | |
250 | | /** |
251 | | * Move the value to the provided variable. |
252 | | * |
253 | | * @param value The variable to assign the value to. May not be set if there is an error. |
254 | | */ |
255 | | simdjson_warn_unused simdjson_inline error_code get(T &value) && noexcept; |
256 | | // |
257 | | /** |
258 | | * Copy the value to a provided std::string, only enabled for std::string_view. |
259 | | * |
260 | | * @param value The variable to assign the value to. May not be set if there is an error. |
261 | | */ |
262 | | simdjson_warn_unused simdjson_inline error_code get(std::string &value) && noexcept |
263 | | #if SIMDJSON_SUPPORTS_DESERIALIZATION |
264 | | requires (!std::is_same_v<T, std::string>) |
265 | | #endif // SIMDJSON_SUPPORTS_DESERIALIZATION |
266 | | ; |
267 | | /** |
268 | | * The error. |
269 | | */ |
270 | | simdjson_inline error_code error() const noexcept; |
271 | | |
272 | | #if SIMDJSON_EXCEPTIONS |
273 | | |
274 | | /** |
275 | | * Get the result value. |
276 | | * |
277 | | * @throw simdjson_error if there was an error. |
278 | | */ |
279 | | simdjson_inline T& value() & noexcept(false); |
280 | | |
281 | | /** |
282 | | * Take the result value (move it). |
283 | | * |
284 | | * @throw simdjson_error if there was an error. |
285 | | */ |
286 | | simdjson_inline T&& value() && noexcept(false); |
287 | | |
288 | | /** |
289 | | * Take the result value (move it). |
290 | | * |
291 | | * @throw simdjson_error if there was an error. |
292 | | */ |
293 | | simdjson_inline T&& take_value() && noexcept(false); |
294 | | |
295 | | /** |
296 | | * Cast to the value (will throw on error). |
297 | | * |
298 | | * @throw simdjson_error if there was an error. |
299 | | */ |
300 | | simdjson_inline operator T&&() && noexcept(false); |
301 | | #endif // SIMDJSON_EXCEPTIONS |
302 | | |
303 | | /** |
304 | | * Get the result value. This function is safe if and only |
305 | | * the error() method returns a value that evaluates to false. |
306 | | */ |
307 | | simdjson_inline const T& value_unsafe() const& noexcept; |
308 | | |
309 | | /** |
310 | | * Take the result value (move it). This function is safe if and only |
311 | | * the error() method returns a value that evaluates to false. |
312 | | */ |
313 | | simdjson_inline T&& value_unsafe() && noexcept; |
314 | | |
315 | | }; // struct simdjson_result |
316 | | |
317 | | #if SIMDJSON_EXCEPTIONS |
318 | | |
319 | | template<typename T> |
320 | | inline std::ostream& operator<<(std::ostream& out, simdjson_result<T> value) { return out << value.value(); } |
321 | | #endif // SIMDJSON_EXCEPTIONS |
322 | | |
323 | | #ifndef SIMDJSON_DISABLE_DEPRECATED_API |
324 | | /** |
325 | | * @deprecated This is an alias and will be removed, use error_code instead |
326 | | */ |
327 | | using ErrorValues [[deprecated("This is an alias and will be removed, use error_code instead")]] = error_code; |
328 | | |
329 | | /** |
330 | | * @deprecated Error codes should be stored and returned as `error_code`, use `error_message()` instead. |
331 | | */ |
332 | | [[deprecated("Error codes should be stored and returned as `error_code`, use `error_message()` instead.")]] |
333 | | inline const std::string error_message(int error) noexcept; |
334 | | #endif // SIMDJSON_DISABLE_DEPRECATED_API |
335 | | } // namespace simdjson |
336 | | |
337 | | #endif // SIMDJSON_ERROR_H |