1 namespace simdjson {
2 namespace SIMDJSON_IMPLEMENTATION {
3 namespace ondemand {
4
json_iterator(json_iterator && other)5 simdjson_really_inline json_iterator::json_iterator(json_iterator &&other) noexcept
6 : token(std::forward<token_iterator>(other.token)),
7 parser{other.parser},
8 _string_buf_loc{other._string_buf_loc},
9 error{other.error},
10 _depth{other._depth},
11 _root{other._root},
12 _streaming{other._streaming}
13 {
14 other.parser = nullptr;
15 }
16 simdjson_really_inline json_iterator &json_iterator::operator=(json_iterator &&other) noexcept {
17 token = other.token;
18 parser = other.parser;
19 _string_buf_loc = other._string_buf_loc;
20 error = other.error;
21 _depth = other._depth;
22 _root = other._root;
23 _streaming = other._streaming;
24 other.parser = nullptr;
25 return *this;
26 }
27
json_iterator(const uint8_t * buf,ondemand::parser * _parser)28 simdjson_really_inline json_iterator::json_iterator(const uint8_t *buf, ondemand::parser *_parser) noexcept
29 : token(buf, &_parser->implementation->structural_indexes[0]),
30 parser{_parser},
31 _string_buf_loc{parser->string_buf.get()},
32 _depth{1},
33 _root{parser->implementation->structural_indexes.get()},
34 _streaming{false}
35
36 {
37 logger::log_headers();
38 #if SIMDJSON_CHECK_EOF
39 assert_more_tokens();
40 #endif
41 }
42
rewind()43 inline void json_iterator::rewind() noexcept {
44 token.set_position( root_position() );
45 logger::log_headers(); // We start again
46 _string_buf_loc = parser->string_buf.get();
47 _depth = 1;
48 }
49
50 // GCC 7 warns when the first line of this function is inlined away into oblivion due to the caller
51 // relating depth and parent_depth, which is a desired effect. The warning does not show up if the
52 // skip_child() function is not marked inline).
53 SIMDJSON_PUSH_DISABLE_WARNINGS
54 SIMDJSON_DISABLE_STRICT_OVERFLOW_WARNING
skip_child(depth_t parent_depth)55 simdjson_warn_unused simdjson_really_inline error_code json_iterator::skip_child(depth_t parent_depth) noexcept {
56 /***
57 * WARNING:
58 * Inside an object, a string value is a depth of +1 compared to the object. Yet a key
59 * is at the same depth as the object.
60 * But json_iterator cannot easily tell whether we are pointing at a key or a string value.
61 * Instead, it assumes that if you are pointing at a string, then it is a value, not a key.
62 * To be clear...
63 * the following code assumes that we are *not* pointing at a key. If we are then a bug
64 * will follow. Unfortunately, it is not possible for the json_iterator its to make this
65 * check.
66 */
67 if (depth() <= parent_depth) { return SUCCESS; }
68 switch (*return_current_and_advance()) {
69 // TODO consider whether matching braces is a requirement: if non-matching braces indicates
70 // *missing* braces, then future lookups are not in the object/arrays they think they are,
71 // violating the rule "validate enough structure that the user can be confident they are
72 // looking at the right values."
73 // PERF TODO we can eliminate the switch here with a lookup of how much to add to depth
74
75 // For the first open array/object in a value, we've already incremented depth, so keep it the same
76 // We never stop at colon, but if we did, it wouldn't affect depth
77 case '[': case '{': case ':':
78 logger::log_start_value(*this, "skip");
79 break;
80 // If there is a comma, we have just finished a value in an array/object, and need to get back in
81 case ',':
82 logger::log_value(*this, "skip");
83 break;
84 // ] or } means we just finished a value and need to jump out of the array/object
85 case ']': case '}':
86 logger::log_end_value(*this, "skip");
87 _depth--;
88 if (depth() <= parent_depth) { return SUCCESS; }
89 #if SIMDJSON_CHECK_EOF
90 // If there are no more tokens, the parent is incomplete.
91 if (at_end()) { return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "Missing [ or { at start"); }
92 #endif // SIMDJSON_CHECK_EOF
93 break;
94 /*case '"':
95 if(*peek() == ':') {
96 // we are at a key!!! This is
97 // only possible if someone searched
98 // for a key in an object and the key
99 // was not found but our code then
100 // decided the consume the separating
101 // comma before returning.
102 logger::log_value(*this, "key");
103 advance(); // eat up the ':'
104 break; // important!!!
105 }
106 simdjson_fallthrough;*/
107 // Anything else must be a scalar value
108 default:
109 // For the first scalar, we will have incremented depth already, so we decrement it here.
110 logger::log_value(*this, "skip");
111 _depth--;
112 if (depth() <= parent_depth) { return SUCCESS; }
113 break;
114 }
115
116 // Now that we've considered the first value, we only increment/decrement for arrays/objects
117 while (position() < end_position()) {
118 switch (*return_current_and_advance()) {
119 case '[': case '{':
120 logger::log_start_value(*this, "skip");
121 _depth++;
122 break;
123 // TODO consider whether matching braces is a requirement: if non-matching braces indicates
124 // *missing* braces, then future lookups are not in the object/arrays they think they are,
125 // violating the rule "validate enough structure that the user can be confident they are
126 // looking at the right values."
127 // PERF TODO we can eliminate the switch here with a lookup of how much to add to depth
128 case ']': case '}':
129 logger::log_end_value(*this, "skip");
130 _depth--;
131 if (depth() <= parent_depth) { return SUCCESS; }
132 break;
133 default:
134 logger::log_value(*this, "skip", "");
135 break;
136 }
137 }
138
139 return report_error(TAPE_ERROR, "not enough close braces");
140 }
141
142 SIMDJSON_POP_DISABLE_WARNINGS
143
at_root()144 simdjson_really_inline bool json_iterator::at_root() const noexcept {
145 return position() == root_position();
146 }
147
streaming()148 simdjson_really_inline bool json_iterator::streaming() const noexcept {
149 return _streaming;
150 }
151
root_position()152 simdjson_really_inline token_position json_iterator::root_position() const noexcept {
153 return _root;
154 }
155
assert_at_document_depth()156 simdjson_really_inline void json_iterator::assert_at_document_depth() const noexcept {
157 SIMDJSON_ASSUME( _depth == 1 );
158 }
159
assert_at_root()160 simdjson_really_inline void json_iterator::assert_at_root() const noexcept {
161 SIMDJSON_ASSUME( _depth == 1 );
162 #ifndef SIMDJSON_CLANG_VISUAL_STUDIO
163 // Under Visual Studio, the next SIMDJSON_ASSUME fails with: the argument
164 // has side effects that will be discarded.
165 SIMDJSON_ASSUME( token.position() == _root );
166 #endif
167 }
168
assert_more_tokens(uint32_t required_tokens)169 simdjson_really_inline void json_iterator::assert_more_tokens(uint32_t required_tokens) const noexcept {
170 assert_valid_position(token._position + required_tokens - 1);
171 }
172
assert_valid_position(token_position position)173 simdjson_really_inline void json_iterator::assert_valid_position(token_position position) const noexcept {
174 #ifndef SIMDJSON_CLANG_VISUAL_STUDIO
175 SIMDJSON_ASSUME( position >= &parser->implementation->structural_indexes[0] );
176 SIMDJSON_ASSUME( position < &parser->implementation->structural_indexes[parser->implementation->n_structural_indexes] );
177 #endif
178 }
179
at_end()180 simdjson_really_inline bool json_iterator::at_end() const noexcept {
181 return position() == end_position();
182 }
end_position()183 simdjson_really_inline token_position json_iterator::end_position() const noexcept {
184 uint32_t n_structural_indexes{parser->implementation->n_structural_indexes};
185 return &parser->implementation->structural_indexes[n_structural_indexes];
186 }
187
to_string()188 inline std::string json_iterator::to_string() const noexcept {
189 if( !is_alive() ) { return "dead json_iterator instance"; }
190 const char * current_structural = reinterpret_cast<const char *>(token.peek());
191 return std::string("json_iterator [ depth : ") + std::to_string(_depth)
192 + std::string(", structural : '") + std::string(current_structural,1)
193 + std::string("', offset : ") + std::to_string(token.current_offset())
194 + std::string("', error : ") + error_message(error)
195 + std::string(" ]");
196 }
197
current_location()198 inline simdjson_result<const char *> json_iterator::current_location() noexcept {
199 if (!is_alive()) { // Unrecoverable error
200 if (!at_root()) {
201 return reinterpret_cast<const char *>(token.peek(-1));
202 } else {
203 return reinterpret_cast<const char *>(token.peek());
204 }
205 }
206 if (at_end()) {
207 return OUT_OF_BOUNDS;
208 }
209 return reinterpret_cast<const char *>(token.peek());
210 }
211
is_alive()212 simdjson_really_inline bool json_iterator::is_alive() const noexcept {
213 return parser;
214 }
215
abandon()216 simdjson_really_inline void json_iterator::abandon() noexcept {
217 parser = nullptr;
218 _depth = 0;
219 }
220
return_current_and_advance()221 simdjson_really_inline const uint8_t *json_iterator::return_current_and_advance() noexcept {
222 #if SIMDJSON_CHECK_EOF
223 assert_more_tokens();
224 #endif // SIMDJSON_CHECK_EOF
225 return token.return_current_and_advance();
226 }
227
unsafe_pointer()228 simdjson_really_inline const uint8_t *json_iterator::unsafe_pointer() const noexcept {
229 // deliberately done without safety guard:
230 return token.peek(0);
231 }
232
peek(int32_t delta)233 simdjson_really_inline const uint8_t *json_iterator::peek(int32_t delta) const noexcept {
234 #if SIMDJSON_CHECK_EOF
235 assert_more_tokens(delta+1);
236 #endif // SIMDJSON_CHECK_EOF
237 return token.peek(delta);
238 }
239
peek_length(int32_t delta)240 simdjson_really_inline uint32_t json_iterator::peek_length(int32_t delta) const noexcept {
241 #if SIMDJSON_CHECK_EOF
242 assert_more_tokens(delta+1);
243 #endif // #if SIMDJSON_CHECK_EOF
244 return token.peek_length(delta);
245 }
246
peek(token_position position)247 simdjson_really_inline const uint8_t *json_iterator::peek(token_position position) const noexcept {
248 // todo: currently we require end-of-string buffering, but the following
249 // assert_valid_position should be turned on if/when we lift that condition.
250 // assert_valid_position(position);
251 // This is almost surely related to SIMDJSON_CHECK_EOF but given that SIMDJSON_CHECK_EOF
252 // is ON by default, we have no choice but to disable it for real with a comment.
253 return token.peek(position);
254 }
255
peek_length(token_position position)256 simdjson_really_inline uint32_t json_iterator::peek_length(token_position position) const noexcept {
257 #if SIMDJSON_CHECK_EOF
258 assert_valid_position(position);
259 #endif // SIMDJSON_CHECK_EOF
260 return token.peek_length(position);
261 }
262
last_position()263 simdjson_really_inline token_position json_iterator::last_position() const noexcept {
264 // The following line fails under some compilers...
265 // SIMDJSON_ASSUME(parser->implementation->n_structural_indexes > 0);
266 // since it has side-effects.
267 uint32_t n_structural_indexes{parser->implementation->n_structural_indexes};
268 SIMDJSON_ASSUME(n_structural_indexes > 0);
269 return &parser->implementation->structural_indexes[n_structural_indexes - 1];
270 }
peek_last()271 simdjson_really_inline const uint8_t *json_iterator::peek_last() const noexcept {
272 return token.peek(last_position());
273 }
274
ascend_to(depth_t parent_depth)275 simdjson_really_inline void json_iterator::ascend_to(depth_t parent_depth) noexcept {
276 SIMDJSON_ASSUME(parent_depth >= 0 && parent_depth < INT32_MAX - 1);
277 SIMDJSON_ASSUME(_depth == parent_depth + 1);
278 _depth = parent_depth;
279 }
280
descend_to(depth_t child_depth)281 simdjson_really_inline void json_iterator::descend_to(depth_t child_depth) noexcept {
282 SIMDJSON_ASSUME(child_depth >= 1 && child_depth < INT32_MAX);
283 SIMDJSON_ASSUME(_depth == child_depth - 1);
284 _depth = child_depth;
285 }
286
depth()287 simdjson_really_inline depth_t json_iterator::depth() const noexcept {
288 return _depth;
289 }
290
string_buf_loc()291 simdjson_really_inline uint8_t *&json_iterator::string_buf_loc() noexcept {
292 return _string_buf_loc;
293 }
294
report_error(error_code _error,const char * message)295 simdjson_really_inline error_code json_iterator::report_error(error_code _error, const char *message) noexcept {
296 SIMDJSON_ASSUME(_error != SUCCESS && _error != UNINITIALIZED && _error != INCORRECT_TYPE && _error != NO_SUCH_FIELD);
297 logger::log_error(*this, message);
298 error = _error;
299 return error;
300 }
301
position()302 simdjson_really_inline token_position json_iterator::position() const noexcept {
303 return token.position();
304 }
305
reenter_child(token_position position,depth_t child_depth)306 simdjson_really_inline void json_iterator::reenter_child(token_position position, depth_t child_depth) noexcept {
307 SIMDJSON_ASSUME(child_depth >= 1 && child_depth < INT32_MAX);
308 SIMDJSON_ASSUME(_depth == child_depth - 1);
309 #ifdef SIMDJSON_DEVELOPMENT_CHECKS
310 #ifndef SIMDJSON_CLANG_VISUAL_STUDIO
311 SIMDJSON_ASSUME(position >= parser->start_positions[child_depth]);
312 #endif
313 #endif
314 token.set_position(position);
315 _depth = child_depth;
316 }
317
318 #ifdef SIMDJSON_DEVELOPMENT_CHECKS
319
start_position(depth_t depth)320 simdjson_really_inline token_position json_iterator::start_position(depth_t depth) const noexcept {
321 return parser->start_positions[depth];
322 }
323
set_start_position(depth_t depth,token_position position)324 simdjson_really_inline void json_iterator::set_start_position(depth_t depth, token_position position) noexcept {
325 parser->start_positions[depth] = position;
326 }
327
328 #endif
329
330
optional_error(error_code _error,const char * message)331 simdjson_really_inline error_code json_iterator::optional_error(error_code _error, const char *message) noexcept {
332 SIMDJSON_ASSUME(_error == INCORRECT_TYPE || _error == NO_SUCH_FIELD);
333 logger::log_error(*this, message);
334 return _error;
335 }
336
337 template<int N>
copy_to_buffer(const uint8_t * json,uint32_t max_len,uint8_t (& tmpbuf)[N])338 simdjson_warn_unused simdjson_really_inline bool json_iterator::copy_to_buffer(const uint8_t *json, uint32_t max_len, uint8_t (&tmpbuf)[N]) noexcept {
339 // Let us guard against silly cases:
340 if((N < max_len) || (N == 0)) { return false; }
341 // Truncate whitespace to fit the buffer.
342 if (max_len > N-1) {
343 // if (jsoncharutils::is_not_structural_or_whitespace(json[N-1])) { return false; }
344 max_len = N-1;
345 }
346
347 // Copy to the buffer.
348 std::memcpy(tmpbuf, json, max_len);
349 tmpbuf[max_len] = ' ';
350 return true;
351 }
352
353 } // namespace ondemand
354 } // namespace SIMDJSON_IMPLEMENTATION
355 } // namespace simdjson
356
357 namespace simdjson {
358
simdjson_result(SIMDJSON_IMPLEMENTATION::ondemand::json_iterator && value)359 simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::json_iterator>::simdjson_result(SIMDJSON_IMPLEMENTATION::ondemand::json_iterator &&value) noexcept
360 : implementation_simdjson_result_base<SIMDJSON_IMPLEMENTATION::ondemand::json_iterator>(std::forward<SIMDJSON_IMPLEMENTATION::ondemand::json_iterator>(value)) {}
simdjson_result(error_code error)361 simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::json_iterator>::simdjson_result(error_code error) noexcept
362 : implementation_simdjson_result_base<SIMDJSON_IMPLEMENTATION::ondemand::json_iterator>(error) {}
363
364 } // namespace simdjson