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