Skip to content

Commit f667d49

Browse files
authored
This is a bug fix: our prev function was buggy. (simdjson#291)
1 parent 585f84a commit f667d49

File tree

2 files changed

+90
-13
lines changed

2 files changed

+90
-13
lines changed

include/simdjson/parsedjsoniterator.h

Lines changed: 20 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,9 @@ class ParsedJson::BasicIterator {
185185
// Thus, given [true, null, {"a":1}, [1,2]], we would visit ], }, null, true
186186
// when starting at the end of the scope. At the object ({) or at the array
187187
// ([), you can issue a "down" to visit their content.
188+
// Performance warning: This function is implemented by starting again
189+
// from the beginning of the scope and scanning forward. You should expect
190+
// it to be relatively slow.
188191
inline bool prev();
189192

190193
// Moves back to either the containing array or object (type { or [) from
@@ -338,22 +341,26 @@ bool ParsedJson::BasicIterator<max_depth>::move_to_index(uint32_t index) {
338341

339342
template <size_t max_depth>
340343
bool ParsedJson::BasicIterator<max_depth>::prev() {
341-
if (location - 1 < depth_index[depth].start_of_scope) {
342-
return false;
344+
size_t target_location = location;
345+
to_start_scope();
346+
size_t npos = location;
347+
if(target_location == npos) {
348+
return false; // we were already at the start
343349
}
344-
location -= 1;
345-
current_val = pj->tape[location];
346-
current_type = (current_val >> 56);
347-
if ((current_type == ']') || (current_type == '}')) {
350+
size_t oldnpos;
351+
// we have that npos < target_location here
352+
do {
353+
oldnpos = npos;
354+
if ((current_type == '[') || (current_type == '{')) {
348355
// we need to jump
349-
size_t new_location = (current_val & JSON_VALUE_MASK);
350-
if (new_location < depth_index[depth].start_of_scope) {
351-
return false; // shoud never happen
356+
npos = (current_val & JSON_VALUE_MASK);
357+
} else {
358+
npos = npos + ((current_type == 'd' || current_type == 'l') ? 2 : 1);
352359
}
353-
location = new_location;
354-
current_val = pj->tape[location];
355-
current_type = (current_val >> 56);
356-
}
360+
} while(npos < target_location);
361+
location = oldnpos;
362+
current_val = pj->tape[location];
363+
current_type = current_val >> 56;
357364
return true;
358365
}
359366

tests/basictests.cpp

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,74 @@
99

1010
#include "simdjson/jsonparser.h"
1111

12+
13+
// returns true if successful
14+
bool navigate_test() {
15+
std::string json = "{"
16+
"\"Image\": {"
17+
"\"Width\": 800,"
18+
"\"Height\": 600,"
19+
"\"Title\": \"View from 15th Floor\","
20+
"\"Thumbnail\": {"
21+
" \"Url\": \"http://www.example.com/image/481989943\","
22+
" \"Height\": 125,"
23+
" \"Width\": 100"
24+
"},"
25+
"\"Animated\" : false,"
26+
"\"IDs\": [116, 943, 234, 38793]"
27+
"}"
28+
"}";
29+
30+
simdjson::ParsedJson pj = simdjson::build_parsed_json(json);
31+
if (!pj.is_valid()) {
32+
printf("Something is wrong in navigate: %s.\n", json.c_str());
33+
return false;
34+
}
35+
simdjson::ParsedJson::Iterator pjh(pj);
36+
if(!pjh.is_object()) {
37+
printf("Root should be object\n");
38+
return false;
39+
}
40+
if(!pjh.down()) {
41+
printf("Root should not be emtpy\n");
42+
return false;
43+
}
44+
if(!pjh.is_string()) {
45+
printf("Object should start with string key\n");
46+
return false;
47+
}
48+
if(pjh.prev()) {
49+
printf("We should not be able to go back from the start of the scope.\n");
50+
return false;
51+
}
52+
if(strcmp(pjh.get_string(),"Image")!=0) {
53+
printf("There should be a single key, image.\n");
54+
return false;
55+
}
56+
pjh.move_to_value();
57+
if(!pjh.is_object()) {
58+
printf("Value of image should be object\n");
59+
return false;
60+
}
61+
if(!pjh.down()) {
62+
printf("Image key should not be emtpy\n");
63+
return false;
64+
}
65+
if(!pjh.next()) {
66+
printf("key should have a value\n");
67+
return false;
68+
}
69+
if(!pjh.prev()) {
70+
printf("We should go back to the key.\n");
71+
return false;
72+
}
73+
if(strcmp(pjh.get_string(),"Width")!=0) {
74+
printf("There should be a key Width.\n");
75+
return false;
76+
}
77+
return true;
78+
}
79+
1280
// returns true if successful
1381
bool skyprophet_test() {
1482
const size_t n_records = 100000;
@@ -68,6 +136,8 @@ bool skyprophet_test() {
68136

69137
int main() {
70138
std::cout << "Running basic tests." << std::endl;
139+
if (!navigate_test())
140+
return EXIT_FAILURE;
71141
if (!skyprophet_test())
72142
return EXIT_FAILURE;
73143
std::cout << "Basic tests are ok." << std::endl;

0 commit comments

Comments
 (0)