1 #ifndef SIMDJSON_INLINE_PARSEDJSON_ITERATOR_H
2 #define SIMDJSON_INLINE_PARSEDJSON_ITERATOR_H
4 #include "simdjson/dom/parsedjson_iterator.h"
5 #include "simdjson/internal/tape_ref-inl.h"
6 #include "simdjson/internal/jsonformatutils.h"
10 #ifndef SIMDJSON_DISABLE_DEPRECATED_API
15 SIMDJSON_PUSH_DISABLE_WARNINGS
16 SIMDJSON_DISABLE_DEPRECATED_WARNING
19 simdjson_warn_unused
bool dom::parser::Iterator::is_ok()
const {
20 return location < tape_length;
24 size_t dom::parser::Iterator::get_tape_location()
const {
29 size_t dom::parser::Iterator::get_tape_length()
const {
35 size_t dom::parser::Iterator::get_depth()
const {
41 uint8_t dom::parser::Iterator::get_scope_type()
const {
42 return depth_index[depth].scope_type;
45 bool dom::parser::Iterator::move_forward() {
46 if (location + 1 >= tape_length) {
50 if ((current_type ==
'[') || (current_type ==
'{')) {
53 assert(depth < max_depth);
54 depth_index[depth].start_of_scope = location;
55 depth_index[depth].scope_type = current_type;
56 }
else if ((current_type ==
']') || (current_type ==
'}')) {
59 }
else if (is_number()) {
65 current_val = doc.tape[location];
66 current_type = uint8_t(current_val >> 56);
70 void dom::parser::Iterator::move_to_value() {
73 current_val = doc.tape[location];
74 current_type = uint8_t(current_val >> 56);
77 bool dom::parser::Iterator::move_to_key(
const char *key) {
80 const bool right_key = (strcmp(get_string(), key) == 0);
91 bool dom::parser::Iterator::move_to_key_insensitive(
95 const bool right_key = (simdjson_strcasecmp(get_string(), key) == 0);
106 bool dom::parser::Iterator::move_to_key(
const char *key,
110 bool right_key = ((get_string_length() == length) &&
111 (memcmp(get_string(), key, length) == 0));
122 bool dom::parser::Iterator::move_to_index(uint32_t index) {
125 for (; i < index; i++) {
138 bool dom::parser::Iterator::prev() {
139 size_t target_location = location;
141 size_t npos = location;
142 if (target_location == npos) {
149 if ((current_type ==
'[') || (current_type ==
'{')) {
151 npos = uint32_t(current_val);
153 npos = npos + ((current_type ==
'd' || current_type ==
'l') ? 2 : 1);
155 }
while (npos < target_location);
157 current_val = doc.tape[location];
158 current_type = uint8_t(current_val >> 56);
162 bool dom::parser::Iterator::up() {
170 current_val = doc.tape[location];
171 current_type = uint8_t(current_val >> 56);
175 bool dom::parser::Iterator::down() {
176 if (location + 1 >= tape_length) {
179 if ((current_type ==
'[') || (current_type ==
'{')) {
180 size_t npos = uint32_t(current_val);
181 if (npos == location + 2) {
185 assert(depth < max_depth);
186 location = location + 1;
187 depth_index[depth].start_of_scope = location;
188 depth_index[depth].scope_type = current_type;
189 current_val = doc.tape[location];
190 current_type = uint8_t(current_val >> 56);
196 void dom::parser::Iterator::to_start_scope() {
197 location = depth_index[depth].start_of_scope;
198 current_val = doc.tape[location];
199 current_type = uint8_t(current_val >> 56);
202 inline void dom::parser::Iterator::rewind() {
208 bool dom::parser::Iterator::next() {
210 if ((current_type ==
'[') || (current_type ==
'{')) {
212 npos = uint32_t(current_val);
214 npos = location + (is_number() ? 2 : 1);
216 uint64_t next_val = doc.tape[npos];
217 uint8_t next_type = uint8_t(next_val >> 56);
218 if ((next_type ==
']') || (next_type ==
'}')) {
222 current_val = next_val;
223 current_type = next_type;
226 dom::parser::Iterator::Iterator(
const dom::parser &pj) noexcept(
false)
229 #if SIMDJSON_EXCEPTIONS
230 if (!pj.valid) {
throw simdjson_error(pj.error); }
232 if (!pj.valid) {
return; }
235 max_depth = pj.max_depth();
236 depth_index =
new scopeindex_t[max_depth + 1];
237 depth_index[0].start_of_scope = location;
238 current_val = doc.tape[location++];
239 current_type = uint8_t(current_val >> 56);
240 depth_index[0].scope_type = current_type;
241 tape_length = size_t(current_val & internal::JSON_VALUE_MASK);
242 if (location < tape_length) {
245 current_val = doc.tape[location];
246 current_type = uint8_t(current_val >> 56);
248 assert(depth < max_depth);
249 depth_index[depth].start_of_scope = location;
250 depth_index[depth].scope_type = current_type;
253 dom::parser::Iterator::Iterator(
254 const dom::parser::Iterator &o) noexcept
258 location(o.location),
259 tape_length(o.tape_length),
260 current_type(o.current_type),
261 current_val(o.current_val)
263 depth_index =
new scopeindex_t[max_depth+1];
264 std::memcpy(depth_index, o.depth_index, (depth + 1) *
sizeof(depth_index[0]));
267 dom::parser::Iterator::~Iterator() noexcept {
268 if (depth_index) {
delete[] depth_index; }
271 bool dom::parser::Iterator::print(std::ostream &os,
bool escape_strings)
const {
275 switch (current_type) {
278 if (escape_strings) {
279 os << internal::escape_json_string(std::string_view(get_string(), get_string_length()));
283 std::copy(get_string(), get_string() + get_string_length(), std::ostream_iterator<char>(os));
291 os << get_unsigned_integer();
309 os << char(current_type);
317 bool dom::parser::Iterator::move_to(
const char *pointer,
319 char *new_pointer =
nullptr;
320 if (pointer[0] ==
'#') {
322 new_pointer =
new char[length];
323 uint32_t new_length = 0;
324 for (uint32_t i = 1; i < length; i++) {
325 if (pointer[i] ==
'%' && pointer[i + 1] ==
'x') {
330 std::stoi(std::string(&pointer[i + 2], 2),
nullptr, 16);
331 if (fragment ==
'\\' || fragment ==
'"' || (fragment <= 0x1F)) {
333 new_pointer[new_length] =
'\\';
336 new_pointer[new_length] = char(fragment);
339 }
catch (std::invalid_argument &) {
340 delete[] new_pointer;
345 new_pointer[new_length] = pointer[i];
350 pointer = new_pointer;
354 size_t depth_s = depth;
355 size_t location_s = location;
356 uint8_t current_type_s = current_type;
357 uint64_t current_val_s = current_val;
361 bool found = relative_move_to(pointer, length);
362 delete[] new_pointer;
368 location = location_s;
369 current_type = current_type_s;
370 current_val = current_val_s;
376 inline bool dom::parser::Iterator::move_to(
const std::string &pointer) {
377 return move_to(pointer.c_str(), uint32_t(pointer.length()));
380 inline int64_t dom::parser::Iterator::get_integer()
const {
381 if (location + 1 >= tape_length) {
384 return static_cast<int64_t
>(doc.tape[location + 1]);
387 inline uint64_t dom::parser::Iterator::get_unsigned_integer()
const {
388 if (location + 1 >= tape_length) {
391 return doc.tape[location + 1];
394 inline const char * dom::parser::Iterator::get_string()
const {
395 return reinterpret_cast<const char *
>(
396 doc.string_buf.get() + (current_val & internal::JSON_VALUE_MASK) +
sizeof(uint32_t));
399 inline uint32_t dom::parser::Iterator::get_string_length()
const {
402 reinterpret_cast<const char *
>(doc.string_buf.get() +
403 (current_val & internal::JSON_VALUE_MASK)),
408 inline double dom::parser::Iterator::get_double()
const {
409 if (location + 1 >= tape_length) {
410 return std::numeric_limits<double>::quiet_NaN();
414 std::memcpy(&answer, &doc.tape[location + 1],
sizeof(answer));
418 bool dom::parser::Iterator::relative_move_to(
const char *pointer,
425 if (pointer[0] !=
'/') {
431 std::string key_or_index;
435 if (is_array() && pointer[1] ==
'-') {
447 for (; offset < length; offset++) {
448 if (pointer[offset] ==
'/') {
452 if (is_array() && (pointer[offset] <
'0' || pointer[offset] >
'9')) {
457 if (pointer[offset] ==
'~') {
459 if (pointer[offset + 1] ==
'1') {
465 if (pointer[offset + 1] ==
'0') {
471 if (pointer[offset] ==
'\\') {
472 if (pointer[offset + 1] ==
'\\' || pointer[offset + 1] ==
'"' ||
473 (pointer[offset + 1] <= 0x1F)) {
474 key_or_index += pointer[offset + 1];
480 if (pointer[offset] ==
'\"') {
486 key_or_index += pointer[offset];
491 if (move_to_key(key_or_index.c_str(), uint32_t(key_or_index.length()))) {
492 found = relative_move_to(pointer + offset, length - offset);
494 }
else if (is_array()) {
495 if (key_or_index ==
"-") {
501 if ((current_type ==
'[') || (current_type ==
'{')) {
503 npos = uint32_t(current_val);
506 location + ((current_type ==
'd' || current_type ==
'l') ? 2 : 1);
509 current_val = doc.tape[npos];
510 current_type = uint8_t(current_val >> 56);
515 if (key_or_index[0] ==
'0' && key_or_index.length() > 1) {
519 if (key_or_index.length() == 0) {
523 uint32_t index = std::stoi(key_or_index);
524 if (move_to_index(index)) {
525 found = relative_move_to(pointer + offset, length - offset);
533 SIMDJSON_POP_DISABLE_WARNINGS
The top level simdjson namespace, containing everything the library provides.