simdjson 4.0.7
Ridiculously Fast JSON
Loading...
Searching...
No Matches
value_iterator-inl.h
1#ifndef SIMDJSON_GENERIC_ONDEMAND_VALUE_ITERATOR_INL_H
2
3#ifndef SIMDJSON_CONDITIONAL_INCLUDE
4#define SIMDJSON_GENERIC_ONDEMAND_VALUE_ITERATOR_INL_H
5#include "simdjson/generic/ondemand/base.h"
6#include "simdjson/generic/atomparsing.h"
7#include "simdjson/generic/numberparsing.h"
8#include "simdjson/generic/ondemand/json_iterator.h"
9#include "simdjson/generic/ondemand/value_iterator.h"
10#include "simdjson/generic/ondemand/json_type-inl.h"
11#include "simdjson/generic/ondemand/raw_json_string-inl.h"
12#endif // SIMDJSON_CONDITIONAL_INCLUDE
13
14namespace simdjson {
15namespace SIMDJSON_IMPLEMENTATION {
16namespace ondemand {
17
18simdjson_inline value_iterator::value_iterator(
19 json_iterator *json_iter,
20 depth_t depth,
21 token_position start_position
22) noexcept : _json_iter{json_iter}, _depth{depth}, _start_position{start_position}
23{
24}
25
26simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::start_object() noexcept {
27 SIMDJSON_TRY( start_container('{', "Not an object", "object") );
28 return started_object();
29}
30
32 SIMDJSON_TRY( start_container('{', "Not an object", "object") );
33 return started_root_object();
34}
35
36simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::started_object() noexcept {
37 assert_at_container_start();
38#if SIMDJSON_DEVELOPMENT_CHECKS
39 _json_iter->set_start_position(_depth, start_position());
40#endif
41 if (*_json_iter->peek() == '}') {
42 logger::log_value(*_json_iter, "empty object");
43 _json_iter->return_current_and_advance();
44 SIMDJSON_TRY(end_container());
45 return false;
46 }
47 return true;
48}
49
50simdjson_warn_unused simdjson_inline error_code value_iterator::check_root_object() noexcept {
51 // When in streaming mode, we cannot expect peek_last() to be the last structural element of the
52 // current document. It only works in the normal mode where we have indexed a single document.
53 // Note that adding a check for 'streaming' is not expensive since we only have at most
54 // one root element.
55 if ( ! _json_iter->streaming() ) {
56 // The following lines do not fully protect against garbage content within the
57 // object: e.g., `{"a":2} foo }`. Users concerned with garbage content should
58 // call `at_end()` on the document instance at the end of the processing to
59 // ensure that the processing has finished at the end.
60 //
61 if (*_json_iter->peek_last() != '}') {
62 _json_iter->abandon();
63 return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "missing } at end");
64 }
65 // If the last character is } *and* the first gibberish character is also '}'
66 // then on-demand could accidentally go over. So we need additional checks.
67 // https://github.com/simdjson/simdjson/issues/1834
68 // Checking that the document is balanced requires a full scan which is potentially
69 // expensive, but it only happens in edge cases where the first padding character is
70 // a closing bracket.
71 if ((*_json_iter->peek(_json_iter->end_position()) == '}') && (!_json_iter->balanced())) {
72 _json_iter->abandon();
73 // The exact error would require more work. It will typically be an unclosed object.
74 return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "the document is unbalanced");
75 }
76 }
77 return SUCCESS;
78}
79
81 auto error = check_root_object();
82 if(error) { return error; }
83 return started_object();
84}
85
86simdjson_warn_unused simdjson_inline error_code value_iterator::end_container() noexcept {
87#if SIMDJSON_CHECK_EOF
88 if (depth() > 1 && at_end()) { return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "missing parent ] or }"); }
89 // if (depth() <= 1 && !at_end()) { return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "missing [ or { at start"); }
90#endif // SIMDJSON_CHECK_EOF
91 _json_iter->ascend_to(depth()-1);
92 return SUCCESS;
93}
94
95simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::has_next_field() noexcept {
96 assert_at_next();
97
98 // It's illegal to call this unless there are more tokens: anything that ends in } or ] is
99 // obligated to verify there are more tokens if they are not the top level.
100 switch (*_json_iter->return_current_and_advance()) {
101 case '}':
102 logger::log_end_value(*_json_iter, "object");
103 SIMDJSON_TRY( end_container() );
104 return false;
105 case ',':
106 return true;
107 default:
108 return report_error(TAPE_ERROR, "Missing comma between object fields");
109 }
110}
111
112simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::find_field_raw(const std::string_view key) noexcept {
113 error_code error;
114 bool has_value;
115 //
116 // Initially, the object can be in one of a few different places:
117 //
118 // 1. The start of the object, at the first field:
119 //
120 // ```
121 // { "a": [ 1, 2 ], "b": [ 3, 4 ] }
122 // ^ (depth 2, index 1)
123 // ```
124 if (at_first_field()) {
125 has_value = true;
126
127 //
128 // 2. When a previous search did not yield a value or the object is empty:
129 //
130 // ```
131 // { "a": [ 1, 2 ], "b": [ 3, 4 ] }
132 // ^ (depth 0)
133 // { }
134 // ^ (depth 0, index 2)
135 // ```
136 //
137 } else if (!is_open()) {
138#if SIMDJSON_DEVELOPMENT_CHECKS
139 // If we're past the end of the object, we're being iterated out of order.
140 // Note: this is not perfect detection. It's possible the user is inside some other object; if so,
141 // this object iterator will blithely scan that object for fields.
142 if (_json_iter->depth() < depth() - 1) { return OUT_OF_ORDER_ITERATION; }
143#endif
144 return false;
145
146 // 3. When a previous search found a field or an iterator yielded a value:
147 //
148 // ```
149 // // When a field was not fully consumed (or not even touched at all)
150 // { "a": [ 1, 2 ], "b": [ 3, 4 ] }
151 // ^ (depth 2)
152 // // When a field was fully consumed
153 // { "a": [ 1, 2 ], "b": [ 3, 4 ] }
154 // ^ (depth 1)
155 // // When the last field was fully consumed
156 // { "a": [ 1, 2 ], "b": [ 3, 4 ] }
157 // ^ (depth 1)
158 // ```
159 //
160 } else {
161 if ((error = skip_child() )) { abandon(); return error; }
162 if ((error = has_next_field().get(has_value) )) { abandon(); return error; }
163#if SIMDJSON_DEVELOPMENT_CHECKS
164 if (_json_iter->start_position(_depth) != start_position()) { return OUT_OF_ORDER_ITERATION; }
165#endif
166 }
167 while (has_value) {
168 // Get the key and colon, stopping at the value.
170 // size_t max_key_length = _json_iter->peek_length() - 2; // -2 for the two quotes
171 // Note: _json_iter->peek_length() - 2 might overflow if _json_iter->peek_length() < 2.
172 // field_key() advances the pointer and checks that '"' is found (corresponding to a key).
173 // The depth is left unchanged by field_key().
174 if ((error = field_key().get(actual_key) )) { abandon(); return error; };
175 // field_value() will advance and check that we find a ':' separating the
176 // key and the value. It will also increment the depth by one.
177 if ((error = field_value() )) { abandon(); return error; }
178 // If it matches, stop and return
179 // We could do it this way if we wanted to allow arbitrary
180 // key content (including escaped quotes).
181 //if (actual_key.unsafe_is_equal(max_key_length, key)) {
182 // Instead we do the following which may trigger buffer overruns if the
183 // user provides an adversarial key (containing a well placed unescaped quote
184 // character and being longer than the number of bytes remaining in the JSON
185 // input).
186 if (actual_key.unsafe_is_equal(key)) {
187 logger::log_event(*this, "match", key, -2);
188 // If we return here, then we return while pointing at the ':' that we just checked.
189 return true;
190 }
191
192 // No match: skip the value and see if , or } is next
193 logger::log_event(*this, "no match", key, -2);
194 // The call to skip_child is meant to skip over the value corresponding to the key.
195 // After skip_child(), we are right before the next comma (',') or the final brace ('}').
196 SIMDJSON_TRY( skip_child() ); // Skip the value entirely
197 // The has_next_field() advances the pointer and check that either ',' or '}' is found.
198 // It returns true if ',' is found, false otherwise. If anything other than ',' or '}' is found,
199 // then we are in error and we abort.
200 if ((error = has_next_field().get(has_value) )) { abandon(); return error; }
201 }
202
203 // If the loop ended, we're out of fields to look at.
204 return false;
205}
206
207SIMDJSON_PUSH_DISABLE_WARNINGS
208SIMDJSON_DISABLE_STRICT_OVERFLOW_WARNING
209simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::find_field_unordered_raw(const std::string_view key) noexcept {
217 error_code error;
218 bool has_value;
219
220 // First, we scan from that point to the end.
221 // If we don't find a match, we may loop back around, and scan from the beginning to that point.
222 token_position search_start = _json_iter->position();
223
224 // We want to know whether we need to go back to the beginning.
225 bool at_first = at_first_field();
227 // Initially, the object can be in one of a few different places:
228 //
229 // 1. At the first key:
230 //
231 // ```
232 // { "a": [ 1, 2 ], "b": [ 3, 4 ] }
233 // ^ (depth 2, index 1)
234 // ```
235 //
236 if (at_first) {
237 has_value = true;
238
239 // 2. When a previous search did not yield a value or the object is empty:
240 //
241 // ```
242 // { "a": [ 1, 2 ], "b": [ 3, 4 ] }
243 // ^ (depth 0)
244 // { }
245 // ^ (depth 0, index 2)
246 // ```
247 //
248 } else if (!is_open()) {
249
250#if SIMDJSON_DEVELOPMENT_CHECKS
251 // If we're past the end of the object, we're being iterated out of order.
252 // Note: this is not perfect detection. It's possible the user is inside some other object; if so,
253 // this object iterator will blithely scan that object for fields.
254 if (_json_iter->depth() < depth() - 1) { return OUT_OF_ORDER_ITERATION; }
255#endif
256 SIMDJSON_TRY(reset_object().get(has_value));
257 at_first = true;
258 // 3. When a previous search found a field or an iterator yielded a value:
259 //
260 // ```
261 // // When a field was not fully consumed (or not even touched at all)
262 // { "a": [ 1, 2 ], "b": [ 3, 4 ] }
263 // ^ (depth 2)
264 // // When a field was fully consumed
265 // { "a": [ 1, 2 ], "b": [ 3, 4 ] }
266 // ^ (depth 1)
267 // // When the last field was fully consumed
268 // { "a": [ 1, 2 ], "b": [ 3, 4 ] }
269 // ^ (depth 1)
270 // ```
271 //
272 } else {
273 // If someone queried a key but they not did access the value, then we are left pointing
274 // at the ':' and we need to move forward through the value... If the value was
275 // processed then skip_child() does not move the iterator (but may adjust the depth).
276 if ((error = skip_child() )) { abandon(); return error; }
277 search_start = _json_iter->position();
278 if ((error = has_next_field().get(has_value) )) { abandon(); return error; }
279#if SIMDJSON_DEVELOPMENT_CHECKS
280 if (_json_iter->start_position(_depth) != start_position()) { return OUT_OF_ORDER_ITERATION; }
281#endif
282 }
283
284 // After initial processing, we will be in one of two states:
285 //
286 // ```
287 // // At the beginning of a field
288 // { "a": [ 1, 2 ], "b": [ 3, 4 ] }
289 // ^ (depth 1)
290 // { "a": [ 1, 2 ], "b": [ 3, 4 ] }
291 // ^ (depth 1)
292 // // At the end of the object
293 // { "a": [ 1, 2 ], "b": [ 3, 4 ] }
294 // ^ (depth 0)
295 // ```
296 //
297 // Next, we find a match starting from the current position.
298 while (has_value) {
299 SIMDJSON_ASSUME( _json_iter->_depth == _depth ); // We must be at the start of a field
300
301 // Get the key and colon, stopping at the value.
303 // size_t max_key_length = _json_iter->peek_length() - 2; // -2 for the two quotes
304 // Note: _json_iter->peek_length() - 2 might overflow if _json_iter->peek_length() < 2.
305 // field_key() advances the pointer and checks that '"' is found (corresponding to a key).
306 // The depth is left unchanged by field_key().
307 if ((error = field_key().get(actual_key) )) { abandon(); return error; };
308 // field_value() will advance and check that we find a ':' separating the
309 // key and the value. It will also increment the depth by one.
310 if ((error = field_value() )) { abandon(); return error; }
311
312 // If it matches, stop and return
313 // We could do it this way if we wanted to allow arbitrary
314 // key content (including escaped quotes).
315 // if (actual_key.unsafe_is_equal(max_key_length, key)) {
316 // Instead we do the following which may trigger buffer overruns if the
317 // user provides an adversarial key (containing a well placed unescaped quote
318 // character and being longer than the number of bytes remaining in the JSON
319 // input).
320 if (actual_key.unsafe_is_equal(key)) {
321 logger::log_event(*this, "match", key, -2);
322 // If we return here, then we return while pointing at the ':' that we just checked.
323 return true;
324 }
325
326 // No match: skip the value and see if , or } is next
327 logger::log_event(*this, "no match", key, -2);
328 // The call to skip_child is meant to skip over the value corresponding to the key.
329 // After skip_child(), we are right before the next comma (',') or the final brace ('}').
330 SIMDJSON_TRY( skip_child() );
331 // The has_next_field() advances the pointer and check that either ',' or '}' is found.
332 // It returns true if ',' is found, false otherwise. If anything other than ',' or '}' is found,
333 // then we are in error and we abort.
334 if ((error = has_next_field().get(has_value) )) { abandon(); return error; }
335 }
336 // Performance note: it maybe wasteful to rewind to the beginning when there might be
337 // no other query following. Indeed, it would require reskipping the whole object.
338 // Instead, you can just stay where you are. If there is a new query, there is always time
339 // to rewind.
340 if(at_first) { return false; }
341
342 // If we reach the end without finding a match, search the rest of the fields starting at the
343 // beginning of the object.
344 // (We have already run through the object before, so we've already validated its structure. We
345 // don't check errors in this bit.)
346 SIMDJSON_TRY(reset_object().get(has_value));
347 while (true) {
348 SIMDJSON_ASSUME(has_value); // we should reach search_start before ever reaching the end of the object
349 SIMDJSON_ASSUME( _json_iter->_depth == _depth ); // We must be at the start of a field
350
351 // Get the key and colon, stopping at the value.
353 // size_t max_key_length = _json_iter->peek_length() - 2; // -2 for the two quotes
354 // Note: _json_iter->peek_length() - 2 might overflow if _json_iter->peek_length() < 2.
355 // field_key() advances the pointer and checks that '"' is found (corresponding to a key).
356 // The depth is left unchanged by field_key().
357 error = field_key().get(actual_key); SIMDJSON_ASSUME(!error);
358 // field_value() will advance and check that we find a ':' separating the
359 // key and the value. It will also increment the depth by one.
360 error = field_value(); SIMDJSON_ASSUME(!error);
361
362 // If it matches, stop and return
363 // We could do it this way if we wanted to allow arbitrary
364 // key content (including escaped quotes).
365 // if (actual_key.unsafe_is_equal(max_key_length, key)) {
366 // Instead we do the following which may trigger buffer overruns if the
367 // user provides an adversarial key (containing a well placed unescaped quote
368 // character and being longer than the number of bytes remaining in the JSON
369 // input).
370 if (actual_key.unsafe_is_equal(key)) {
371 logger::log_event(*this, "match", key, -2);
372 // If we return here, then we return while pointing at the ':' that we just checked.
373 return true;
374 }
375
376 // No match: skip the value and see if , or } is next
377 logger::log_event(*this, "no match", key, -2);
378 // The call to skip_child is meant to skip over the value corresponding to the key.
379 // After skip_child(), we are right before the next comma (',') or the final brace ('}').
380 SIMDJSON_TRY( skip_child() );
381 // If we reached the end of the key-value pair we started from, then we know
382 // that the key is not there so we return false. We are either right before
383 // the next comma or the final brace.
384 if(_json_iter->position() == search_start) { return false; }
385 // The has_next_field() advances the pointer and check that either ',' or '}' is found.
386 // It returns true if ',' is found, false otherwise. If anything other than ',' or '}' is found,
387 // then we are in error and we abort.
388 error = has_next_field().get(has_value); SIMDJSON_ASSUME(!error);
389 // If we make the mistake of exiting here, then we could be left pointing at a key
390 // in the middle of an object. That's not an allowable state.
391 }
392 // If the loop ended, we're out of fields to look at. The program should
393 // never reach this point.
394 return false;
395}
396SIMDJSON_POP_DISABLE_WARNINGS
397
399 assert_at_next();
400
401 const uint8_t *key = _json_iter->return_current_and_advance();
402 if (*(key++) != '"') { return report_error(TAPE_ERROR, "Object key is not a string"); }
403 return raw_json_string(key);
404}
405
406simdjson_warn_unused simdjson_inline error_code value_iterator::field_value() noexcept {
407 assert_at_next();
408
409 if (*_json_iter->return_current_and_advance() != ':') { return report_error(TAPE_ERROR, "Missing colon in object field"); }
410 _json_iter->descend_to(depth()+1);
411 return SUCCESS;
412}
413
414simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::start_array() noexcept {
415 SIMDJSON_TRY( start_container('[', "Not an array", "array") );
416 return started_array();
417}
418
420 SIMDJSON_TRY( start_container('[', "Not an array", "array") );
421 return started_root_array();
422}
423
424inline std::string value_iterator::to_string() const noexcept {
425 auto answer = std::string("value_iterator [ depth : ") + std::to_string(_depth) + std::string(", ");
426 if(_json_iter != nullptr) { answer += _json_iter->to_string(); }
427 answer += std::string(" ]");
428 return answer;
429}
430
431simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::started_array() noexcept {
432 assert_at_container_start();
433 if (*_json_iter->peek() == ']') {
434 logger::log_value(*_json_iter, "empty array");
435 _json_iter->return_current_and_advance();
436 SIMDJSON_TRY( end_container() );
437 return false;
438 }
439 _json_iter->descend_to(depth()+1);
440#if SIMDJSON_DEVELOPMENT_CHECKS
441 _json_iter->set_start_position(_depth, start_position());
442#endif
443 return true;
444}
445
446simdjson_warn_unused simdjson_inline error_code value_iterator::check_root_array() noexcept {
447 // When in streaming mode, we cannot expect peek_last() to be the last structural element of the
448 // current document. It only works in the normal mode where we have indexed a single document.
449 // Note that adding a check for 'streaming' is not expensive since we only have at most
450 // one root element.
451 if ( ! _json_iter->streaming() ) {
452 // The following lines do not fully protect against garbage content within the
453 // array: e.g., `[1, 2] foo]`. Users concerned with garbage content should
454 // also call `at_end()` on the document instance at the end of the processing to
455 // ensure that the processing has finished at the end.
456 //
457 if (*_json_iter->peek_last() != ']') {
458 _json_iter->abandon();
459 return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "missing ] at end");
460 }
461 // If the last character is ] *and* the first gibberish character is also ']'
462 // then on-demand could accidentally go over. So we need additional checks.
463 // https://github.com/simdjson/simdjson/issues/1834
464 // Checking that the document is balanced requires a full scan which is potentially
465 // expensive, but it only happens in edge cases where the first padding character is
466 // a closing bracket.
467 if ((*_json_iter->peek(_json_iter->end_position()) == ']') && (!_json_iter->balanced())) {
468 _json_iter->abandon();
469 // The exact error would require more work. It will typically be an unclosed array.
470 return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "the document is unbalanced");
471 }
472 }
473 return SUCCESS;
474}
475
477 auto error = check_root_array();
478 if (error) { return error; }
479 return started_array();
480}
481
483 assert_at_next();
484
485 logger::log_event(*this, "has_next_element");
486 switch (*_json_iter->return_current_and_advance()) {
487 case ']':
488 logger::log_end_value(*_json_iter, "array");
489 SIMDJSON_TRY( end_container() );
490 return false;
491 case ',':
492 _json_iter->descend_to(depth()+1);
493 return true;
494 default:
495 return report_error(TAPE_ERROR, "Missing comma between array elements");
496 }
497}
498
499simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::parse_bool(const uint8_t *json) const noexcept {
500 auto not_true = atomparsing::str4ncmp(json, "true");
501 auto not_false = atomparsing::str4ncmp(json, "fals") | (json[4] ^ 'e');
502 bool error = (not_true && not_false) || jsoncharutils::is_not_structural_or_whitespace(json[not_true ? 5 : 4]);
503 if (error) { return incorrect_type_error("Not a boolean"); }
504 return simdjson_result<bool>(!not_true);
505}
506simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::parse_null(const uint8_t *json) const noexcept {
507 bool is_null_string = !atomparsing::str4ncmp(json, "null") && jsoncharutils::is_structural_or_whitespace(json[4]);
508 // if we start with 'n', we must be a null
509 if(!is_null_string && json[0]=='n') { return incorrect_type_error("Not a null but starts with n"); }
510 return is_null_string;
511}
512
513simdjson_warn_unused simdjson_inline simdjson_result<std::string_view> value_iterator::get_string(bool allow_replacement) noexcept {
514 return get_raw_json_string().unescape(json_iter(), allow_replacement);
515}
516template <typename string_type>
517simdjson_warn_unused simdjson_inline error_code value_iterator::get_string(string_type& receiver, bool allow_replacement) noexcept {
518 std::string_view content;
519 auto err = get_string(allow_replacement).get(content);
520 if (err) { return err; }
521 receiver = content;
522 return SUCCESS;
523}
524simdjson_warn_unused simdjson_inline simdjson_result<std::string_view> value_iterator::get_wobbly_string() noexcept {
525 return get_raw_json_string().unescape_wobbly(json_iter());
526}
527simdjson_warn_unused simdjson_inline simdjson_result<raw_json_string> value_iterator::get_raw_json_string() noexcept {
528 auto json = peek_scalar("string");
529 if (*json != '"') { return incorrect_type_error("Not a string"); }
530 advance_scalar("string");
531 return raw_json_string(json+1);
532}
533simdjson_warn_unused simdjson_inline simdjson_result<uint64_t> value_iterator::get_uint64() noexcept {
534 auto result = numberparsing::parse_unsigned(peek_non_root_scalar("uint64"));
535 if(result.error() == SUCCESS) { advance_non_root_scalar("uint64"); }
536 return result;
537}
538simdjson_warn_unused simdjson_inline simdjson_result<uint64_t> value_iterator::get_uint64_in_string() noexcept {
539 auto result = numberparsing::parse_unsigned_in_string(peek_non_root_scalar("uint64"));
540 if(result.error() == SUCCESS) { advance_non_root_scalar("uint64"); }
541 return result;
542}
543simdjson_warn_unused simdjson_inline simdjson_result<int64_t> value_iterator::get_int64() noexcept {
544 auto result = numberparsing::parse_integer(peek_non_root_scalar("int64"));
545 if(result.error() == SUCCESS) { advance_non_root_scalar("int64"); }
546 return result;
547}
548simdjson_warn_unused simdjson_inline simdjson_result<int64_t> value_iterator::get_int64_in_string() noexcept {
549 auto result = numberparsing::parse_integer_in_string(peek_non_root_scalar("int64"));
550 if(result.error() == SUCCESS) { advance_non_root_scalar("int64"); }
551 return result;
552}
553simdjson_warn_unused simdjson_inline simdjson_result<double> value_iterator::get_double() noexcept {
554 auto result = numberparsing::parse_double(peek_non_root_scalar("double"));
555 if(result.error() == SUCCESS) { advance_non_root_scalar("double"); }
556 return result;
557}
558simdjson_warn_unused simdjson_inline simdjson_result<double> value_iterator::get_double_in_string() noexcept {
559 auto result = numberparsing::parse_double_in_string(peek_non_root_scalar("double"));
560 if(result.error() == SUCCESS) { advance_non_root_scalar("double"); }
561 return result;
562}
563simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::get_bool() noexcept {
564 auto result = parse_bool(peek_non_root_scalar("bool"));
565 if(result.error() == SUCCESS) { advance_non_root_scalar("bool"); }
566 return result;
567}
568simdjson_inline simdjson_result<bool> value_iterator::is_null() noexcept {
569 bool is_null_value;
570 SIMDJSON_TRY(parse_null(peek_non_root_scalar("null")).get(is_null_value));
571 if(is_null_value) { advance_non_root_scalar("null"); }
572 return is_null_value;
573}
574simdjson_inline bool value_iterator::is_negative() noexcept {
575 return numberparsing::is_negative(peek_non_root_scalar("numbersign"));
576}
577simdjson_inline bool value_iterator::is_root_negative() noexcept {
578 return numberparsing::is_negative(peek_root_scalar("numbersign"));
579}
580simdjson_inline simdjson_result<bool> value_iterator::is_integer() noexcept {
581 return numberparsing::is_integer(peek_non_root_scalar("integer"));
582}
583simdjson_inline simdjson_result<number_type> value_iterator::get_number_type() noexcept {
584 return numberparsing::get_number_type(peek_non_root_scalar("integer"));
585}
586simdjson_inline simdjson_result<number> value_iterator::get_number() noexcept {
587 number num;
588 error_code error = numberparsing::parse_number(peek_non_root_scalar("number"), num);
589 if(error) { return error; }
590 return num;
591}
592
593simdjson_inline simdjson_result<bool> value_iterator::is_root_integer(bool check_trailing) noexcept {
594 auto max_len = peek_root_length();
595 auto json = peek_root_scalar("is_root_integer");
596 uint8_t tmpbuf[20+1+1]{}; // <20 digits> is the longest possible unsigned integer
597 tmpbuf[20+1] = '\0'; // make sure that buffer is always null terminated.
598 if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 20+1)) {
599 return false; // if there are more than 20 characters, it cannot be represented as an integer.
600 }
601 auto answer = numberparsing::is_integer(tmpbuf);
602 // If the parsing was a success, we must still check that it is
603 // a single scalar. Note that we parse first because of cases like '[]' where
604 // getting TRAILING_CONTENT is wrong.
605 if(check_trailing && (answer.error() == SUCCESS) && (!_json_iter->is_single_token())) { return TRAILING_CONTENT; }
606 return answer;
607}
608
609simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::number_type> value_iterator::get_root_number_type(bool check_trailing) noexcept {
610 auto max_len = peek_root_length();
611 auto json = peek_root_scalar("number");
612 // Per https://www.exploringbinary.com/maximum-number-of-decimal-digits-in-binary-floating-point-numbers/,
613 // 1074 is the maximum number of significant fractional digits. Add 8 more digits for the biggest
614 // number: -0.<fraction>e-308.
615 uint8_t tmpbuf[1074+8+1+1];
616 tmpbuf[1074+8+1] = '\0'; // make sure that buffer is always null terminated.
617 if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 1074+8+1)) {
618 if(numberparsing::check_if_integer(json, max_len)) {
619 if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
620 logger::log_error(*_json_iter, start_position(), depth(), "Found big integer");
621 return number_type::big_integer;
622 }
623 logger::log_error(*_json_iter, start_position(), depth(), "Root number more than 1082 characters and not a big integer");
624 return NUMBER_ERROR;
625 }
626 auto answer = numberparsing::get_number_type(tmpbuf);
627 if (check_trailing && (answer.error() == SUCCESS) && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
628 return answer;
629}
630simdjson_inline simdjson_result<number> value_iterator::get_root_number(bool check_trailing) noexcept {
631 auto max_len = peek_root_length();
632 auto json = peek_root_scalar("number");
633 // Per https://www.exploringbinary.com/maximum-number-of-decimal-digits-in-binary-floating-point-numbers/,
634 // 1074 is the maximum number of significant fractional digits. Add 8 more digits for the biggest
635 // number: -0.<fraction>e-308.
636 // NOTE: the current approach doesn't work for very big integer numbers containing more than 1074 digits.
637 uint8_t tmpbuf[1074+8+1+1];
638 tmpbuf[1074+8+1] = '\0'; // make sure that buffer is always null terminated.
639 if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 1074+8+1)) {
640 if(numberparsing::check_if_integer(json, max_len)) {
641 if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
642 logger::log_error(*_json_iter, start_position(), depth(), "Found big integer");
643 return BIGINT_ERROR;
644 }
645 logger::log_error(*_json_iter, start_position(), depth(), "Root number more than 1082 characters and not a big integer");
646 return NUMBER_ERROR;
647 }
648 number num;
649 error_code error = numberparsing::parse_number(tmpbuf, num);
650 if(error) { return error; }
651 if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
652 advance_root_scalar("number");
653 return num;
654}
655simdjson_warn_unused simdjson_inline simdjson_result<std::string_view> value_iterator::get_root_string(bool check_trailing, bool allow_replacement) noexcept {
656 return get_root_raw_json_string(check_trailing).unescape(json_iter(), allow_replacement);
657}
658template <typename string_type>
659simdjson_warn_unused simdjson_inline error_code value_iterator::get_root_string(string_type& receiver, bool check_trailing, bool allow_replacement) noexcept {
660 std::string_view content;
661 auto err = get_root_string(check_trailing, allow_replacement).get(content);
662 if (err) { return err; }
663 receiver = content;
664 return SUCCESS;
665}
666simdjson_warn_unused simdjson_inline simdjson_result<std::string_view> value_iterator::get_root_wobbly_string(bool check_trailing) noexcept {
667 return get_root_raw_json_string(check_trailing).unescape_wobbly(json_iter());
668}
669simdjson_warn_unused simdjson_inline simdjson_result<raw_json_string> value_iterator::get_root_raw_json_string(bool check_trailing) noexcept {
670 auto json = peek_scalar("string");
671 if (*json != '"') { return incorrect_type_error("Not a string"); }
672 if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
673 advance_scalar("string");
674 return raw_json_string(json+1);
675}
676simdjson_warn_unused simdjson_inline simdjson_result<uint64_t> value_iterator::get_root_uint64(bool check_trailing) noexcept {
677 auto max_len = peek_root_length();
678 auto json = peek_root_scalar("uint64");
679 uint8_t tmpbuf[20+1+1]{}; // <20 digits> is the longest possible unsigned integer
680 tmpbuf[20+1] = '\0'; // make sure that buffer is always null terminated.
681 if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 20+1)) {
682 logger::log_error(*_json_iter, start_position(), depth(), "Root number more than 20 characters");
683 return NUMBER_ERROR;
684 }
685 auto result = numberparsing::parse_unsigned(tmpbuf);
686 if(result.error() == SUCCESS) {
687 if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
688 advance_root_scalar("uint64");
689 }
690 return result;
691}
692simdjson_warn_unused simdjson_inline simdjson_result<uint64_t> value_iterator::get_root_uint64_in_string(bool check_trailing) noexcept {
693 auto max_len = peek_root_length();
694 auto json = peek_root_scalar("uint64");
695 uint8_t tmpbuf[20+1+1]{}; // <20 digits> is the longest possible unsigned integer
696 tmpbuf[20+1] = '\0'; // make sure that buffer is always null terminated.
697 if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 20+1)) {
698 logger::log_error(*_json_iter, start_position(), depth(), "Root number more than 20 characters");
699 return NUMBER_ERROR;
700 }
701 auto result = numberparsing::parse_unsigned_in_string(tmpbuf);
702 if(result.error() == SUCCESS) {
703 if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
704 advance_root_scalar("uint64");
705 }
706 return result;
707}
708simdjson_warn_unused simdjson_inline simdjson_result<int64_t> value_iterator::get_root_int64(bool check_trailing) noexcept {
709 auto max_len = peek_root_length();
710 auto json = peek_root_scalar("int64");
711 uint8_t tmpbuf[20+1+1]; // -<19 digits> is the longest possible integer
712 tmpbuf[20+1] = '\0'; // make sure that buffer is always null terminated.
713 if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 20+1)) {
714 logger::log_error(*_json_iter, start_position(), depth(), "Root number more than 20 characters");
715 return NUMBER_ERROR;
716 }
717
718 auto result = numberparsing::parse_integer(tmpbuf);
719 if(result.error() == SUCCESS) {
720 if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
721 advance_root_scalar("int64");
722 }
723 return result;
724}
725simdjson_warn_unused simdjson_inline simdjson_result<int64_t> value_iterator::get_root_int64_in_string(bool check_trailing) noexcept {
726 auto max_len = peek_root_length();
727 auto json = peek_root_scalar("int64");
728 uint8_t tmpbuf[20+1+1]; // -<19 digits> is the longest possible integer
729 tmpbuf[20+1] = '\0'; // make sure that buffer is always null terminated.
730 if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 20+1)) {
731 logger::log_error(*_json_iter, start_position(), depth(), "Root number more than 20 characters");
732 return NUMBER_ERROR;
733 }
734
735 auto result = numberparsing::parse_integer_in_string(tmpbuf);
736 if(result.error() == SUCCESS) {
737 if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
738 advance_root_scalar("int64");
739 }
740 return result;
741}
742simdjson_warn_unused simdjson_inline simdjson_result<double> value_iterator::get_root_double(bool check_trailing) noexcept {
743 auto max_len = peek_root_length();
744 auto json = peek_root_scalar("double");
745 // Per https://www.exploringbinary.com/maximum-number-of-decimal-digits-in-binary-floating-point-numbers/,
746 // 1074 is the maximum number of significant fractional digits. Add 8 more digits for the biggest
747 // number: -0.<fraction>e-308.
748 uint8_t tmpbuf[1074+8+1+1]; // +1 for null termination.
749 tmpbuf[1074+8+1] = '\0'; // make sure that buffer is always null terminated.
750 if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 1074+8+1)) {
751 logger::log_error(*_json_iter, start_position(), depth(), "Root number more than 1082 characters");
752 return NUMBER_ERROR;
753 }
754 auto result = numberparsing::parse_double(tmpbuf);
755 if(result.error() == SUCCESS) {
756 if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
757 advance_root_scalar("double");
758 }
759 return result;
760}
761
762simdjson_warn_unused simdjson_inline simdjson_result<double> value_iterator::get_root_double_in_string(bool check_trailing) noexcept {
763 auto max_len = peek_root_length();
764 auto json = peek_root_scalar("double");
765 // Per https://www.exploringbinary.com/maximum-number-of-decimal-digits-in-binary-floating-point-numbers/,
766 // 1074 is the maximum number of significant fractional digits. Add 8 more digits for the biggest
767 // number: -0.<fraction>e-308.
768 uint8_t tmpbuf[1074+8+1+1]; // +1 for null termination.
769 tmpbuf[1074+8+1] = '\0'; // make sure that buffer is always null terminated.
770 if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 1074+8+1)) {
771 logger::log_error(*_json_iter, start_position(), depth(), "Root number more than 1082 characters");
772 return NUMBER_ERROR;
773 }
774 auto result = numberparsing::parse_double_in_string(tmpbuf);
775 if(result.error() == SUCCESS) {
776 if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
777 advance_root_scalar("double");
778 }
779 return result;
780}
781
782simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::get_root_bool(bool check_trailing) noexcept {
783 auto max_len = peek_root_length();
784 auto json = peek_root_scalar("bool");
785 // We have a boolean if we have either "true" or "false" and the next character is either
786 // a structural character or whitespace. We also check that the length is correct:
787 // "true" and "false" are 4 and 5 characters long, respectively.
788 bool value_true = (max_len >= 4 && !atomparsing::str4ncmp(json, "true") &&
789 (max_len == 4 || jsoncharutils::is_structural_or_whitespace(json[4])));
790 bool value_false = (max_len >= 5 && !atomparsing::str4ncmp(json, "false") &&
791 (max_len == 5 || jsoncharutils::is_structural_or_whitespace(json[5])));
792 if(value_true == false && value_false == false) { return incorrect_type_error("Not a boolean"); }
793 if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
794 advance_root_scalar("bool");
795 return value_true;
796}
797
798simdjson_inline simdjson_result<bool> value_iterator::is_root_null(bool check_trailing) noexcept {
799 auto max_len = peek_root_length();
800 auto json = peek_root_scalar("null");
801 bool result = (max_len >= 4 && !atomparsing::str4ncmp(json, "null") &&
802 (max_len == 4 || jsoncharutils::is_structural_or_whitespace(json[4])));
803 if(result) { // we have something that looks like a null.
804 if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
805 advance_root_scalar("null");
806 } else if (json[0] == 'n') {
807 return incorrect_type_error("Not a null but starts with n");
808 }
809 return result;
810}
811
812simdjson_warn_unused simdjson_inline error_code value_iterator::skip_child() noexcept {
813 SIMDJSON_ASSUME( _json_iter->token._position > _start_position );
814 SIMDJSON_ASSUME( _json_iter->_depth >= _depth );
815
816 return _json_iter->skip_child(depth());
817}
818
819simdjson_inline value_iterator value_iterator::child() const noexcept {
820 assert_at_child();
821 return { _json_iter, depth()+1, _json_iter->token.position() };
822}
823
824// GCC 7 warns when the first line of this function is inlined away into oblivion due to the caller
825// relating depth and iterator depth, which is a desired effect. It does not happen if is_open is
826// marked non-inline.
827SIMDJSON_PUSH_DISABLE_WARNINGS
828SIMDJSON_DISABLE_STRICT_OVERFLOW_WARNING
829simdjson_inline bool value_iterator::is_open() const noexcept {
830 return _json_iter->depth() >= depth();
831}
832SIMDJSON_POP_DISABLE_WARNINGS
833
834simdjson_inline bool value_iterator::at_end() const noexcept {
835 return _json_iter->at_end();
836}
837
838simdjson_inline bool value_iterator::at_start() const noexcept {
839 return _json_iter->token.position() == start_position();
840}
841
842simdjson_inline bool value_iterator::at_first_field() const noexcept {
843 SIMDJSON_ASSUME( _json_iter->token._position > _start_position );
844 return _json_iter->token.position() == start_position() + 1;
845}
846
847simdjson_inline void value_iterator::abandon() noexcept {
848 _json_iter->abandon();
849}
850
851simdjson_warn_unused simdjson_inline depth_t value_iterator::depth() const noexcept {
852 return _depth;
853}
854simdjson_warn_unused simdjson_inline error_code value_iterator::error() const noexcept {
855 return _json_iter->error;
856}
857simdjson_warn_unused simdjson_inline uint8_t *&value_iterator::string_buf_loc() noexcept {
858 return _json_iter->string_buf_loc();
859}
860simdjson_warn_unused simdjson_inline const json_iterator &value_iterator::json_iter() const noexcept {
861 return *_json_iter;
862}
863simdjson_warn_unused simdjson_inline json_iterator &value_iterator::json_iter() noexcept {
864 return *_json_iter;
865}
866
867simdjson_inline const uint8_t *value_iterator::peek_start() const noexcept {
868 return _json_iter->peek(start_position());
869}
870simdjson_inline uint32_t value_iterator::peek_start_length() const noexcept {
871 return _json_iter->peek_length(start_position());
872}
873simdjson_inline uint32_t value_iterator::peek_root_length() const noexcept {
874 return _json_iter->peek_root_length(start_position());
875}
876
877simdjson_inline const uint8_t *value_iterator::peek_scalar(const char *type) noexcept {
878 logger::log_value(*_json_iter, start_position(), depth(), type);
879 // If we're not at the position anymore, we don't want to advance the cursor.
880 if (!is_at_start()) { return peek_start(); }
881
882 // Get the JSON and advance the cursor, decreasing depth to signify that we have retrieved the value.
883 assert_at_start();
884 return _json_iter->peek();
885}
886
887simdjson_inline void value_iterator::advance_scalar(const char *type) noexcept {
888 logger::log_value(*_json_iter, start_position(), depth(), type);
889 // If we're not at the position anymore, we don't want to advance the cursor.
890 if (!is_at_start()) { return; }
891
892 // Get the JSON and advance the cursor, decreasing depth to signify that we have retrieved the value.
893 assert_at_start();
894 _json_iter->return_current_and_advance();
895 _json_iter->ascend_to(depth()-1);
896}
897
898simdjson_warn_unused simdjson_inline error_code value_iterator::start_container(uint8_t start_char, const char *incorrect_type_message, const char *type) noexcept {
899 logger::log_start_value(*_json_iter, start_position(), depth(), type);
900 // If we're not at the position anymore, we don't want to advance the cursor.
901 const uint8_t *json;
902 if (!is_at_start()) {
903#if SIMDJSON_DEVELOPMENT_CHECKS
904 if (!is_at_iterator_start()) { return OUT_OF_ORDER_ITERATION; }
905#endif
906 json = peek_start();
907 if (*json != start_char) { return incorrect_type_error(incorrect_type_message); }
908 } else {
909 assert_at_start();
915 json = _json_iter->peek();
916 if (*json != start_char) { return incorrect_type_error(incorrect_type_message); }
917 _json_iter->return_current_and_advance();
918 }
919
920
921 return SUCCESS;
922}
923
924
925simdjson_inline const uint8_t *value_iterator::peek_root_scalar(const char *type) noexcept {
926 logger::log_value(*_json_iter, start_position(), depth(), type);
927 if (!is_at_start()) { return peek_start(); }
928
929 assert_at_root();
930 return _json_iter->peek();
931}
932simdjson_inline const uint8_t *value_iterator::peek_non_root_scalar(const char *type) noexcept {
933 logger::log_value(*_json_iter, start_position(), depth(), type);
934 if (!is_at_start()) { return peek_start(); }
935
936 assert_at_non_root_start();
937 return _json_iter->peek();
938}
939
940simdjson_inline void value_iterator::advance_root_scalar(const char *type) noexcept {
941 logger::log_value(*_json_iter, start_position(), depth(), type);
942 if (!is_at_start()) { return; }
943
944 assert_at_root();
945 _json_iter->return_current_and_advance();
946 _json_iter->ascend_to(depth()-1);
947}
948simdjson_inline void value_iterator::advance_non_root_scalar(const char *type) noexcept {
949 logger::log_value(*_json_iter, start_position(), depth(), type);
950 if (!is_at_start()) { return; }
951
952 assert_at_non_root_start();
953 _json_iter->return_current_and_advance();
954 _json_iter->ascend_to(depth()-1);
955}
956
957simdjson_inline error_code value_iterator::incorrect_type_error(const char *message) const noexcept {
958 logger::log_error(*_json_iter, start_position(), depth(), message);
959 return INCORRECT_TYPE;
960}
961
962simdjson_inline bool value_iterator::is_at_start() const noexcept {
963 return position() == start_position();
964}
965
966simdjson_inline bool value_iterator::is_at_key() const noexcept {
967 // Keys are at the same depth as the object.
968 // Note here that we could be safer and check that we are within an object,
969 // but we do not.
970 return _depth == _json_iter->_depth && *_json_iter->peek() == '"';
971}
972
973simdjson_inline bool value_iterator::is_at_iterator_start() const noexcept {
974 // We can legitimately be either at the first value ([1]), or after the array if it's empty ([]).
975 auto delta = position() - start_position();
976 return delta == 1 || delta == 2;
977}
978
979inline void value_iterator::assert_at_start() const noexcept {
980 SIMDJSON_ASSUME( _json_iter->token._position == _start_position );
981 SIMDJSON_ASSUME( _json_iter->_depth == _depth );
982 SIMDJSON_ASSUME( _depth > 0 );
983}
984
985inline void value_iterator::assert_at_container_start() const noexcept {
986 SIMDJSON_ASSUME( _json_iter->token._position == _start_position + 1 );
987 SIMDJSON_ASSUME( _json_iter->_depth == _depth );
988 SIMDJSON_ASSUME( _depth > 0 );
989}
990
991inline void value_iterator::assert_at_next() const noexcept {
992 SIMDJSON_ASSUME( _json_iter->token._position > _start_position );
993 SIMDJSON_ASSUME( _json_iter->_depth == _depth );
994 SIMDJSON_ASSUME( _depth > 0 );
995}
996
997simdjson_inline void value_iterator::move_at_start() noexcept {
998 _json_iter->_depth = _depth;
999 _json_iter->token.set_position(_start_position);
1000}
1001
1002simdjson_inline void value_iterator::move_at_container_start() noexcept {
1003 _json_iter->_depth = _depth;
1004 _json_iter->token.set_position(_start_position + 1);
1005}
1006
1007simdjson_inline simdjson_result<bool> value_iterator::reset_array() noexcept {
1008 if(error()) { return error(); }
1009 move_at_container_start();
1010 return started_array();
1011}
1012
1013simdjson_inline simdjson_result<bool> value_iterator::reset_object() noexcept {
1014 if(error()) { return error(); }
1015 move_at_container_start();
1016 return started_object();
1017}
1018
1019inline void value_iterator::assert_at_child() const noexcept {
1020 SIMDJSON_ASSUME( _json_iter->token._position > _start_position );
1021 SIMDJSON_ASSUME( _json_iter->_depth == _depth + 1 );
1022 SIMDJSON_ASSUME( _depth > 0 );
1023}
1024
1025inline void value_iterator::assert_at_root() const noexcept {
1026 assert_at_start();
1027 SIMDJSON_ASSUME( _depth == 1 );
1028}
1029
1030inline void value_iterator::assert_at_non_root_start() const noexcept {
1031 assert_at_start();
1032 SIMDJSON_ASSUME( _depth > 1 );
1033}
1034
1035inline void value_iterator::assert_is_valid() const noexcept {
1036 SIMDJSON_ASSUME( _json_iter != nullptr );
1037}
1038
1039simdjson_inline bool value_iterator::is_valid() const noexcept {
1040 return _json_iter != nullptr;
1041}
1042
1043simdjson_inline simdjson_result<json_type> value_iterator::type() const noexcept {
1044 switch (*peek_start()) {
1045 case '{':
1046 return json_type::object;
1047 case '[':
1048 return json_type::array;
1049 case '"':
1050 return json_type::string;
1051 case 'n':
1052 return json_type::null;
1053 case 't': case 'f':
1054 return json_type::boolean;
1055 case '-':
1056 case '0': case '1': case '2': case '3': case '4':
1057 case '5': case '6': case '7': case '8': case '9':
1058 return json_type::number;
1059 default:
1060 return json_type::unknown;
1061 }
1062}
1063
1064simdjson_inline token_position value_iterator::start_position() const noexcept {
1065 return _start_position;
1066}
1067
1068simdjson_inline token_position value_iterator::position() const noexcept {
1069 return _json_iter->position();
1070}
1071
1072simdjson_inline token_position value_iterator::end_position() const noexcept {
1073 return _json_iter->end_position();
1074}
1075
1076simdjson_inline token_position value_iterator::last_position() const noexcept {
1077 return _json_iter->last_position();
1078}
1079
1080simdjson_inline error_code value_iterator::report_error(error_code error, const char *message) noexcept {
1081 return _json_iter->report_error(error, message);
1082}
1083
1084} // namespace ondemand
1085} // namespace SIMDJSON_IMPLEMENTATION
1086} // namespace simdjson
1087
1088namespace simdjson {
1089
1090simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value_iterator>::simdjson_result(SIMDJSON_IMPLEMENTATION::ondemand::value_iterator &&value) noexcept
1091 : implementation_simdjson_result_base<SIMDJSON_IMPLEMENTATION::ondemand::value_iterator>(std::forward<SIMDJSON_IMPLEMENTATION::ondemand::value_iterator>(value)) {}
1092simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value_iterator>::simdjson_result(error_code error) noexcept
1093 : implementation_simdjson_result_base<SIMDJSON_IMPLEMENTATION::ondemand::value_iterator>(error) {}
1094
1095} // namespace simdjson
1096
1097#endif // SIMDJSON_GENERIC_ONDEMAND_VALUE_ITERATOR_INL_H
A string escaped per JSON rules, terminated with quote (").
simdjson_warn_unused simdjson_inline simdjson_result< bool > started_array() noexcept
Start an array iteration, after the user has already checked and moved past the [.
simdjson_warn_unused simdjson_inline simdjson_result< bool > start_array() noexcept
Check for an opening [ and start an array iteration.
simdjson_warn_unused simdjson_inline error_code check_root_array() noexcept
Checks whether an array could be started from the root.
simdjson_warn_unused simdjson_inline simdjson_result< bool > has_next_element() noexcept
Moves to the next element in an array.
simdjson_warn_unused simdjson_inline simdjson_result< bool > start_root_array() noexcept
Check for an opening [ and start an array iteration while at the root.
simdjson_warn_unused simdjson_inline simdjson_result< bool > started_root_array() noexcept
Start an array iteration from the root, after the user has already checked and moved past the [.
simdjson_warn_unused simdjson_inline value_iterator child() const noexcept
Get a child value iterator.
simdjson_warn_unused simdjson_inline simdjson_result< bool > started_object() noexcept
Start an object iteration after the user has already checked and moved past the {.
simdjson_warn_unused simdjson_inline error_code check_root_object() noexcept
Checks whether an object could be started from the root.
simdjson_warn_unused simdjson_inline simdjson_result< bool > start_object() noexcept
Start an object iteration.
simdjson_warn_unused simdjson_inline simdjson_result< bool > find_field_unordered_raw(const std::string_view key) noexcept
Find the field with the given key without regard to order, and without unescaping.
simdjson_warn_unused simdjson_inline simdjson_result< bool > has_next_field() noexcept
Moves to the next field in an object.
simdjson_warn_unused simdjson_inline simdjson_result< raw_json_string > field_key() noexcept
Get the current field's key.
simdjson_warn_unused simdjson_inline simdjson_result< bool > started_root_object() noexcept
Start an object iteration from the root, after the user has already checked and moved past the {.
simdjson_warn_unused simdjson_inline error_code field_value() noexcept
Pass the : in the field and move to its value.
simdjson_warn_unused simdjson_inline simdjson_result< bool > find_field_raw(const std::string_view key) noexcept
Find the next field with the given key, without unescaping.
simdjson_warn_unused simdjson_inline simdjson_result< bool > start_root_object() noexcept
Start an object iteration from the root.
@ object
A JSON object ( { "a": 1, "b" 2, ... } )
@ number
A JSON number ( 1 or -2.3 or 4.5e6 ...)
@ string
A JSON string ( "a" or "hello world\n" ...)
int32_t depth_t
Represents the depth of a JSON value (number of nested arrays/objects).
Definition base.h:18
The top level simdjson namespace, containing everything the library provides.
Definition base.h:8
error_code
All possible errors returned by simdjson.
Definition error.h:19
@ INCORRECT_TYPE
JSON element has a different type than user expected.
Definition error.h:37
@ OUT_OF_ORDER_ITERATION
tried to iterate an array or object out of order (checked when SIMDJSON_DEVELOPMENT_CHECKS=1)
Definition error.h:46
@ TAPE_ERROR
Something went wrong, this is a generic error. Fatal/unrecoverable error.
Definition error.h:23
@ SUCCESS
No error.
Definition error.h:20
@ TRAILING_CONTENT
Unexpected trailing content in the JSON input.
Definition error.h:51
@ INCOMPLETE_ARRAY_OR_OBJECT
The document ends early. Fatal/unrecoverable error.
Definition error.h:48
@ NUMBER_ERROR
Problem while parsing a number.
Definition error.h:29
@ BIGINT_ERROR
The integer value exceeds 64 bits.
Definition error.h:30
The result of a simdjson operation that could fail.
Definition error.h:278