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