simdjson 5.0.2
Ridiculously Fast JSON
Loading...
Searching...
No Matches
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
11namespace simdjson {
12namespace SIMDJSON_IMPLEMENTATION {
13namespace ondemand {
14
15//
16// object_iterator
17//
18
19simdjson_inline object_iterator::object_iterator(const value_iterator &_iter) noexcept
20 : iter{_iter}
21{}
22
23#if SIMDJSON_DEVELOPMENT_CHECKS
24simdjson_inline object_iterator::object_iterator(const value_iterator &_iter, object* _parent) noexcept
25 : parent{_parent}, iter{_iter}
26{
27 if (parent) parent->set_locked(true);
28}
29#endif
30
31#if SIMDJSON_DEVELOPMENT_CHECKS
32simdjson_inline object_iterator::~object_iterator() noexcept
33{
34 if (parent) parent->set_locked(false);
35}
36
37simdjson_inline object_iterator::object_iterator(object_iterator&& other) noexcept
38 : has_been_referenced{other.has_been_referenced},
39 parent{other.parent},
40 iter{std::move(other.iter)}
41{
42 other.parent = nullptr;
43}
44
45simdjson_inline object_iterator& object_iterator::operator=(object_iterator&& other) noexcept {
46 if (this != &other)
47 {
48 if (parent)
49 parent->set_locked(false);
50 has_been_referenced = other.has_been_referenced;
51 parent = other.parent;
52 iter = std::move(other.iter);
53
54 other.parent = nullptr;
55 }
56 return *this;
57}
58
59simdjson_inline object_iterator::object_iterator(const object_iterator& other) noexcept
60 : has_been_referenced{other.has_been_referenced},
61 parent{nullptr},
62 iter{other.iter}
63{}
64
65simdjson_inline object_iterator& object_iterator::operator=(const object_iterator& other) noexcept {
66 if (this != &other)
67 {
68 if (parent)
69 parent->set_locked(false);
70 has_been_referenced = other.has_been_referenced;
71 parent = nullptr;
72 iter = other.iter;
73 }
74 return *this;
75}
76#endif
77
78simdjson_inline simdjson_result<field> object_iterator::operator*() noexcept {
79#if SIMDJSON_DEVELOPMENT_CHECKS
80 // We must call * once per iteration.
81 SIMDJSON_ASSUME(!has_been_referenced);
82 has_been_referenced = true;
83#endif
84 error_code error = iter.error();
85 if (error) { iter.abandon(); return error; }
86 auto result = field::start(iter);
87 // TODO this is a safety rail ... users should exit loops as soon as they receive an error.
88 // Nonetheless, let's see if performance is OK with this if statement--the compiler may give it to us for free.
89 if (result.error()) { iter.abandon(); }
90 return result;
91}
92simdjson_inline bool object_iterator::operator==(const object_iterator &other) const noexcept {
93 return !(*this != other);
94}
95simdjson_inline bool object_iterator::operator!=(const object_iterator &) const noexcept {
96 return iter.is_open();
97}
98
99SIMDJSON_PUSH_DISABLE_WARNINGS
100SIMDJSON_DISABLE_STRICT_OVERFLOW_WARNING
101simdjson_inline object_iterator &object_iterator::operator++() noexcept {
102#if SIMDJSON_DEVELOPMENT_CHECKS
103 // Before calling ++, we must have called *.
104 SIMDJSON_ASSUME(has_been_referenced);
105 has_been_referenced = false;
106#endif
107 // TODO this is a safety rail ... users should exit loops as soon as they receive an error.
108 // Nonetheless, let's see if performance is OK with this if statement--the compiler may give it to us for free.
109 if (!iter.is_open()) { return *this; } // Iterator will be released if there is an error
110
111 simdjson_unused error_code error;
112 if ((error = iter.skip_child() )) { return *this; }
113
114 simdjson_unused bool has_value;
115 if ((error = iter.has_next_field().get(has_value) )) { return *this; };
116 return *this;
117}
118SIMDJSON_POP_DISABLE_WARNINGS
119
120//
121// ### Live States
122//
123// While iterating or looking up values, depth >= iter.depth. at_start may vary. Error is
124// always SUCCESS:
125//
126// - Start: This is the state when the object is first found and the iterator is just past the {.
127// In this state, at_start == true.
128// - Next: After we hand a scalar value to the user, or an array/object which they then fully
129// iterate over, the iterator is at the , or } before the next value. In this state,
130// depth == iter.depth, at_start == false, and error == SUCCESS.
131// - Unfinished Business: When we hand an array/object to the user which they do not fully
132// iterate over, we need to finish that iteration by skipping child values until we reach the
133// Next state. In this state, depth > iter.depth, at_start == false, and error == SUCCESS.
134//
135// ## Error States
136//
137// In error states, we will yield exactly one more value before stopping. iter.depth == depth
138// and at_start is always false. We decrement after yielding the error, moving to the Finished
139// state.
140//
141// - Chained Error: When the object iterator is part of an error chain--for example, in
142// `for (auto tweet : doc["tweets"])`, where the tweet field may be missing or not be an
143// object--we yield that error in the loop, exactly once. In this state, error != SUCCESS and
144// iter.depth == depth, and at_start == false. We decrement depth when we yield the error.
145// - Missing Comma Error: When the iterator ++ method discovers there is no comma between fields,
146// we flag that as an error and treat it exactly the same as a Chained Error. In this state,
147// error == TAPE_ERROR, iter.depth == depth, and at_start == false.
148//
149// Errors that occur while reading a field to give to the user (such as when the key is not a
150// string or the field is missing a colon) are yielded immediately. Depth is then decremented,
151// moving to the Finished state without transitioning through an Error state at all.
152//
153// ## Terminal State
154//
155// The terminal state has iter.depth < depth. at_start is always false.
156//
157// - Finished: When we have reached a }, we are finished. We signal this by decrementing depth.
158// In this state, iter.depth < depth, at_start == false, and error == SUCCESS.
159//
160
161} // namespace ondemand
162} // namespace SIMDJSON_IMPLEMENTATION
163} // namespace simdjson
164
165namespace simdjson {
166
167simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object_iterator>::simdjson_result(
168 SIMDJSON_IMPLEMENTATION::ondemand::object_iterator &&value
169) noexcept
170 : implementation_simdjson_result_base<SIMDJSON_IMPLEMENTATION::ondemand::object_iterator>(std::forward<SIMDJSON_IMPLEMENTATION::ondemand::object_iterator>(value))
171{
172 first.iter.assert_is_valid();
173}
174simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object_iterator>::simdjson_result(error_code error) noexcept
175 : implementation_simdjson_result_base<SIMDJSON_IMPLEMENTATION::ondemand::object_iterator>({}, error)
176{
177}
178
179simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::field> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object_iterator>::operator*() noexcept {
180 if (error()) { return error(); }
181 return *first;
182}
183// If we're iterating and there is an error, return the error once.
184simdjson_inline bool simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object_iterator>::operator==(const simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object_iterator> &other) const noexcept {
185 if (!first.iter.is_valid()) { return !error(); }
186 return first == other.first;
187}
188// If we're iterating and there is an error, return the error once.
189simdjson_inline bool simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object_iterator>::operator!=(const simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object_iterator> &other) const noexcept {
190 if (!first.iter.is_valid()) { return error(); }
191 return first != other.first;
192}
193// Checks for ']' and ','
194simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object_iterator> &simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object_iterator>::operator++() noexcept {
195 // Clear the error if there is one, so we don't yield it twice
196 if (error()) { second = SUCCESS; return *this; }
197 ++first;
198 return *this;
199}
200
201} // namespace simdjson
202
203#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