Coverage Report

Created: 2025-06-13 06:21

/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