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