simdjson 5.0.2
Ridiculously Fast JSON
Loading...
Searching...
No Matches
array-inl.h
1#ifndef SIMDJSON_GENERIC_ONDEMAND_ARRAY_INL_H
2
3#ifndef SIMDJSON_CONDITIONAL_INCLUDE
4#define SIMDJSON_GENERIC_ONDEMAND_ARRAY_INL_H
5#include "simdjson/jsonpathutil.h"
6#include "simdjson/generic/ondemand/base.h"
7#include "simdjson/generic/ondemand/array.h"
8#include "simdjson/generic/ondemand/array_iterator-inl.h"
9#include "simdjson/generic/ondemand/json_iterator.h"
10#include "simdjson/generic/ondemand/value.h"
11#include "simdjson/generic/ondemand/value_iterator-inl.h"
12#endif // SIMDJSON_CONDITIONAL_INCLUDE
13
14namespace simdjson {
15namespace SIMDJSON_IMPLEMENTATION {
16namespace ondemand {
17
18//
19// ### Live States
20//
21// While iterating or looking up values, depth >= iter->depth. at_start may vary. Error is
22// always SUCCESS:
23//
24// - Start: This is the state when the array is first found and the iterator is just past the `{`.
25// In this state, at_start == true.
26// - Next: After we hand a scalar value to the user, or an array/object which they then fully
27// iterate over, the iterator is at the `,` before the next value (or `]`). In this state,
28// depth == iter->depth, at_start == false, and error == SUCCESS.
29// - Unfinished Business: When we hand an array/object to the user which they do not fully
30// iterate over, we need to finish that iteration by skipping child values until we reach the
31// Next state. In this state, depth > iter->depth, at_start == false, and error == SUCCESS.
32//
33// ## Error States
34//
35// In error states, we will yield exactly one more value before stopping. iter->depth == depth
36// and at_start is always false. We decrement after yielding the error, moving to the Finished
37// state.
38//
39// - Chained Error: When the array iterator is part of an error chain--for example, in
40// `for (auto tweet : doc["tweets"])`, where the tweet element may be missing or not be an
41// array--we yield that error in the loop, exactly once. In this state, error != SUCCESS and
42// iter->depth == depth, and at_start == false. We decrement depth when we yield the error.
43// - Missing Comma Error: When the iterator ++ method discovers there is no comma between elements,
44// we flag that as an error and treat it exactly the same as a Chained Error. In this state,
45// error == TAPE_ERROR, iter->depth == depth, and at_start == false.
46//
47// ## Terminal State
48//
49// The terminal state has iter->depth < depth. at_start is always false.
50//
51// - Finished: When we have reached a `]` or have reported an error, we are finished. We signal this
52// by decrementing depth. In this state, iter->depth < depth, at_start == false, and
53// error == SUCCESS.
54//
55
56simdjson_inline array::array(const value_iterator &_iter) noexcept
57 : iter{_iter}
58{
59}
60
61simdjson_inline simdjson_result<array> array::start(value_iterator &iter) noexcept {
62 // We don't need to know if the array is empty to start iteration, but we do want to know if there
63 // is an error--thus `simdjson_unused`.
64 simdjson_unused bool has_value;
65 SIMDJSON_TRY( iter.start_array().get(has_value) );
66 return array(iter);
67}
68simdjson_inline simdjson_result<array> array::start_root(value_iterator &iter) noexcept {
69 simdjson_unused bool has_value;
70 SIMDJSON_TRY( iter.start_root_array().get(has_value) );
71 return array(iter);
72}
73simdjson_inline simdjson_result<array> array::started(value_iterator &iter) noexcept {
74 bool has_value;
75 SIMDJSON_TRY(iter.started_array().get(has_value));
76 return array(iter);
77}
78
79simdjson_inline simdjson_result<array_iterator> array::begin() & noexcept {
80#if SIMDJSON_DEVELOPMENT_CHECKS
81 if (!iter.is_at_iterator_start() || locked) { return OUT_OF_ORDER_ITERATION; }
82 return array_iterator(iter, this);
83#endif
84 return array_iterator(iter);
85}
86simdjson_inline simdjson_result<array_iterator> array::begin() && noexcept {
87#if SIMDJSON_DEVELOPMENT_CHECKS
88 // The array is a temporary that the iterator may outlive: do not lock it.
89 if (!iter.is_at_iterator_start() || locked) { return OUT_OF_ORDER_ITERATION; }
90#endif
91 return array_iterator(iter);
92}
93simdjson_inline simdjson_result<array_iterator> array::end() noexcept {
94 return array_iterator(iter);
95}
96simdjson_warn_unused simdjson_warn_unused simdjson_inline error_code array::consume() noexcept {
97 auto error = iter.json_iter().skip_child(iter.depth()-1);
98 if(error) { iter.abandon(); }
99 return error;
100}
101
103 const uint8_t * starting_point{iter.peek_start()};
104 auto error = consume();
105 if(error) { return error; }
106 // After 'consume()', we could be left pointing just beyond the document, but that
107 // is ok because we are not going to dereference the final pointer position, we just
108 // use it to compute the length in bytes.
109 const uint8_t * final_point{iter._json_iter->unsafe_pointer()};
110 return std::string_view(reinterpret_cast<const char*>(starting_point), size_t(final_point - starting_point));
111}
112
113SIMDJSON_PUSH_DISABLE_WARNINGS
114SIMDJSON_DISABLE_STRICT_OVERFLOW_WARNING
115simdjson_inline simdjson_result<size_t> array::count_elements() & noexcept {
116#if SIMDJSON_DEVELOPMENT_CHECKS
117 if (locked) return OUT_OF_ORDER_ITERATION;
118#endif
119 size_t count{0};
120 // Important: we do not consume any of the values.
121 for(simdjson_unused auto v : *this) { count++; }
122 // The above loop will always succeed, but we want to report errors.
123 if(iter.error()) { return iter.error(); }
124 // We need to move back at the start because we expect users to iterate through
125 // the array after counting the number of elements.
126 iter.reset_array();
127 return count;
128}
129SIMDJSON_POP_DISABLE_WARNINGS
130
131simdjson_inline simdjson_result<bool> array::is_empty() & noexcept {
132#if SIMDJSON_DEVELOPMENT_CHECKS
133 if (locked) return OUT_OF_ORDER_ITERATION;
134#endif
135 bool is_not_empty;
136 auto error = iter.reset_array().get(is_not_empty);
137 if(error) { return error; }
138 return !is_not_empty;
139}
140
142#if SIMDJSON_DEVELOPMENT_CHECKS
143 if (locked) return OUT_OF_ORDER_ITERATION;
144#endif
145 return iter.reset_array();
146}
147
148#if SIMDJSON_DEVELOPMENT_CHECKS
149simdjson_inline void array::set_locked(bool _locked) noexcept {
150 locked = _locked;
151}
152#endif
153
154inline simdjson_result<value> array::at_pointer(std::string_view json_pointer) noexcept {
155 if (json_pointer[0] != '/') { return INVALID_JSON_POINTER; }
156 json_pointer = json_pointer.substr(1);
157 // - means "the append position" or "the element after the end of the array"
158 // We don't support this, because we're returning a real element, not a position.
159 if (json_pointer == "-") { return INDEX_OUT_OF_BOUNDS; }
160
161 size_t array_index = 0;
162 size_t i;
163 SIMDJSON_TRY(internal::parse_json_pointer_array_index(json_pointer, array_index, i));
164 // Get the child
165 auto child = at(array_index);
166 // If there is an error, it ends here
167 if(child.error()) {
168 return child;
169 }
170
171 // If there is a /, we're not done yet, call recursively.
172 if (i < json_pointer.length()) {
173 child = child.at_pointer(json_pointer.substr(i));
174 }
175 return child;
176}
177
178inline simdjson_result<value> array::at_path(std::string_view json_path) noexcept {
179 auto json_pointer = json_path_to_pointer_conversion(json_path);
180 if (json_pointer == "-1") { return INVALID_JSON_POINTER; }
181 return at_pointer(json_pointer);
182}
183
184#if SIMDJSON_SUPPORTS_CONCEPTS
185template <typename Func>
186 requires std::invocable<Func, value>
187#else
188template <typename Func>
189#endif
190inline error_code array::for_each_at_path_with_wildcard(std::string_view json_path, Func&& callback) noexcept {
191 auto result_pair = get_next_key_and_json_path(json_path);
192 std::string_view key = result_pair.first;
193 std::string_view remaining_path = result_pair.second;
194 // Empty key means the path segment could not be parsed (including malformed
195 // bracket-quoted keys). Without this check, an empty key is treated as index
196 // 0 and remaining_path may be unchanged, causing infinite recursion.
197 if (key.empty()) {
199 }
200 // Wildcard case
201 if (key=="*"){
202 for(auto element: *this) {
203 value val;
204 SIMDJSON_TRY(element.get(val));
205 if (remaining_path.empty()) {
206 callback(val);
207 } else {
208 error_code err = element.for_each_at_path_with_wildcard(remaining_path, callback);
209 if(err) { return err; }
210 }
211 }
212 return SUCCESS;
213 } else {
214 // Specific index case in which we access the element at the given index
215 size_t idx = 0;
216
217 for (char c : key) {
218 if(c < '0' || c > '9'){
220 }
221 idx = idx*10 + (c - '0');
222 }
223
224 auto element = at(idx);
225 value val;
226 SIMDJSON_TRY(element.get(val));
227 if (remaining_path.empty()){
228 callback(val);
229 return SUCCESS;
230 } else {
231 return element.for_each_at_path_with_wildcard(remaining_path, callback);
232 }
233 }
234}
235
236simdjson_inline simdjson_result<value> array::at(size_t index) noexcept {
237#if SIMDJSON_DEVELOPMENT_CHECKS
238 if (locked) return OUT_OF_ORDER_ITERATION;
239#endif
240 size_t i = 0;
241 for (auto value : *this) {
242 if (i == index) { return value; }
243 i++;
244 }
245 return INDEX_OUT_OF_BOUNDS;
246}
247
248} // namespace ondemand
249} // namespace SIMDJSON_IMPLEMENTATION
250} // namespace simdjson
251
252namespace simdjson {
253
254simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::array>::simdjson_result(
255 SIMDJSON_IMPLEMENTATION::ondemand::array &&value
256) noexcept
257 : implementation_simdjson_result_base<SIMDJSON_IMPLEMENTATION::ondemand::array>(
258 std::forward<SIMDJSON_IMPLEMENTATION::ondemand::array>(value)
259 )
260{
261}
262simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::array>::simdjson_result(
263 error_code error
264) noexcept
265 : implementation_simdjson_result_base<SIMDJSON_IMPLEMENTATION::ondemand::array>(error)
266{
267}
268
269simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::array_iterator> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::array>::begin() & noexcept {
270 if (error()) { return error(); }
271 return first.begin();
272}
273simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::array_iterator> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::array>::begin() && noexcept {
274 if (error()) { return error(); }
275 return std::move(first).begin();
276}
277simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::array_iterator> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::array>::end() noexcept {
278 if (error()) { return error(); }
279 return first.end();
280}
281simdjson_inline simdjson_result<size_t> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::array>::count_elements() & noexcept {
282 if (error()) { return error(); }
283 return first.count_elements();
284}
285simdjson_inline simdjson_result<bool> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::array>::is_empty() & noexcept {
286 if (error()) { return error(); }
287 return first.is_empty();
288}
289simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::array>::at(size_t index) noexcept {
290 if (error()) { return error(); }
291 return first.at(index);
292}
293simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::array>::at_pointer(std::string_view json_pointer) noexcept {
294 if (error()) { return error(); }
295 return first.at_pointer(json_pointer);
296}
297simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::array>::at_path(std::string_view json_path) noexcept {
298 if (error()) { return error(); }
299 return first.at_path(json_path);
300}
301#if SIMDJSON_SUPPORTS_CONCEPTS
302template <typename Func>
303 requires std::invocable<Func, SIMDJSON_IMPLEMENTATION::ondemand::value>
304#else
305template <typename Func>
306#endif
307simdjson_inline error_code simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::array>::for_each_at_path_with_wildcard(std::string_view json_path, Func&& callback) noexcept {
308 if (error()) { return error(); }
309 return first.for_each_at_path_with_wildcard(json_path, std::forward<Func>(callback));
310}
311simdjson_inline simdjson_result<std::string_view> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::array>::raw_json() noexcept {
312 if (error()) { return error(); }
313 return first.raw_json();
314}
315} // namespace simdjson
316
317#endif // SIMDJSON_GENERIC_ONDEMAND_ARRAY_INL_H
error_code for_each_at_path_with_wildcard(std::string_view json_path, Func &&callback) noexcept
Call the provided callback for each value matching the given JSONPath expression with wildcard suppor...
Definition array-inl.h:190
simdjson_inline simdjson_result< value > at(size_t index) noexcept
Get the value at the given index.
Definition array-inl.h:236
value_iterator iter
Iterator marking current position.
Definition array.h:241
simdjson_inline simdjson_result< bool > is_empty() &noexcept
This method scans the beginning of the array and checks whether the array is empty.
Definition array-inl.h:131
simdjson_inline simdjson_result< array_iterator > begin() &noexcept
Begin array iteration.
Definition array-inl.h:79
simdjson_result< value > at_pointer(std::string_view json_pointer) noexcept
Get the value associated with the given JSON pointer.
Definition array-inl.h:154
static simdjson_inline simdjson_result< array > start(value_iterator &iter) noexcept
Begin array iteration.
Definition array-inl.h:61
simdjson_inline array() noexcept=default
Create a new invalid array.
simdjson_inline simdjson_result< size_t > count_elements() &noexcept
This method scans the array and counts the number of elements.
Definition array-inl.h:115
simdjson_result< value > at_path(std::string_view json_path) noexcept
Get the value associated with the given JSONPath expression.
Definition array-inl.h:178
static simdjson_inline simdjson_result< array > start_root(value_iterator &iter) noexcept
Begin array iteration from the root.
Definition array-inl.h:68
static simdjson_inline simdjson_result< array > started(value_iterator &iter) noexcept
Begin array iteration.
Definition array-inl.h:73
simdjson_warn_unused simdjson_inline error_code consume() noexcept
Go to the end of the array, no matter where you are right now.
Definition array-inl.h:96
simdjson_inline simdjson_result< std::string_view > raw_json() noexcept
Consumes the array and returns a string_view instance corresponding to the array as represented in JS...
Definition array-inl.h:102
simdjson_inline simdjson_result< array_iterator > end() noexcept
Sentinel representing the end of the array.
Definition array-inl.h:93
simdjson_result< bool > reset() &noexcept
Reset the iterator so that we are pointing back at the beginning of the array.
Definition array-inl.h:141
An ephemeral JSON value returned during iteration.
Definition value.h:22
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
@ OUT_OF_ORDER_ITERATION
tried to iterate an array or object out of order (checked when SIMDJSON_DEVELOPMENT_CHECKS=1)
Definition error.h:46
@ INDEX_OUT_OF_BOUNDS
JSON array index too large.
Definition error.h:39
@ SUCCESS
No error.
Definition error.h:20
@ INVALID_JSON_POINTER
Invalid JSON pointer syntax.
Definition error.h:42
std::string json_path_to_pointer_conversion(std::string_view json_path)
Converts JSONPath to JSON Pointer.
The result of a simdjson operation that could fail.
Definition error.h:281
simdjson_inline error_code error() const noexcept
The error.
Definition error-inl.h:168