simdjson 4.6.6
Ridiculously Fast JSON
Loading...
Searching...
No Matches
object-inl.h
1#ifndef SIMDJSON_GENERIC_ONDEMAND_OBJECT_INL_H
2
3#ifndef SIMDJSON_CONDITIONAL_INCLUDE
4#define SIMDJSON_GENERIC_ONDEMAND_OBJECT_INL_H
5#include "simdjson/generic/ondemand/base.h"
6#include "simdjson/generic/ondemand/field.h"
7#include "simdjson/generic/ondemand/object.h"
8#include "simdjson/generic/ondemand/object_iterator.h"
9#include "simdjson/generic/ondemand/raw_json_string.h"
10#include "simdjson/generic/ondemand/json_iterator.h"
11#include "simdjson/generic/ondemand/value-inl.h"
12#include "simdjson/jsonpathutil.h"
13#if SIMDJSON_STATIC_REFLECTION
14#include "simdjson/generic/ondemand/json_string_builder.h" // for constevalutil::fixed_string
15#include <meta>
16#endif
17#endif // SIMDJSON_CONDITIONAL_INCLUDE
18
19namespace simdjson {
20namespace SIMDJSON_IMPLEMENTATION {
21namespace ondemand {
22
23simdjson_inline simdjson_result<value> object::find_field_unordered(const std::string_view key) & noexcept {
24 bool has_value;
25 SIMDJSON_TRY( iter.find_field_unordered_raw(key).get(has_value) );
26 if (!has_value) {
27 logger::log_line(iter.json_iter(), "ERROR: ", "Cannot find key %.*s", "", -1, 0, logger::log_level::error, static_cast<int>(key.size()), key.data());
28 return NO_SUCH_FIELD;
29 }
30 return value(iter.child());
31}
32simdjson_inline simdjson_result<value> object::find_field_unordered(const std::string_view key) && noexcept {
33 bool has_value;
34 SIMDJSON_TRY( iter.find_field_unordered_raw(key).get(has_value) );
35 if (!has_value) {
36 logger::log_line(iter.json_iter(), "ERROR: ", "Cannot find key %.*s", "", -1, 0, logger::log_level::error, static_cast<int>(key.size()), key.data());
37 return NO_SUCH_FIELD;
38 }
39 return value(iter.child());
40}
41simdjson_inline simdjson_result<value> object::operator[](const std::string_view key) & noexcept {
42 return find_field_unordered(key);
43}
44simdjson_inline simdjson_result<value> object::operator[](const std::string_view key) && noexcept {
45 return std::forward<object>(*this).find_field_unordered(key);
46}
47simdjson_inline simdjson_result<value> object::find_field(const std::string_view key) & noexcept {
48 bool has_value;
49 SIMDJSON_TRY( iter.find_field_raw(key).get(has_value) );
50 if (!has_value) {
51 logger::log_line(iter.json_iter(), "ERROR: ", "Cannot find key %.*s", "", -1, 0, logger::log_level::error, static_cast<int>(key.size()), key.data());
52 return NO_SUCH_FIELD;
53 }
54 return value(iter.child());
55}
56simdjson_inline simdjson_result<value> object::find_field(const std::string_view key) && noexcept {
57 bool has_value;
58 SIMDJSON_TRY( iter.find_field_raw(key).get(has_value) );
59 if (!has_value) {
60 logger::log_line(iter.json_iter(), "ERROR: ", "Cannot find key %.*s", "", -1, 0, logger::log_level::error, static_cast<int>(key.size()), key.data());
61 return NO_SUCH_FIELD;
62 }
63 return value(iter.child());
64}
65
66simdjson_inline simdjson_result<object> object::start(value_iterator &iter) noexcept {
67 SIMDJSON_TRY( iter.start_object().error() );
68 return object(iter);
69}
70simdjson_inline simdjson_result<object> object::start_root(value_iterator &iter) noexcept {
71 SIMDJSON_TRY( iter.start_root_object().error() );
72 return object(iter);
73}
74simdjson_warn_unused simdjson_inline error_code object::consume() noexcept {
75 if(iter.is_at_key()) {
89 simdjson_unused raw_json_string actual_key;
90 auto error = iter.field_key().get(actual_key);
91 if (error) { iter.abandon(); return error; };
92 // Let us move to the value while we are at it.
93 if ((error = iter.field_value())) { iter.abandon(); return error; }
94 }
95 auto error_skip = iter.json_iter().skip_child(iter.depth()-1);
96 if(error_skip) { iter.abandon(); }
97 return error_skip;
98}
99
101 const uint8_t * starting_point{iter.peek_start()};
102 auto error = consume();
103 if(error) { return error; }
104 const uint8_t * final_point{iter._json_iter->peek()};
105 return std::string_view(reinterpret_cast<const char*>(starting_point), size_t(final_point - starting_point));
106}
107
108simdjson_inline simdjson_result<object> object::started(value_iterator &iter) noexcept {
109 SIMDJSON_TRY( iter.started_object().error() );
110 return object(iter);
111}
112
113simdjson_inline object object::resume(const value_iterator &iter) noexcept {
114 return iter;
115}
116
117simdjson_inline object::object(const value_iterator &_iter) noexcept
118 : iter{_iter}
119{
120}
121
123#if SIMDJSON_DEVELOPMENT_CHECKS
124 if (!iter.is_at_iterator_start()) { return OUT_OF_ORDER_ITERATION; }
125#endif
126 return object_iterator(iter);
127}
128simdjson_inline simdjson_result<object_iterator> object::end() noexcept {
129 return object_iterator(iter);
130}
131
132inline simdjson_result<value> object::at_pointer(std::string_view json_pointer) noexcept {
133 if (json_pointer[0] != '/') { return INVALID_JSON_POINTER; }
134 json_pointer = json_pointer.substr(1);
135 size_t slash = json_pointer.find('/');
136 std::string_view key = json_pointer.substr(0, slash);
137 // Grab the child with the given key
139
140 // If there is an escape character in the key, unescape it and then get the child.
141 size_t escape = key.find('~');
142 if (escape != std::string_view::npos) {
143 // Unescape the key
144 std::string unescaped(key);
145 do {
146 switch (unescaped[escape+1]) {
147 case '0':
148 unescaped.replace(escape, 2, "~");
149 break;
150 case '1':
151 unescaped.replace(escape, 2, "/");
152 break;
153 default:
154 return INVALID_JSON_POINTER; // "Unexpected ~ escape character in JSON pointer");
155 }
156 escape = unescaped.find('~', escape+1);
157 } while (escape != std::string::npos);
158 child = find_field(unescaped); // Take note find_field does not unescape keys when matching
159 } else {
160 child = find_field(key);
161 }
162 if(child.error()) {
163 return child; // we do not continue if there was an error
164 }
165 // If there is a /, we have to recurse and look up more of the path
166 if (slash != std::string_view::npos) {
167 child = child.at_pointer(json_pointer.substr(slash));
168 }
169 return child;
170}
171
172inline simdjson_result<value> object::at_path(std::string_view json_path) noexcept {
173 auto json_pointer = json_path_to_pointer_conversion(json_path);
174 if (json_pointer == "-1") {
176 }
177 return at_pointer(json_pointer);
178}
179
180#if SIMDJSON_SUPPORTS_CONCEPTS
181template <typename Func>
182 requires std::invocable<Func, value>
183#else
184template <typename Func>
185#endif
186inline error_code object::for_each_at_path_with_wildcard(std::string_view json_path, Func&& callback) noexcept {
187 auto result_pair = get_next_key_and_json_path(json_path);
188 std::string_view key = result_pair.first;
189 std::string_view remaining_path = result_pair.second;
190 // Empty key means the path segment could not be parsed (including malformed
191 // bracket-quoted keys). Match DOM at_path_with_wildcard and avoid treating
192 // "no progress" as a recursive lookup of "".
193 if (key.empty()) {
195 }
196 // Handle when its the case for wildcard
197 if (key == "*") {
198 // Loop through each field in the object
199 for (auto field : *this) {
200 value val;
201 SIMDJSON_TRY(field.value().get(val));
202 if (remaining_path.empty()) {
203 callback(val);
204 } else {
205 SIMDJSON_TRY(val.for_each_at_path_with_wildcard(remaining_path, callback));
206 }
207 }
208 return SUCCESS;
209 } else {
210 value val;
211 SIMDJSON_TRY(find_field(key).get(val));
212
213 if (remaining_path.empty()) {
214 callback(val);
215 return SUCCESS;
216 } else {
217 return val.for_each_at_path_with_wildcard(remaining_path, callback);
218 }
219 }
220}
221
222simdjson_inline simdjson_result<size_t> object::count_fields() & noexcept {
223 size_t count{0};
224 // Important: we do not consume any of the values.
225 for(simdjson_unused auto v : *this) { count++; }
226 // The above loop will always succeed, but we want to report errors.
227 if(iter.error()) { return iter.error(); }
228 // We need to move back at the start because we expect users to iterate through
229 // the object after counting the number of elements.
230 iter.reset_object();
231 return count;
232}
233
234simdjson_inline simdjson_result<bool> object::is_empty() & noexcept {
235 bool is_not_empty;
236 auto error = iter.reset_object().get(is_not_empty);
237 if(error) { return error; }
238 return !is_not_empty;
239}
240
241simdjson_inline simdjson_result<bool> object::reset() & noexcept {
242 return iter.reset_object();
243}
244
245#if SIMDJSON_SUPPORTS_CONCEPTS && SIMDJSON_STATIC_REFLECTION
246
247template<constevalutil::fixed_string... FieldNames, typename T>
248 requires(std::is_class_v<T> && (sizeof...(FieldNames) > 0))
249simdjson_warn_unused simdjson_inline error_code object::extract_into(T& out) & noexcept {
250 // Helper to check if a field name matches any of the requested fields
251 auto should_extract = [](std::string_view field_name) constexpr -> bool {
252 return ((FieldNames.view() == field_name) || ...);
253 };
254
255 // Iterate through all members of T using reflection
256 template for (constexpr auto mem : std::define_static_array(
257 std::meta::nonstatic_data_members_of(^^T, std::meta::access_context::unchecked()))) {
258
259 if constexpr (!std::meta::is_const(mem) && std::meta::is_public(mem)) {
260 constexpr std::string_view key = std::define_static_string(std::meta::identifier_of(mem));
261
262 // Only extract this field if it's in our list of requested fields
263 if constexpr (should_extract(key)) {
264 // Try to find and extract the field
265 if constexpr (concepts::optional_type<decltype(out.[:mem:])>) {
266 // For optional fields, it's ok if they're missing
267 auto field_result = find_field_unordered(key);
268 if (!field_result.error()) {
269 auto error = field_result.get(out.[:mem:]);
270 if (error && error != NO_SUCH_FIELD) {
271 return error;
272 }
273 } else if (field_result.error() != NO_SUCH_FIELD) {
274 return field_result.error();
275 } else {
276 out.[:mem:].reset();
277 }
278 } else {
279 // For required fields (in the requested list), fail if missing
280 SIMDJSON_TRY((*this)[key].get(out.[:mem:]));
281 }
282 }
283 }
284 };
285
286 return SUCCESS;
287}
288
289#endif // SIMDJSON_SUPPORTS_CONCEPTS && SIMDJSON_STATIC_REFLECTION
290
291} // namespace ondemand
292} // namespace SIMDJSON_IMPLEMENTATION
293} // namespace simdjson
294
295namespace simdjson {
296
297simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object>::simdjson_result(SIMDJSON_IMPLEMENTATION::ondemand::object &&value) noexcept
298 : implementation_simdjson_result_base<SIMDJSON_IMPLEMENTATION::ondemand::object>(std::forward<SIMDJSON_IMPLEMENTATION::ondemand::object>(value)) {}
299simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object>::simdjson_result(error_code error) noexcept
300 : implementation_simdjson_result_base<SIMDJSON_IMPLEMENTATION::ondemand::object>(error) {}
301
302simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object_iterator> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object>::begin() noexcept {
303 if (error()) { return error(); }
304 return first.begin();
305}
306simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object_iterator> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object>::end() noexcept {
307 if (error()) { return error(); }
308 return first.end();
309}
310simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object>::find_field_unordered(std::string_view key) & noexcept {
311 if (error()) { return error(); }
312 return first.find_field_unordered(key);
313}
314simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object>::find_field_unordered(std::string_view key) && noexcept {
315 if (error()) { return error(); }
316 return std::forward<SIMDJSON_IMPLEMENTATION::ondemand::object>(first).find_field_unordered(key);
317}
318simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object>::operator[](std::string_view key) & noexcept {
319 if (error()) { return error(); }
320 return first[key];
321}
322simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object>::operator[](std::string_view key) && noexcept {
323 if (error()) { return error(); }
324 return std::forward<SIMDJSON_IMPLEMENTATION::ondemand::object>(first)[key];
325}
326simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object>::find_field(std::string_view key) & noexcept {
327 if (error()) { return error(); }
328 return first.find_field(key);
329}
330simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object>::find_field(std::string_view key) && noexcept {
331 if (error()) { return error(); }
332 return std::forward<SIMDJSON_IMPLEMENTATION::ondemand::object>(first).find_field(key);
333}
334
335simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object>::at_pointer(std::string_view json_pointer) noexcept {
336 if (error()) { return error(); }
337 return first.at_pointer(json_pointer);
338}
339
340simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object>::at_path(
341 std::string_view json_path) noexcept {
342 if (error()) {
343 return error();
344 }
345 return first.at_path(json_path);
346}
347
348#if SIMDJSON_SUPPORTS_CONCEPTS
349template <typename Func>
350 requires std::invocable<Func, SIMDJSON_IMPLEMENTATION::ondemand::value>
351#else
352template <typename Func>
353#endif
354simdjson_inline error_code simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object>::for_each_at_path_with_wildcard(std::string_view json_path, Func&& callback) noexcept {
355 if (error()) { return error(); }
356 return first.for_each_at_path_with_wildcard(json_path, std::forward<Func>(callback));
357}
358
359inline simdjson_result<bool> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object>::reset() noexcept {
360 if (error()) { return error(); }
361 return first.reset();
362}
363
364inline simdjson_result<bool> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object>::is_empty() noexcept {
365 if (error()) { return error(); }
366 return first.is_empty();
367}
368
369simdjson_inline simdjson_result<size_t> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object>::count_fields() & noexcept {
370 if (error()) { return error(); }
371 return first.count_fields();
372}
373
374simdjson_inline simdjson_result<std::string_view> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object>::raw_json() noexcept {
375 if (error()) { return error(); }
376 return first.raw_json();
377}
378
379} // namespace simdjson
380
381#endif // SIMDJSON_GENERIC_ONDEMAND_OBJECT_INL_H
A JSON field (key/value pair) in an object.
Definition field.h:22
simdjson_inline ondemand::value & value() &noexcept
Get the field value.
Definition field-inl.h:67
A forward-only JSON object field iterator.
Definition object.h:21
simdjson_inline object() noexcept=default
Create a new invalid object.
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 object-inl.h:186
simdjson_inline simdjson_result< value > find_field_unordered(std::string_view key) &noexcept
Look up a field by name on an object, without regard to key order.
Definition object-inl.h:23
simdjson_inline simdjson_result< std::string_view > raw_json() noexcept
Consumes the object and returns a string_view instance corresponding to the object as represented in ...
Definition object-inl.h:100
simdjson_warn_unused simdjson_inline error_code consume() noexcept
Go to the end of the object, no matter where you are right now.
Definition object-inl.h:74
simdjson_inline simdjson_result< value > find_field(std::string_view key) &noexcept
Look up a field by name on an object (order-sensitive).
Definition object-inl.h:47
simdjson_result< bool > is_empty() &noexcept
This method scans the beginning of the object and checks whether the object is empty.
Definition object-inl.h:234
simdjson_result< bool > reset() &noexcept
Reset the iterator so that we are pointing back at the beginning of the object.
Definition object-inl.h:241
simdjson_result< value > at_path(std::string_view json_path) noexcept
Get the value associated with the given JSONPath expression.
Definition object-inl.h:172
simdjson_result< value > at_pointer(std::string_view json_pointer) noexcept
Get the value associated with the given JSON pointer.
Definition object-inl.h:132
simdjson_inline simdjson_result< object_iterator > begin() noexcept
Get an iterator to the start of the object.
Definition object-inl.h:122
simdjson_inline simdjson_result< size_t > count_fields() &noexcept
This method scans the object and counts the number of key-value pairs.
Definition object-inl.h:222
A string escaped per JSON rules, terminated with quote (").
An ephemeral JSON value returned during iteration.
Definition value.h:22
simdjson_inline 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...
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
@ NO_SUCH_FIELD
JSON field not found in object.
Definition error.h:40
@ 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:280
simdjson_inline error_code error() const noexcept
The error.
Definition error-inl.h:168