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