1 | #ifndef SIMDJSON_DOM_ELEMENT_H |
2 | #define SIMDJSON_DOM_ELEMENT_H |
3 | |
4 | #include "simdjson/common_defs.h" |
5 | #include "simdjson/error.h" |
6 | #include "simdjson/internal/tape_ref.h" |
7 | #include <ostream> |
8 | |
9 | namespace simdjson { |
10 | namespace internal { |
11 | template<typename T> |
12 | class string_builder; |
13 | } |
14 | namespace dom { |
15 | class array; |
16 | class document; |
17 | class object; |
18 | |
19 | /** |
20 | * The actual concrete type of a JSON element |
21 | * This is the type it is most easily cast to with get<>. |
22 | */ |
23 | enum class element_type { |
24 | ARRAY = '[', ///< dom::array |
25 | OBJECT = '{', ///< dom::object |
26 | INT64 = 'l', ///< int64_t |
27 | UINT64 = 'u', ///< uint64_t: any integer that fits in uint64_t but *not* int64_t |
28 | DOUBLE = 'd', ///< double: Any number with a "." or "e" that fits in double. |
29 | STRING = '"', ///< std::string_view |
30 | BOOL = 't', ///< bool |
31 | NULL_VALUE = 'n' ///< null |
32 | }; |
33 | |
34 | /** |
35 | * A JSON element. |
36 | * |
37 | * References an element in a JSON document, representing a JSON null, boolean, string, number, |
38 | * array or object. |
39 | */ |
40 | class element { |
41 | public: |
42 | /** Create a new, invalid element. */ |
43 | simdjson_inline element() noexcept; |
44 | |
45 | /** The type of this element. */ |
46 | simdjson_inline element_type type() const noexcept; |
47 | |
48 | /** |
49 | * Cast this element to an array. |
50 | * |
51 | * @returns An object that can be used to iterate the array, or: |
52 | * INCORRECT_TYPE if the JSON element is not an array. |
53 | */ |
54 | inline simdjson_result<array> get_array() const noexcept; |
55 | /** |
56 | * Cast this element to an object. |
57 | * |
58 | * @returns An object that can be used to look up or iterate the object's fields, or: |
59 | * INCORRECT_TYPE if the JSON element is not an object. |
60 | */ |
61 | inline simdjson_result<object> get_object() const noexcept; |
62 | /** |
63 | * Cast this element to a null-terminated C string. |
64 | * |
65 | * The string is guaranteed to be valid UTF-8. |
66 | * |
67 | * The length of the string is given by get_string_length(). Because JSON strings |
68 | * may contain null characters, it may be incorrect to use strlen to determine the |
69 | * string length. |
70 | * |
71 | * It is possible to get a single string_view instance which represents both the string |
72 | * content and its length: see get_string(). |
73 | * |
74 | * @returns A pointer to a null-terminated UTF-8 string. This string is stored in the parser and will |
75 | * be invalidated the next time it parses a document or when it is destroyed. |
76 | * Returns INCORRECT_TYPE if the JSON element is not a string. |
77 | */ |
78 | inline simdjson_result<const char *> get_c_str() const noexcept; |
79 | /** |
80 | * Gives the length in bytes of the string. |
81 | * |
82 | * It is possible to get a single string_view instance which represents both the string |
83 | * content and its length: see get_string(). |
84 | * |
85 | * @returns A string length in bytes. |
86 | * Returns INCORRECT_TYPE if the JSON element is not a string. |
87 | */ |
88 | inline simdjson_result<size_t> get_string_length() const noexcept; |
89 | /** |
90 | * Cast this element to a string. |
91 | * |
92 | * The string is guaranteed to be valid UTF-8. |
93 | * |
94 | * @returns An UTF-8 string. The string is stored in the parser and will be invalidated the next time it |
95 | * parses a document or when it is destroyed. |
96 | * Returns INCORRECT_TYPE if the JSON element is not a string. |
97 | */ |
98 | inline simdjson_result<std::string_view> get_string() const noexcept; |
99 | /** |
100 | * Cast this element to a signed integer. |
101 | * |
102 | * @returns A signed 64-bit integer. |
103 | * Returns INCORRECT_TYPE if the JSON element is not an integer, or NUMBER_OUT_OF_RANGE |
104 | * if it is negative. |
105 | */ |
106 | inline simdjson_result<int64_t> get_int64() const noexcept; |
107 | /** |
108 | * Cast this element to an unsigned integer. |
109 | * |
110 | * @returns An unsigned 64-bit integer. |
111 | * Returns INCORRECT_TYPE if the JSON element is not an integer, or NUMBER_OUT_OF_RANGE |
112 | * if it is too large. |
113 | */ |
114 | inline simdjson_result<uint64_t> get_uint64() const noexcept; |
115 | /** |
116 | * Cast this element to a double floating-point. |
117 | * |
118 | * @returns A double value. |
119 | * Returns INCORRECT_TYPE if the JSON element is not a number. |
120 | */ |
121 | inline simdjson_result<double> get_double() const noexcept; |
122 | /** |
123 | * Cast this element to a bool. |
124 | * |
125 | * @returns A bool value. |
126 | * Returns INCORRECT_TYPE if the JSON element is not a boolean. |
127 | */ |
128 | inline simdjson_result<bool> get_bool() const noexcept; |
129 | |
130 | /** |
131 | * Whether this element is a json array. |
132 | * |
133 | * Equivalent to is<array>(). |
134 | */ |
135 | inline bool is_array() const noexcept; |
136 | /** |
137 | * Whether this element is a json object. |
138 | * |
139 | * Equivalent to is<object>(). |
140 | */ |
141 | inline bool is_object() const noexcept; |
142 | /** |
143 | * Whether this element is a json string. |
144 | * |
145 | * Equivalent to is<std::string_view>() or is<const char *>(). |
146 | */ |
147 | inline bool is_string() const noexcept; |
148 | /** |
149 | * Whether this element is a json number that fits in a signed 64-bit integer. |
150 | * |
151 | * Equivalent to is<int64_t>(). |
152 | */ |
153 | inline bool is_int64() const noexcept; |
154 | /** |
155 | * Whether this element is a json number that fits in an unsigned 64-bit integer. |
156 | * |
157 | * Equivalent to is<uint64_t>(). |
158 | */ |
159 | inline bool is_uint64() const noexcept; |
160 | /** |
161 | * Whether this element is a json number that fits in a double. |
162 | * |
163 | * Equivalent to is<double>(). |
164 | */ |
165 | inline bool is_double() const noexcept; |
166 | |
167 | /** |
168 | * Whether this element is a json number. |
169 | * |
170 | * Both integers and floating points will return true. |
171 | */ |
172 | inline bool is_number() const noexcept; |
173 | |
174 | /** |
175 | * Whether this element is a json `true` or `false`. |
176 | * |
177 | * Equivalent to is<bool>(). |
178 | */ |
179 | inline bool is_bool() const noexcept; |
180 | /** |
181 | * Whether this element is a json `null`. |
182 | */ |
183 | inline bool is_null() const noexcept; |
184 | |
185 | /** |
186 | * Tell whether the value can be cast to provided type (T). |
187 | * |
188 | * Supported types: |
189 | * - Boolean: bool |
190 | * - Number: double, uint64_t, int64_t |
191 | * - String: std::string_view, const char * |
192 | * - Array: dom::array |
193 | * - Object: dom::object |
194 | * |
195 | * @tparam T bool, double, uint64_t, int64_t, std::string_view, const char *, dom::array, dom::object |
196 | */ |
197 | template<typename T> |
198 | simdjson_inline bool is() const noexcept; |
199 | |
200 | /** |
201 | * Get the value as the provided type (T). |
202 | * |
203 | * Supported types: |
204 | * - Boolean: bool |
205 | * - Number: double, uint64_t, int64_t |
206 | * - String: std::string_view, const char * |
207 | * - Array: dom::array |
208 | * - Object: dom::object |
209 | * |
210 | * You may use get_double(), get_bool(), get_uint64(), get_int64(), |
211 | * get_object(), get_array() or get_string() instead. |
212 | * |
213 | * @tparam T bool, double, uint64_t, int64_t, std::string_view, const char *, dom::array, dom::object |
214 | * |
215 | * @returns The value cast to the given type, or: |
216 | * INCORRECT_TYPE if the value cannot be cast to the given type. |
217 | */ |
218 | |
219 | template<typename T> |
220 | inline simdjson_result<T> get() const noexcept { |
221 | // Unless the simdjson library provides an inline implementation, calling this method should |
222 | // immediately fail. |
223 | static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library." ); |
224 | } |
225 | |
226 | /** |
227 | * Get the value as the provided type (T). |
228 | * |
229 | * Supported types: |
230 | * - Boolean: bool |
231 | * - Number: double, uint64_t, int64_t |
232 | * - String: std::string_view, const char * |
233 | * - Array: dom::array |
234 | * - Object: dom::object |
235 | * |
236 | * @tparam T bool, double, uint64_t, int64_t, std::string_view, const char *, dom::array, dom::object |
237 | * |
238 | * @param value The variable to set to the value. May not be set if there is an error. |
239 | * |
240 | * @returns The error that occurred, or SUCCESS if there was no error. |
241 | */ |
242 | template<typename T> |
243 | simdjson_warn_unused simdjson_inline error_code get(T &value) const noexcept; |
244 | |
245 | /** |
246 | * Get the value as the provided type (T), setting error if it's not the given type. |
247 | * |
248 | * Supported types: |
249 | * - Boolean: bool |
250 | * - Number: double, uint64_t, int64_t |
251 | * - String: std::string_view, const char * |
252 | * - Array: dom::array |
253 | * - Object: dom::object |
254 | * |
255 | * @tparam T bool, double, uint64_t, int64_t, std::string_view, const char *, dom::array, dom::object |
256 | * |
257 | * @param value The variable to set to the given type. value is undefined if there is an error. |
258 | * @param error The variable to store the error. error is set to error_code::SUCCEED if there is an error. |
259 | */ |
260 | template<typename T> |
261 | inline void tie(T &value, error_code &error) && noexcept; |
262 | |
263 | #if SIMDJSON_EXCEPTIONS |
264 | /** |
265 | * Read this element as a boolean. |
266 | * |
267 | * @return The boolean value |
268 | * @exception simdjson_error(INCORRECT_TYPE) if the JSON element is not a boolean. |
269 | */ |
270 | inline operator bool() const noexcept(false); |
271 | |
272 | /** |
273 | * Read this element as a null-terminated UTF-8 string. |
274 | * |
275 | * Be mindful that JSON allows strings to contain null characters. |
276 | * |
277 | * Does *not* convert other types to a string; requires that the JSON type of the element was |
278 | * an actual string. |
279 | * |
280 | * @return The string value. |
281 | * @exception simdjson_error(INCORRECT_TYPE) if the JSON element is not a string. |
282 | */ |
283 | inline explicit operator const char*() const noexcept(false); |
284 | |
285 | /** |
286 | * Read this element as a null-terminated UTF-8 string. |
287 | * |
288 | * Does *not* convert other types to a string; requires that the JSON type of the element was |
289 | * an actual string. |
290 | * |
291 | * @return The string value. |
292 | * @exception simdjson_error(INCORRECT_TYPE) if the JSON element is not a string. |
293 | */ |
294 | inline operator std::string_view() const noexcept(false); |
295 | |
296 | /** |
297 | * Read this element as an unsigned integer. |
298 | * |
299 | * @return The integer value. |
300 | * @exception simdjson_error(INCORRECT_TYPE) if the JSON element is not an integer |
301 | * @exception simdjson_error(NUMBER_OUT_OF_RANGE) if the integer doesn't fit in 64 bits or is negative |
302 | */ |
303 | inline operator uint64_t() const noexcept(false); |
304 | /** |
305 | * Read this element as an signed integer. |
306 | * |
307 | * @return The integer value. |
308 | * @exception simdjson_error(INCORRECT_TYPE) if the JSON element is not an integer |
309 | * @exception simdjson_error(NUMBER_OUT_OF_RANGE) if the integer doesn't fit in 64 bits |
310 | */ |
311 | inline operator int64_t() const noexcept(false); |
312 | /** |
313 | * Read this element as an double. |
314 | * |
315 | * @return The double value. |
316 | * @exception simdjson_error(INCORRECT_TYPE) if the JSON element is not a number |
317 | * @exception simdjson_error(NUMBER_OUT_OF_RANGE) if the integer doesn't fit in 64 bits or is negative |
318 | */ |
319 | inline operator double() const noexcept(false); |
320 | /** |
321 | * Read this element as a JSON array. |
322 | * |
323 | * @return The JSON array. |
324 | * @exception simdjson_error(INCORRECT_TYPE) if the JSON element is not an array |
325 | */ |
326 | inline operator array() const noexcept(false); |
327 | /** |
328 | * Read this element as a JSON object (key/value pairs). |
329 | * |
330 | * @return The JSON object. |
331 | * @exception simdjson_error(INCORRECT_TYPE) if the JSON element is not an object |
332 | */ |
333 | inline operator object() const noexcept(false); |
334 | |
335 | /** |
336 | * Iterate over each element in this array. |
337 | * |
338 | * @return The beginning of the iteration. |
339 | * @exception simdjson_error(INCORRECT_TYPE) if the JSON element is not an array |
340 | */ |
341 | inline dom::array::iterator begin() const noexcept(false); |
342 | |
343 | /** |
344 | * Iterate over each element in this array. |
345 | * |
346 | * @return The end of the iteration. |
347 | * @exception simdjson_error(INCORRECT_TYPE) if the JSON element is not an array |
348 | */ |
349 | inline dom::array::iterator end() const noexcept(false); |
350 | #endif // SIMDJSON_EXCEPTIONS |
351 | |
352 | /** |
353 | * Get the value associated with the given key. |
354 | * |
355 | * The key will be matched against **unescaped** JSON: |
356 | * |
357 | * dom::parser parser; |
358 | * int64_t(parser.parse(R"({ "a\n": 1 })"_padded)["a\n"]) == 1 |
359 | * parser.parse(R"({ "a\n": 1 })"_padded)["a\\n"].get_uint64().error() == NO_SUCH_FIELD |
360 | * |
361 | * @return The value associated with this field, or: |
362 | * - NO_SUCH_FIELD if the field does not exist in the object |
363 | * - INCORRECT_TYPE if this is not an object |
364 | */ |
365 | inline simdjson_result<element> operator[](std::string_view key) const noexcept; |
366 | |
367 | /** |
368 | * Get the value associated with the given key. |
369 | * |
370 | * The key will be matched against **unescaped** JSON: |
371 | * |
372 | * dom::parser parser; |
373 | * int64_t(parser.parse(R"({ "a\n": 1 })"_padded)["a\n"]) == 1 |
374 | * parser.parse(R"({ "a\n": 1 })"_padded)["a\\n"].get_uint64().error() == NO_SUCH_FIELD |
375 | * |
376 | * @return The value associated with this field, or: |
377 | * - NO_SUCH_FIELD if the field does not exist in the object |
378 | * - INCORRECT_TYPE if this is not an object |
379 | */ |
380 | inline simdjson_result<element> operator[](const char *key) const noexcept; |
381 | |
382 | /** |
383 | * Get the value associated with the given JSON pointer. We use the RFC 6901 |
384 | * https://tools.ietf.org/html/rfc6901 standard. |
385 | * |
386 | * dom::parser parser; |
387 | * element doc = parser.parse(R"({ "foo": { "a": [ 10, 20, 30 ] }})"_padded); |
388 | * doc.at_pointer("/foo/a/1") == 20 |
389 | * doc.at_pointer("/foo")["a"].at(1) == 20 |
390 | * doc.at_pointer("")["foo"]["a"].at(1) == 20 |
391 | * |
392 | * It is allowed for a key to be the empty string: |
393 | * |
394 | * dom::parser parser; |
395 | * object obj = parser.parse(R"({ "": { "a": [ 10, 20, 30 ] }})"_padded); |
396 | * obj.at_pointer("//a/1") == 20 |
397 | * |
398 | * @return The value associated with the given JSON pointer, or: |
399 | * - NO_SUCH_FIELD if a field does not exist in an object |
400 | * - INDEX_OUT_OF_BOUNDS if an array index is larger than an array length |
401 | * - INCORRECT_TYPE if a non-integer is used to access an array |
402 | * - INVALID_JSON_POINTER if the JSON pointer is invalid and cannot be parsed |
403 | */ |
404 | inline simdjson_result<element> at_pointer(const std::string_view json_pointer) const noexcept; |
405 | |
406 | #ifndef SIMDJSON_DISABLE_DEPRECATED_API |
407 | /** |
408 | * |
409 | * Version 0.4 of simdjson used an incorrect interpretation of the JSON Pointer standard |
410 | * and allowed the following : |
411 | * |
412 | * dom::parser parser; |
413 | * element doc = parser.parse(R"({ "foo": { "a": [ 10, 20, 30 ] }})"_padded); |
414 | * doc.at("foo/a/1") == 20 |
415 | * |
416 | * Though it is intuitive, it is not compliant with RFC 6901 |
417 | * https://tools.ietf.org/html/rfc6901 |
418 | * |
419 | * For standard compliance, use the at_pointer function instead. |
420 | * |
421 | * @return The value associated with the given JSON pointer, or: |
422 | * - NO_SUCH_FIELD if a field does not exist in an object |
423 | * - INDEX_OUT_OF_BOUNDS if an array index is larger than an array length |
424 | * - INCORRECT_TYPE if a non-integer is used to access an array |
425 | * - INVALID_JSON_POINTER if the JSON pointer is invalid and cannot be parsed |
426 | */ |
427 | [[deprecated("For standard compliance, use at_pointer instead, and prefix your pointers with a slash '/', see RFC6901 " )]] |
428 | inline simdjson_result<element> at(const std::string_view json_pointer) const noexcept; |
429 | #endif // SIMDJSON_DISABLE_DEPRECATED_API |
430 | |
431 | /** |
432 | * Get the value at the given index. |
433 | * |
434 | * @return The value at the given index, or: |
435 | * - INDEX_OUT_OF_BOUNDS if the array index is larger than an array length |
436 | */ |
437 | inline simdjson_result<element> at(size_t index) const noexcept; |
438 | |
439 | /** |
440 | * Get the value associated with the given key. |
441 | * |
442 | * The key will be matched against **unescaped** JSON: |
443 | * |
444 | * dom::parser parser; |
445 | * int64_t(parser.parse(R"({ "a\n": 1 })"_padded)["a\n"]) == 1 |
446 | * parser.parse(R"({ "a\n": 1 })"_padded)["a\\n"].get_uint64().error() == NO_SUCH_FIELD |
447 | * |
448 | * @return The value associated with this field, or: |
449 | * - NO_SUCH_FIELD if the field does not exist in the object |
450 | */ |
451 | inline simdjson_result<element> at_key(std::string_view key) const noexcept; |
452 | |
453 | /** |
454 | * Get the value associated with the given key in a case-insensitive manner. |
455 | * |
456 | * Note: The key will be matched against **unescaped** JSON. |
457 | * |
458 | * @return The value associated with this field, or: |
459 | * - NO_SUCH_FIELD if the field does not exist in the object |
460 | */ |
461 | inline simdjson_result<element> at_key_case_insensitive(std::string_view key) const noexcept; |
462 | |
463 | /** @private for debugging. Prints out the root element. */ |
464 | inline bool dump_raw_tape(std::ostream &out) const noexcept; |
465 | |
466 | private: |
467 | simdjson_inline element(const internal::tape_ref &tape) noexcept; |
468 | internal::tape_ref tape; |
469 | friend class document; |
470 | friend class object; |
471 | friend class array; |
472 | friend struct simdjson_result<element>; |
473 | template<typename T> |
474 | friend class simdjson::internal::string_builder; |
475 | |
476 | }; |
477 | |
478 | } // namespace dom |
479 | |
480 | /** The result of a JSON navigation that may fail. */ |
481 | template<> |
482 | struct simdjson_result<dom::element> : public internal::simdjson_result_base<dom::element> { |
483 | public: |
484 | simdjson_inline simdjson_result() noexcept; ///< @private |
485 | simdjson_inline simdjson_result(dom::element &&value) noexcept; ///< @private |
486 | simdjson_inline simdjson_result(error_code error) noexcept; ///< @private |
487 | |
488 | simdjson_inline simdjson_result<dom::element_type> type() const noexcept; |
489 | template<typename T> |
490 | simdjson_inline bool is() const noexcept; |
491 | template<typename T> |
492 | simdjson_inline simdjson_result<T> get() const noexcept; |
493 | template<typename T> |
494 | simdjson_warn_unused simdjson_inline error_code get(T &value) const noexcept; |
495 | |
496 | simdjson_inline simdjson_result<dom::array> get_array() const noexcept; |
497 | simdjson_inline simdjson_result<dom::object> get_object() const noexcept; |
498 | simdjson_inline simdjson_result<const char *> get_c_str() const noexcept; |
499 | simdjson_inline simdjson_result<size_t> get_string_length() const noexcept; |
500 | simdjson_inline simdjson_result<std::string_view> get_string() const noexcept; |
501 | simdjson_inline simdjson_result<int64_t> get_int64() const noexcept; |
502 | simdjson_inline simdjson_result<uint64_t> get_uint64() const noexcept; |
503 | simdjson_inline simdjson_result<double> get_double() const noexcept; |
504 | simdjson_inline simdjson_result<bool> get_bool() const noexcept; |
505 | |
506 | simdjson_inline bool is_array() const noexcept; |
507 | simdjson_inline bool is_object() const noexcept; |
508 | simdjson_inline bool is_string() const noexcept; |
509 | simdjson_inline bool is_int64() const noexcept; |
510 | simdjson_inline bool is_uint64() const noexcept; |
511 | simdjson_inline bool is_double() const noexcept; |
512 | simdjson_inline bool is_number() const noexcept; |
513 | simdjson_inline bool is_bool() const noexcept; |
514 | simdjson_inline bool is_null() const noexcept; |
515 | |
516 | simdjson_inline simdjson_result<dom::element> operator[](std::string_view key) const noexcept; |
517 | simdjson_inline simdjson_result<dom::element> operator[](const char *key) const noexcept; |
518 | simdjson_inline simdjson_result<dom::element> at_pointer(const std::string_view json_pointer) const noexcept; |
519 | [[deprecated("For standard compliance, use at_pointer instead, and prefix your pointers with a slash '/', see RFC6901 " )]] |
520 | simdjson_inline simdjson_result<dom::element> at(const std::string_view json_pointer) const noexcept; |
521 | simdjson_inline simdjson_result<dom::element> at(size_t index) const noexcept; |
522 | simdjson_inline simdjson_result<dom::element> at_key(std::string_view key) const noexcept; |
523 | simdjson_inline simdjson_result<dom::element> at_key_case_insensitive(std::string_view key) const noexcept; |
524 | |
525 | #if SIMDJSON_EXCEPTIONS |
526 | simdjson_inline operator bool() const noexcept(false); |
527 | simdjson_inline explicit operator const char*() const noexcept(false); |
528 | simdjson_inline operator std::string_view() const noexcept(false); |
529 | simdjson_inline operator uint64_t() const noexcept(false); |
530 | simdjson_inline operator int64_t() const noexcept(false); |
531 | simdjson_inline operator double() const noexcept(false); |
532 | simdjson_inline operator dom::array() const noexcept(false); |
533 | simdjson_inline operator dom::object() const noexcept(false); |
534 | |
535 | simdjson_inline dom::array::iterator begin() const noexcept(false); |
536 | simdjson_inline dom::array::iterator end() const noexcept(false); |
537 | #endif // SIMDJSON_EXCEPTIONS |
538 | }; |
539 | |
540 | |
541 | } // namespace simdjson |
542 | |
543 | #endif // SIMDJSON_DOM_DOCUMENT_H |
544 | |