| 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 |  | 
|---|