1namespace simdjson {
2namespace SIMDJSON_IMPLEMENTATION {
3namespace ondemand {
4
5//
6// object_iterator
7//
8
9simdjson_inline object_iterator::object_iterator(const value_iterator &_iter) noexcept
10 : iter{_iter}
11{}
12
13simdjson_inline simdjson_result<field> object_iterator::operator*() noexcept {
14 error_code error = iter.error();
15 if (error) { iter.abandon(); return error; }
16 auto result = field::start(parent_iter&: iter);
17 // TODO this is a safety rail ... users should exit loops as soon as they receive an error.
18 // Nonetheless, let's see if performance is OK with this if statement--the compiler may give it to us for free.
19 if (result.error()) { iter.abandon(); }
20 return result;
21}
22simdjson_inline bool object_iterator::operator==(const object_iterator &other) const noexcept {
23 return !(*this != other);
24}
25simdjson_inline bool object_iterator::operator!=(const object_iterator &) const noexcept {
26 return iter.is_open();
27}
28
29SIMDJSON_PUSH_DISABLE_WARNINGS
30SIMDJSON_DISABLE_STRICT_OVERFLOW_WARNING
31simdjson_inline object_iterator &object_iterator::operator++() noexcept {
32 // TODO this is a safety rail ... users should exit loops as soon as they receive an error.
33 // Nonetheless, let's see if performance is OK with this if statement--the compiler may give it to us for free.
34 if (!iter.is_open()) { return *this; } // Iterator will be released if there is an error
35
36 simdjson_unused error_code error;
37 if ((error = iter.skip_child() )) { return *this; }
38
39 simdjson_unused bool has_value;
40 if ((error = iter.has_next_field().get(value&: has_value) )) { return *this; };
41 return *this;
42}
43SIMDJSON_POP_DISABLE_WARNINGS
44
45//
46// ### Live States
47//
48// While iterating or looking up values, depth >= iter.depth. at_start may vary. Error is
49// always SUCCESS:
50//
51// - Start: This is the state when the object is first found and the iterator is just past the {.
52// In this state, at_start == true.
53// - Next: After we hand a scalar value to the user, or an array/object which they then fully
54// iterate over, the iterator is at the , or } before the next value. In this state,
55// depth == iter.depth, at_start == false, and error == SUCCESS.
56// - Unfinished Business: When we hand an array/object to the user which they do not fully
57// iterate over, we need to finish that iteration by skipping child values until we reach the
58// Next state. In this state, depth > iter.depth, at_start == false, and error == SUCCESS.
59//
60// ## Error States
61//
62// In error states, we will yield exactly one more value before stopping. iter.depth == depth
63// and at_start is always false. We decrement after yielding the error, moving to the Finished
64// state.
65//
66// - Chained Error: When the object iterator is part of an error chain--for example, in
67// `for (auto tweet : doc["tweets"])`, where the tweet field may be missing or not be an
68// object--we yield that error in the loop, exactly once. In this state, error != SUCCESS and
69// iter.depth == depth, and at_start == false. We decrement depth when we yield the error.
70// - Missing Comma Error: When the iterator ++ method discovers there is no comma between fields,
71// we flag that as an error and treat it exactly the same as a Chained Error. In this state,
72// error == TAPE_ERROR, iter.depth == depth, and at_start == false.
73//
74// Errors that occur while reading a field to give to the user (such as when the key is not a
75// string or the field is missing a colon) are yielded immediately. Depth is then decremented,
76// moving to the Finished state without transitioning through an Error state at all.
77//
78// ## Terminal State
79//
80// The terminal state has iter.depth < depth. at_start is always false.
81//
82// - Finished: When we have reached a }, we are finished. We signal this by decrementing depth.
83// In this state, iter.depth < depth, at_start == false, and error == SUCCESS.
84//
85
86} // namespace ondemand
87} // namespace SIMDJSON_IMPLEMENTATION
88} // namespace simdjson
89
90namespace simdjson {
91
92simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object_iterator>::simdjson_result(
93 SIMDJSON_IMPLEMENTATION::ondemand::object_iterator &&value
94) noexcept
95 : implementation_simdjson_result_base<SIMDJSON_IMPLEMENTATION::ondemand::object_iterator>(std::forward<SIMDJSON_IMPLEMENTATION::ondemand::object_iterator>(t&: value))
96{
97 first.iter.assert_is_valid();
98}
99simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object_iterator>::simdjson_result(error_code error) noexcept
100 : implementation_simdjson_result_base<SIMDJSON_IMPLEMENTATION::ondemand::object_iterator>({}, error)
101{
102}
103
104simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::field> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object_iterator>::operator*() noexcept {
105 if (error()) { return error(); }
106 return *first;
107}
108// If we're iterating and there is an error, return the error once.
109simdjson_inline bool simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object_iterator>::operator==(const simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object_iterator> &other) const noexcept {
110 if (!first.iter.is_valid()) { return !error(); }
111 return first == other.first;
112}
113// If we're iterating and there is an error, return the error once.
114simdjson_inline bool simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object_iterator>::operator!=(const simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object_iterator> &other) const noexcept {
115 if (!first.iter.is_valid()) { return error(); }
116 return first != other.first;
117}
118// Checks for ']' and ','
119simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object_iterator> &simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object_iterator>::operator++() noexcept {
120 // Clear the error if there is one, so we don't yield it twice
121 if (error()) { second = SUCCESS; return *this; }
122 ++first;
123 return *this;
124}
125
126} // namespace simdjson
127