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
9namespace simdjson {
10namespace internal {
11template<typename T>
12class string_builder;
13}
14namespace dom {
15class array;
16class document;
17class 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 */
23enum 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 */
40class element {
41public:
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
466private:
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. */
481template<>
482struct simdjson_result<dom::element> : public internal::simdjson_result_base<dom::element> {
483public:
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