simdjson 5.0.2
Ridiculously Fast JSON
Loading...
Searching...
No Matches
array-inl.h
1#ifndef SIMDJSON_ARRAY_INL_H
2#define SIMDJSON_ARRAY_INL_H
3
4#include <utility>
5
6#include "simdjson/dom/base.h"
7#include "simdjson/dom/array.h"
8#include "simdjson/dom/element.h"
9#include "simdjson/error-inl.h"
10#include "simdjson/jsonpathutil.h"
11#include "simdjson/internal/tape_ref-inl.h"
12
13#include <limits>
14
15namespace simdjson {
16
17//
18// simdjson_result<dom::array> inline implementation
19//
20simdjson_inline simdjson_result<dom::array>::simdjson_result() noexcept
21 : internal::simdjson_result_base<dom::array>() {}
22simdjson_inline simdjson_result<dom::array>::simdjson_result(dom::array value) noexcept
23 : internal::simdjson_result_base<dom::array>(std::forward<dom::array>(value)) {}
24simdjson_inline simdjson_result<dom::array>::simdjson_result(error_code error) noexcept
25 : internal::simdjson_result_base<dom::array>(error) {}
26
27#if SIMDJSON_EXCEPTIONS
28
29inline dom::array::iterator simdjson_result<dom::array>::begin() const noexcept(false) {
30 if (error()) { throw simdjson_error(error()); }
31 return first.begin();
32}
33inline dom::array::iterator simdjson_result<dom::array>::end() const noexcept(false) {
34 if (error()) { throw simdjson_error(error()); }
35 return first.end();
36}
37inline size_t simdjson_result<dom::array>::size() const noexcept(false) {
38 if (error()) { throw simdjson_error(error()); }
39 return first.size();
40}
41inline dom::array::reverse_iterator simdjson_result<dom::array>::rbegin() const noexcept(false) {
42 if (error()) { throw simdjson_error(error()); }
43 return first.rbegin();
44}
45inline dom::array::reverse_iterator simdjson_result<dom::array>::rend() const noexcept(false) {
46 if (error()) { throw simdjson_error(error()); }
47 return first.rend();
48}
49
50#endif // SIMDJSON_EXCEPTIONS
51
52inline simdjson_result<dom::element> simdjson_result<dom::array>::at_pointer(std::string_view json_pointer) const noexcept {
53 if (error()) { return error(); }
54 return first.at_pointer(json_pointer);
55}
56
57 inline simdjson_result<dom::element> simdjson_result<dom::array>::at_path(std::string_view json_path) const noexcept {
58 if (error()) { return error(); }
59 auto json_pointer = json_path_to_pointer_conversion(json_path);
60 if (json_pointer == "-1") { return INVALID_JSON_POINTER; }
61 return at_pointer(json_pointer);
62 }
63
64inline simdjson_result<std::vector<dom::element>> simdjson_result<dom::array>::at_path_with_wildcard(std::string_view json_path) const noexcept {
65 if (error()) {
66 return error();
67 }
68 return first.at_path_with_wildcard(json_path);
69}
70
71inline simdjson_result<dom::element> simdjson_result<dom::array>::at(size_t index) const noexcept {
72 if (error()) { return error(); }
73 return first.at(index);
74}
75
76inline std::vector<dom::element>& simdjson_result<dom::array>::get_values(std::vector<dom::element>& out) const noexcept {
77 return first.get_values(out);
78}
79
80namespace dom {
81
82//
83// array inline implementation
84//
85simdjson_inline array::array() noexcept : tape{} {}
86simdjson_inline array::array(const internal::tape_ref &_tape) noexcept : tape{_tape} {}
87inline array::iterator array::begin() const noexcept {
88 SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
89 return internal::tape_ref(tape.doc, tape.json_index + 1);
90}
91inline array::iterator array::end() const noexcept {
92 SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
93 return internal::tape_ref(tape.doc, tape.after_element() - 1);
94}
95inline size_t array::size() const noexcept {
96 SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
97 return tape.scope_count();
98}
99inline array::reverse_iterator array::rbegin() const noexcept {
100 SIMDJSON_DEVELOPMENT_ASSERT(tape.usable());
101 const internal::tape_ref end_tape(tape.doc, tape.matching_brace_index() - 1);
102 return reverse_iterator(internal::tape_ref(tape.doc, end_tape.before_element(tape.json_index)), tape.json_index);
103}
104inline array::reverse_iterator array::rend() const noexcept {
105 SIMDJSON_DEVELOPMENT_ASSERT(tape.usable());
106 return reverse_iterator(tape, tape.json_index);
107}
108inline size_t array::number_of_slots() const noexcept {
109 SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
110 return tape.matching_brace_index() - tape.json_index;
111}
112inline simdjson_result<element> array::at_pointer(std::string_view json_pointer) const noexcept {
113 SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
114 if(json_pointer.empty()) { // an empty string means that we return the current node
115 return element(this->tape); // copy the current node
116 } else if(json_pointer[0] != '/') { // otherwise there is an error
118 }
119 json_pointer = json_pointer.substr(1);
120 // - means "the append position" or "the element after the end of the array"
121 // We don't support this, because we're returning a real element, not a position.
122 if (json_pointer == "-") { return INDEX_OUT_OF_BOUNDS; }
123
124 size_t array_index = 0;
125 size_t i;
126 SIMDJSON_TRY(internal::parse_json_pointer_array_index(json_pointer, array_index, i));
127
128 // Get the child
129 auto child = array(tape).at(array_index);
130 // If there is an error, it ends here
131 if(child.error()) {
132 return child;
133 }
134 // If there is a /, we're not done yet, call recursively.
135 if (i < json_pointer.length()) {
136 child = child.at_pointer(json_pointer.substr(i));
137 }
138 return child;
139}
140
141inline simdjson_result<element> array::at_path(std::string_view json_path) const noexcept {
142 auto json_pointer = json_path_to_pointer_conversion(json_path);
143 if (json_pointer == "-1") { return INVALID_JSON_POINTER; }
144 return at_pointer(json_pointer);
145}
146
147inline void array::process_json_path_of_child_elements(std::vector<element>::iterator& current, std::vector<element>::iterator& end, const std::string_view& path_suffix, std::vector<element>& accumulator) const noexcept {
148 if (current == end) {
149 return;
150 }
151
153
154
155 for (auto it = current; it != end; ++it) {
156 std::vector<element> child_result;
157 auto error = it->at_path_with_wildcard(path_suffix).get(child_result);
158 if(error) {
159 continue;
160 }
161 accumulator.insert(accumulator.end(),
162 std::make_move_iterator(child_result.begin()),
163 std::make_move_iterator(child_result.end()));
164 }
165}
166
167inline simdjson_result<std::vector<element>> array::at_path_with_wildcard(std::string_view json_path) const noexcept {
168 SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
169
170 size_t i = 0;
171 // json_path.starts_with('$') requires C++20.
172 if (!json_path.empty() && json_path.front() == '$') {
173 i = 1;
174 }
175
176 if (i >= json_path.size() || (json_path[i] != '.' && json_path[i] != '[')) {
178 }
179
180 if (json_path.find("*") != std::string::npos) {
181 std::vector<element> child_values;
182
183 if (
184 (json_path.compare(i, 3, "[*]") == 0 && json_path.size() == i + 3) ||
185 (json_path.compare(i, 2,".*") == 0 && json_path.size() == i + 2)
186 ) {
187 get_values(child_values);
188 return child_values;
189 }
190
191 std::pair<std::string_view, std::string_view> key_and_json_path = get_next_key_and_json_path(json_path);
192
193 std::string_view key = key_and_json_path.first;
194 json_path = key_and_json_path.second;
195
196 if (key.size() > 0) {
197 if (key == "*") {
198 get_values(child_values);
199 } else {
200 element pointer_result;
201 std::string json_pointer = std::string("/") + std::string(key);
202 auto error = at_pointer(json_pointer).get(pointer_result);
203
204 if (!error) {
205 child_values.emplace_back(pointer_result);
206 }
207 }
208
209 std::vector<element> result = {};
210
211 if (child_values.size() > 0) {
212 std::vector<element>::iterator child_values_begin = child_values.begin();
213 std::vector<element>::iterator child_values_end = child_values.end();
214
215 process_json_path_of_child_elements(child_values_begin, child_values_end, json_path, result);
216 }
217
218 return result;
219 } else {
221 }
222 } else {
223 element result;
224 auto error = at_path(json_path).get(result);
225 if (error) {
226 return error;
227 }
228
229 return std::vector<element>{std::move(result)};
230 }
231}
232
233inline simdjson_result<element> array::at(size_t index) const noexcept {
234 SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
235 size_t i=0;
236 for (auto element : *this) {
237 if (i == index) { return element; }
238 i++;
239 }
240 return INDEX_OUT_OF_BOUNDS;
241}
242
243inline std::vector<element>& array::get_values(std::vector<element>& out) const noexcept {
244 out.reserve(this->size());
245 for (auto element : *this) {
246 out.emplace_back(element);
247 }
248
249 return out;
250}
251
252inline array::operator element() const noexcept {
253 return element(tape);
254}
255
256//
257// array::reverse_iterator inline implementation
258//
259simdjson_inline array::reverse_iterator::reverse_iterator(const internal::tape_ref &_tape, size_t _array_start) noexcept
260 : tape{_tape}, array_start{_array_start} { }
261inline element array::reverse_iterator::operator*() const noexcept {
262 return element(tape);
263}
264inline array::reverse_iterator& array::reverse_iterator::operator++() noexcept {
265 tape.json_index = tape.before_element(array_start);
266 return *this;
267}
268inline array::reverse_iterator array::reverse_iterator::operator++(int) noexcept {
269 reverse_iterator out = *this;
270 ++*this;
271 return out;
272}
273inline bool array::reverse_iterator::operator==(const reverse_iterator& other) const noexcept {
274 return tape.doc == other.tape.doc && tape.json_index == other.tape.json_index;
275}
276inline bool array::reverse_iterator::operator!=(const reverse_iterator& other) const noexcept {
277 return !(*this == other);
278}
279
280//
281// array::iterator inline implementation
282//
283simdjson_inline array::iterator::iterator(const internal::tape_ref &_tape) noexcept : tape{_tape} { }
284inline element array::iterator::operator*() const noexcept {
285 return element(tape);
286}
288 tape.json_index = tape.after_element();
289 return *this;
290}
292 array::iterator out = *this;
293 ++*this;
294 return out;
295}
296inline bool array::iterator::operator!=(const array::iterator& other) const noexcept {
297 return tape.json_index != other.tape.json_index;
298}
299inline bool array::iterator::operator==(const array::iterator& other) const noexcept {
300 return tape.json_index == other.tape.json_index;
301}
302inline bool array::iterator::operator<(const array::iterator& other) const noexcept {
303 return tape.json_index < other.tape.json_index;
304}
305inline bool array::iterator::operator<=(const array::iterator& other) const noexcept {
306 return tape.json_index <= other.tape.json_index;
307}
308inline bool array::iterator::operator>=(const array::iterator& other) const noexcept {
309 return tape.json_index >= other.tape.json_index;
310}
311inline bool array::iterator::operator>(const array::iterator& other) const noexcept {
312 return tape.json_index > other.tape.json_index;
313}
314
315} // namespace dom
316
317
318} // namespace simdjson
319
320#include "simdjson/dom/element-inl.h"
321
322#if SIMDJSON_SUPPORTS_RANGES
323static_assert(std::ranges::view<simdjson::dom::array>);
324static_assert(std::ranges::sized_range<simdjson::dom::array>);
325#if SIMDJSON_EXCEPTIONS
326static_assert(std::ranges::view<simdjson::simdjson_result<simdjson::dom::array>>);
327static_assert(std::ranges::sized_range<simdjson::simdjson_result<simdjson::dom::array>>);
328#endif // SIMDJSON_EXCEPTIONS
329#endif // SIMDJSON_SUPPORTS_RANGES
330
331#endif // SIMDJSON_ARRAY_INL_H
bool operator!=(const iterator &other) const noexcept
Check if these values come from the same place in the JSON.
Definition array-inl.h:296
iterator & operator++() noexcept
Get the next value.
Definition array-inl.h:287
reference operator*() const noexcept
Get the actual value.
Definition array-inl.h:284
A forward iterator that visits the array's elements in reverse order.
Definition array.h:71
JSON array.
Definition array.h:15
std::vector< element > & get_values(std::vector< element > &out) const noexcept
Gets the values of items in an array element This function has linear-time complexity: the values are...
Definition array-inl.h:243
simdjson_result< std::vector< element > > at_path_with_wildcard(std::string_view json_path) const noexcept
Adds support for JSONPath expression with wildcards '*'.
Definition array-inl.h:167
size_t number_of_slots() const noexcept
Get the total number of slots used by this array on the tape.
Definition array-inl.h:108
iterator end() const noexcept
One past the last array element.
Definition array-inl.h:91
size_t size() const noexcept
Get the size of the array (number of immediate children).
Definition array-inl.h:95
simdjson_result< element > at(size_t index) const noexcept
Get the value at the given index.
Definition array-inl.h:233
simdjson_result< element > at_pointer(std::string_view json_pointer) const noexcept
Get the value associated with the given JSON pointer.
Definition array-inl.h:112
reverse_iterator rbegin() const noexcept
Return the last array element, or rend() for an empty array.
Definition array-inl.h:99
simdjson_inline array() noexcept
Create a new, invalid array.
Definition array-inl.h:85
simdjson_result< element > at_path(std::string_view json_path) const noexcept
Get the value associated with the given JSONPath expression.
Definition array-inl.h:141
reverse_iterator rend() const noexcept
Return the reverse traversal sentinel, before the first element.
Definition array-inl.h:104
iterator begin() const noexcept
Return the first array element.
Definition array-inl.h:87
void process_json_path_of_child_elements(std::vector< element >::iterator &current, std::vector< element >::iterator &end, const std::string_view &path_suffix, std::vector< element > &accumulator) const noexcept
Recursive function which processes the JSON path of each child element.
Definition array-inl.h:147
A JSON element.
Definition element.h:36
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
@ INDEX_OUT_OF_BOUNDS
JSON array index too large.
Definition error.h:39
@ 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