simdjson 4.1.0
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}
41
42#endif // SIMDJSON_EXCEPTIONS
43
44inline simdjson_result<dom::element> simdjson_result<dom::array>::at_pointer(std::string_view json_pointer) const noexcept {
45 if (error()) { return error(); }
46 return first.at_pointer(json_pointer);
47}
48
49 inline simdjson_result<dom::element> simdjson_result<dom::array>::at_path(std::string_view json_path) const noexcept {
50 auto json_pointer = json_path_to_pointer_conversion(json_path);
51 if (json_pointer == "-1") { return INVALID_JSON_POINTER; }
52 return at_pointer(json_pointer);
53 }
54
55inline simdjson_result<std::vector<dom::element>> simdjson_result<dom::array>::at_path_with_wildcard(std::string_view json_path) const noexcept {
56 if (error()) {
57 return error();
58 }
59 return first.at_path_with_wildcard(json_path);
60}
61
62inline simdjson_result<dom::element> simdjson_result<dom::array>::at(size_t index) const noexcept {
63 if (error()) { return error(); }
64 return first.at(index);
65}
66
67inline std::vector<dom::element>& simdjson_result<dom::array>::get_values(std::vector<dom::element>& out) const noexcept {
68 return first.get_values(out);
69}
70
71namespace dom {
72
73//
74// array inline implementation
75//
76simdjson_inline array::array() noexcept : tape{} {}
77simdjson_inline array::array(const internal::tape_ref &_tape) noexcept : tape{_tape} {}
78inline array::iterator array::begin() const noexcept {
79 SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
80 return internal::tape_ref(tape.doc, tape.json_index + 1);
81}
82inline array::iterator array::end() const noexcept {
83 SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
84 return internal::tape_ref(tape.doc, tape.after_element() - 1);
85}
86inline size_t array::size() const noexcept {
87 SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
88 return tape.scope_count();
89}
90inline size_t array::number_of_slots() const noexcept {
91 SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
92 return tape.matching_brace_index() - tape.json_index;
93}
94inline simdjson_result<element> array::at_pointer(std::string_view json_pointer) const noexcept {
95 SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
96 if(json_pointer.empty()) { // an empty string means that we return the current node
97 return element(this->tape); // copy the current node
98 } else if(json_pointer[0] != '/') { // otherwise there is an error
100 }
101 json_pointer = json_pointer.substr(1);
102 // - means "the append position" or "the element after the end of the array"
103 // We don't support this, because we're returning a real element, not a position.
104 if (json_pointer == "-") { return INDEX_OUT_OF_BOUNDS; }
105
106 // Read the array index
107 size_t array_index = 0;
108 size_t i;
109 for (i = 0; i < json_pointer.length() && json_pointer[i] != '/'; i++) {
110 uint8_t digit = uint8_t(json_pointer[i] - '0');
111 // Check for non-digit in array index. If it's there, we're trying to get a field in an object
112 if (digit > 9) { return INCORRECT_TYPE; }
113 array_index = array_index*10 + digit;
114 }
115
116 // 0 followed by other digits is invalid
117 if (i > 1 && json_pointer[0] == '0') { return INVALID_JSON_POINTER; } // "JSON pointer array index has other characters after 0"
118
119 // Empty string is invalid; so is a "/" with no digits before it
120 if (i == 0) { return INVALID_JSON_POINTER; } // "Empty string in JSON pointer array index"
121
122 // Get the child
123 auto child = array(tape).at(array_index);
124 // If there is an error, it ends here
125 if(child.error()) {
126 return child;
127 }
128 // If there is a /, we're not done yet, call recursively.
129 if (i < json_pointer.length()) {
130 child = child.at_pointer(json_pointer.substr(i));
131 }
132 return child;
133}
134
135inline simdjson_result<element> array::at_path(std::string_view json_path) const noexcept {
136 auto json_pointer = json_path_to_pointer_conversion(json_path);
137 if (json_pointer == "-1") { return INVALID_JSON_POINTER; }
138 return at_pointer(json_pointer);
139}
140
141inline 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 {
142 if (current == end) {
143 return;
144 }
145
147
148
149 for (auto it = current; it != end; ++it) {
150 std::vector<element> child_result;
151 auto error = it->at_path_with_wildcard(path_suffix).get(child_result);
152 if(error) {
153 continue;
154 }
155 accumulator.reserve(accumulator.size() + child_result.size());
156 accumulator.insert(accumulator.end(),
157 std::make_move_iterator(child_result.begin()),
158 std::make_move_iterator(child_result.end()));
159 }
160}
161
162inline simdjson_result<std::vector<element>> array::at_path_with_wildcard(std::string_view json_path) const noexcept {
163 SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
164
165 size_t i = 0;
166 // json_path.starts_with('$') requires C++20.
167 if (!json_path.empty() && json_path.front() == '$') {
168 i = 1;
169 }
170
171 if (i >= json_path.size() || (json_path[i] != '.' && json_path[i] != '[')) {
173 }
174
175 if (json_path.find("*") != std::string::npos) {
176 std::vector<element> child_values;
177
178 if (
179 (json_path.compare(i, 3, "[*]") == 0 && json_path.size() == i + 3) ||
180 (json_path.compare(i, 2,".*") == 0 && json_path.size() == i + 2)
181 ) {
182 get_values(child_values);
183 return child_values;
184 }
185
186 std::pair<std::string_view, std::string_view> key_and_json_path = get_next_key_and_json_path(json_path);
187
188 std::string_view key = key_and_json_path.first;
189 json_path = key_and_json_path.second;
190
191 if (key.size() > 0) {
192 if (key == "*") {
193 get_values(child_values);
194 } else {
195 element pointer_result;
196 std::string json_pointer = std::string("/") + std::string(key);
197 auto error = at_pointer(json_pointer).get(pointer_result);
198
199 if (!error) {
200 child_values.emplace_back(pointer_result);
201 }
202 }
203
204 std::vector<element> result = {};
205
206 if (child_values.size() > 0) {
207 std::vector<element>::iterator child_values_begin = child_values.begin();
208 std::vector<element>::iterator child_values_end = child_values.end();
209
210 process_json_path_of_child_elements(child_values_begin, child_values_end, json_path, result);
211 }
212
213 return result;
214 } else {
216 }
217 } else {
218 element result;
219 auto error = at_path(json_path).get(result);
220 if (error) {
221 return error;
222 }
223
224 return std::vector<element>{std::move(result)};
225 }
226}
227
228inline simdjson_result<element> array::at(size_t index) const noexcept {
229 SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
230 size_t i=0;
231 for (auto element : *this) {
232 if (i == index) { return element; }
233 i++;
234 }
235 return INDEX_OUT_OF_BOUNDS;
236}
237
238inline std::vector<element>& array::get_values(std::vector<element>& out) const noexcept {
239 out.reserve(this->size());
240 for (auto element : *this) {
241 out.emplace_back(element);
242 }
243
244 return out;
245}
246
247inline array::operator element() const noexcept {
248 return element(tape);
249}
250
251//
252// array::iterator inline implementation
253//
254simdjson_inline array::iterator::iterator(const internal::tape_ref &_tape) noexcept : tape{_tape} { }
255inline element array::iterator::operator*() const noexcept {
256 return element(tape);
257}
259 tape.json_index = tape.after_element();
260 return *this;
261}
263 array::iterator out = *this;
264 ++*this;
265 return out;
266}
267inline bool array::iterator::operator!=(const array::iterator& other) const noexcept {
268 return tape.json_index != other.tape.json_index;
269}
270inline bool array::iterator::operator==(const array::iterator& other) const noexcept {
271 return tape.json_index == other.tape.json_index;
272}
273inline bool array::iterator::operator<(const array::iterator& other) const noexcept {
274 return tape.json_index < other.tape.json_index;
275}
276inline bool array::iterator::operator<=(const array::iterator& other) const noexcept {
277 return tape.json_index <= other.tape.json_index;
278}
279inline bool array::iterator::operator>=(const array::iterator& other) const noexcept {
280 return tape.json_index >= other.tape.json_index;
281}
282inline bool array::iterator::operator>(const array::iterator& other) const noexcept {
283 return tape.json_index > other.tape.json_index;
284}
285
286} // namespace dom
287
288
289} // namespace simdjson
290
291#include "simdjson/dom/element-inl.h"
292
293#if SIMDJSON_SUPPORTS_RANGES
294static_assert(std::ranges::view<simdjson::dom::array>);
295static_assert(std::ranges::sized_range<simdjson::dom::array>);
296#if SIMDJSON_EXCEPTIONS
297static_assert(std::ranges::view<simdjson::simdjson_result<simdjson::dom::array>>);
298static_assert(std::ranges::sized_range<simdjson::simdjson_result<simdjson::dom::array>>);
299#endif // SIMDJSON_EXCEPTIONS
300#endif // SIMDJSON_SUPPORTS_RANGES
301
302#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:267
iterator & operator++() noexcept
Get the next value.
Definition array-inl.h:258
reference operator*() const noexcept
Get the actual value.
Definition array-inl.h:255
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:238
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:162
size_t number_of_slots() const noexcept
Get the total number of slots used by this array on the tape.
Definition array-inl.h:90
iterator end() const noexcept
One past the last array element.
Definition array-inl.h:82
size_t size() const noexcept
Get the size of the array (number of immediate children).
Definition array-inl.h:86
simdjson_result< element > at(size_t index) const noexcept
Get the value at the given index.
Definition array-inl.h:228
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:94
simdjson_inline array() noexcept
Create a new, invalid array.
Definition array-inl.h:76
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:135
iterator begin() const noexcept
Return the first array element.
Definition array-inl.h:78
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:141
A JSON element.
Definition element.h:33
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
@ INCORRECT_TYPE
JSON element has a different type than user expected.
Definition error.h:37
@ 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:278