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