simdjson 5.0.2
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#include <utility>
14#if SIMDJSON_SUPPORTS_CONCEPTS
15#include <tuple> // std::forward_as_tuple/get for the variadic for_each adapter
16#endif
17#if SIMDJSON_STATIC_REFLECTION
18#include "simdjson/generic/ondemand/json_string_builder.h" // for constevalutil::fixed_string
19#include <meta>
20#endif
21#endif // SIMDJSON_CONDITIONAL_INCLUDE
22
23namespace simdjson {
24namespace SIMDJSON_IMPLEMENTATION {
25namespace ondemand {
26
27simdjson_inline simdjson_result<value> object::find_field_unordered(const std::string_view key) & noexcept {
28 bool has_value;
29 SIMDJSON_TRY( iter.find_field_unordered_raw(key).get(has_value) );
30 if (!has_value) {
31 logger::log_line(iter.json_iter(), "ERROR: ", "Cannot find key %.*s", "", -1, 0, logger::log_level::error, static_cast<int>(key.size()), key.data());
32 return NO_SUCH_FIELD;
33 }
34 return value(iter.child());
35}
36simdjson_inline simdjson_result<value> object::find_field_unordered(const std::string_view key) && noexcept {
37 bool has_value;
38 SIMDJSON_TRY( iter.find_field_unordered_raw(key).get(has_value) );
39 if (!has_value) {
40 logger::log_line(iter.json_iter(), "ERROR: ", "Cannot find key %.*s", "", -1, 0, logger::log_level::error, static_cast<int>(key.size()), key.data());
41 return NO_SUCH_FIELD;
42 }
43 return value(iter.child());
44}
45simdjson_inline simdjson_result<value> object::operator[](const std::string_view key) & noexcept {
46#if SIMDJSON_DEVELOPMENT_CHECKS
47 if (locked) return OUT_OF_ORDER_ITERATION;
48#endif
49 return find_field_unordered(key);
50}
51simdjson_inline simdjson_result<value> object::operator[](const std::string_view key) && noexcept {
52#if SIMDJSON_DEVELOPMENT_CHECKS
53 if (locked) return OUT_OF_ORDER_ITERATION;
54#endif
55 return std::forward<object>(*this).find_field_unordered(key);
56}
57simdjson_inline simdjson_result<value> object::find_field(const std::string_view key) & noexcept {
58#if SIMDJSON_DEVELOPMENT_CHECKS
59 if (locked) return OUT_OF_ORDER_ITERATION;
60#endif
61 bool has_value;
62 SIMDJSON_TRY( iter.find_field_raw(key).get(has_value) );
63 if (!has_value) {
64 logger::log_line(iter.json_iter(), "ERROR: ", "Cannot find key %.*s", "", -1, 0, logger::log_level::error, static_cast<int>(key.size()), key.data());
65 return NO_SUCH_FIELD;
66 }
67 return value(iter.child());
68}
69simdjson_inline simdjson_result<value> object::find_field(const std::string_view key) && noexcept {
70#if SIMDJSON_DEVELOPMENT_CHECKS
71 if (locked) return OUT_OF_ORDER_ITERATION;
72#endif
73 bool has_value;
74 SIMDJSON_TRY( iter.find_field_raw(key).get(has_value) );
75 if (!has_value) {
76 logger::log_line(iter.json_iter(), "ERROR: ", "Cannot find key %.*s", "", -1, 0, logger::log_level::error, static_cast<int>(key.size()), key.data());
77 return NO_SUCH_FIELD;
78 }
79 return value(iter.child());
80}
81
82#if SIMDJSON_SUPPORTS_CONCEPTS
83template <typename Selector, typename Func>
84 requires key_selector_type<Selector> &&
85 std::is_invocable_v<Func&, std::size_t, value>
86simdjson_flatten simdjson_inline for_each_result object::for_each(Func&& on_match)
87 noexcept(std::is_nothrow_invocable_v<Func&, std::size_t, value>) {
88 // Single pass driven directly by the value_iterator, mirroring
89 // find_field_unordered_raw + value(iter.child()). Compared to walking via
90 // object_iterator/field, this avoids constructing a simdjson_result<field> and
91 // a field (key + value) for every field -- and the development-check bookkeeping
92 // in object_iterator -- building a value only for the fields that actually match.
93 // We operate on a copy of the iterator, as object::begin() would.
94#if SIMDJSON_DEVELOPMENT_CHECKS
95 // Mirror object::begin(): for_each must start at the beginning of the object,
96 // not from some position left behind by a prior find_field on the same object.
97 if (!iter.is_at_iterator_start()) { return {OUT_OF_ORDER_ITERATION, 0}; }
98#endif
99 value_iterator it = iter;
100 std::size_t matched = 0;
101 // Track which selector indices have already matched, as a compile-time bitset
102 // (one 64-bit word per 64 keys): the callback fires once per key, on its first
103 // occurrence, and we stop as soon as every key has matched.
104 constexpr std::size_t seen_words = (Selector::size() + 63) / 64;
105 std::array<std::uint64_t, seen_words> seen{};
106 while (it.is_open()) {
107 raw_json_string key;
108 error_code error;
109 std::size_t idx;
110 if constexpr (Selector::window.ok) {
111 // A window selector confirms a key from its raw bytes alone (the closing
112 // quote bounds it), so we take the length-free path: field_key (no backward
113 // scan, mirroring the ordered find_field) feeding match_raw(raw_json_string).
114 if ((error = it.field_key().get(key))) { it.abandon(); return {error, matched}; }
115 if ((error = it.field_value())) { it.abandon(); return {error, matched}; }
116 idx = Selector::match_raw(key);
117 } else {
118 // Otherwise derive the key length from the structural index (the following
119 // ':' token) to feed the length-aware hash, avoiding a forward SIMD scan.
120 std::size_t key_len;
121 if ((error = it.field_key_with_length(key, key_len))) { it.abandon(); return {error, matched}; }
122 if ((error = it.field_value())) { it.abandon(); return {error, matched}; }
123 idx = Selector::match_raw(key.raw(), key_len);
124 }
125 if (idx < Selector::size()) {
126 const std::uint64_t seen_bit = std::uint64_t{1} << (idx & 63);
127 std::uint64_t &seen_word = seen[idx >> 6];
128 if (!(seen_word & seen_bit)) {
129 seen_word |= seen_bit;
130 value matched_value(it.child());
131 // The callback may return void or anything convertible to error_code
132 // (error_code itself, or a for_each_result from a nested for_each). When
133 // it yields an error_code, we stop at the first non-SUCCESS result and
134 // propagate it so the caller can surface value-parse errors (for example,
135 // a type mismatch on a matched field). A void-returning callback is
136 // responsible for handling its own errors.
137 if constexpr (std::is_convertible_v<decltype(on_match(idx, matched_value)), error_code>) {
138 // Unlike the internal-error paths above, a callback error does not
139 // abandon the iterator: we leave it recoverable so the caller can keep
140 // using the object (or its parent) after handling the error.
141 if ((error = on_match(idx, matched_value))) { return {error, matched}; }
142 } else {
143 on_match(idx, matched_value);
144 }
145 if (++matched >= Selector::size()) { break; }
146 }
147 }
148 // Mirror object_iterator::operator++'s safety rail: if the callback consumed
149 // the value and left the iterator closed or in error (e.g. a void callback
150 // that swallowed a fatal sub-iteration error), stop here rather than calling
151 // skip_child on a closed iterator.
152 if (!it.is_open()) { break; }
153 // Skip the value (a no-op if the callback consumed it) and step to the next
154 // field; has_next_field() ends the container on '}', which closes the loop.
155 if ((error = it.skip_child())) { it.abandon(); return {error, matched}; }
156 if ((error = it.has_next_field().error())) { return {error, matched}; }
157 }
158 return {SUCCESS, matched};
159}
160
161namespace key_selector_for_each_detail {
162
163// Dispatch a matched value to the I-th handler in the tuple (0-based). A handler
164// is either an invocable taking the value (void- or error_code-returning) or a
165// deserialization target, in which case we assign via value::get. We always
166// return error_code so the core (index, value) for_each can treat the adapter
167// uniformly.
168template <typename Tuple, std::size_t... Is>
169simdjson_really_inline error_code dispatch_value(
170 std::size_t idx, Tuple& handlers, value v, std::index_sequence<Is...>) {
171 error_code err = SUCCESS;
172 auto try_one = [&](auto Ic) {
173 constexpr std::size_t I = decltype(Ic)::value;
174 if (idx == I) {
175 auto&& h = std::get<I>(handlers);
176 using H = std::remove_reference_t<decltype(h)>;
177 if constexpr (std::is_invocable_v<H&, value>) {
178 // A handler returning void runs for its side effects; one returning
179 // anything convertible to error_code (error_code, or a for_each_result
180 // from a nested for_each) has its error captured and propagated.
181 if constexpr (std::is_convertible_v<decltype(h(v)), error_code>) {
182 err = h(v);
183 } else {
184 h(v);
185 }
186 } else {
187 // Direct deserialization target: assign the matched value into it.
188 err = v.get(h);
189 }
190 }
191 };
192 (try_one(std::integral_constant<std::size_t, Is>{}), ...);
193 return err;
194}
195
196} // namespace key_selector_for_each_detail
197
198template <typename Selector, typename... Handlers>
199 requires key_selector_type<Selector> &&
200 (sizeof...(Handlers) == Selector::size()) &&
201 (key_selector_for_each_detail::field_handler<Handlers> && ...)
202simdjson_flatten simdjson_inline for_each_result object::for_each(Handlers&&... on_match)
203 noexcept(key_selector_for_each_detail::nothrow_field_handlers_v<Handlers...>) {
204 auto handlers = std::forward_as_tuple(std::forward<Handlers>(on_match)...);
205 // Reuse the single (index, value) implementation via a tiny adapter.
206 // The adapter is called once per *matched* key (very few); the hot path
207 // (iteration + match_raw + seen bitset) stays exactly the same.
208 return this->template for_each<Selector>(
209 [&](std::size_t i, value v) -> error_code {
210 return key_selector_for_each_detail::dispatch_value(
211 i, handlers, v, std::make_index_sequence<Selector::size()>{});
212 });
213}
214
215template <constevalutil::fixed_string... Keys, typename... Handlers>
216 requires (sizeof...(Handlers) == sizeof...(Keys)) &&
217 (sizeof...(Keys) >= 1) && (sizeof...(Keys) <= 255) &&
218 (key_selector_for_each_detail::field_handler<Handlers> && ...)
219simdjson_inline for_each_result object::for_each(Handlers&&... on_match)
220 noexcept(key_selector_for_each_detail::nothrow_field_handlers_v<Handlers...>) {
221 using Selector = key_selector<Keys...>;
222 return this->template for_each<Selector>(std::forward<Handlers>(on_match)...);
223}
224#endif
225
226simdjson_inline simdjson_result<object> object::start(value_iterator &iter) noexcept {
227 SIMDJSON_TRY( iter.start_object().error() );
228 return object(iter);
229}
230simdjson_inline simdjson_result<object> object::start_root(value_iterator &iter) noexcept {
231 SIMDJSON_TRY( iter.start_root_object().error() );
232 return object(iter);
233}
234simdjson_warn_unused simdjson_inline error_code object::consume() noexcept {
235 if(iter.is_at_key()) {
249 simdjson_unused raw_json_string actual_key;
250 auto error = iter.field_key().get(actual_key);
251 if (error) { iter.abandon(); return error; };
252 // Let us move to the value while we are at it.
253 if ((error = iter.field_value())) { iter.abandon(); return error; }
254 }
255 auto error_skip = iter.json_iter().skip_child(iter.depth()-1);
256 if(error_skip) { iter.abandon(); }
257 return error_skip;
258}
259
261#if SIMDJSON_DEVELOPMENT_CHECKS
262 if (locked) return OUT_OF_ORDER_ITERATION;
263#endif
264 const uint8_t * starting_point{iter.peek_start()};
265 auto error = consume();
266 if(error) { return error; }
267 const uint8_t * final_point{iter._json_iter->peek()};
268 return std::string_view(reinterpret_cast<const char*>(starting_point), size_t(final_point - starting_point));
269}
270
271simdjson_inline simdjson_result<object> object::started(value_iterator &iter) noexcept {
272 SIMDJSON_TRY( iter.started_object().error() );
273 return object(iter);
274}
275
276simdjson_inline object object::resume(const value_iterator &iter) noexcept {
277 return iter;
278}
279
280simdjson_inline object::object(const value_iterator &_iter) noexcept
281 : iter{_iter}
282{
283}
284
286#if SIMDJSON_DEVELOPMENT_CHECKS
287 if (!iter.is_at_iterator_start() || locked) { return OUT_OF_ORDER_ITERATION; }
288 return object_iterator(iter, this);
289#endif
290 return object_iterator(iter);
291}
292simdjson_inline simdjson_result<object_iterator> object::begin() && noexcept {
293#if SIMDJSON_DEVELOPMENT_CHECKS
294 // The object is a temporary that the iterator may outlive: do not lock it.
295 if (!iter.is_at_iterator_start() || locked) { return OUT_OF_ORDER_ITERATION; }
296#endif
297 return object_iterator(iter);
298}
299simdjson_inline simdjson_result<object_iterator> object::end() noexcept {
300 return object_iterator(iter);
301}
302
303inline simdjson_result<value> object::at_pointer(std::string_view json_pointer) noexcept {
304 if (json_pointer[0] != '/') { return INVALID_JSON_POINTER; }
305 json_pointer = json_pointer.substr(1);
306 size_t slash = json_pointer.find('/');
307 std::string_view key = json_pointer.substr(0, slash);
308 // Grab the child with the given key
310
311 // If there is an escape character in the key, unescape it and then get the child.
312 size_t escape = key.find('~');
313 if (escape != std::string_view::npos) {
314 // Unescape the key
315 std::string unescaped(key);
316 do {
317 switch (unescaped[escape+1]) {
318 case '0':
319 unescaped.replace(escape, 2, "~");
320 break;
321 case '1':
322 unescaped.replace(escape, 2, "/");
323 break;
324 default:
325 return INVALID_JSON_POINTER; // "Unexpected ~ escape character in JSON pointer");
326 }
327 escape = unescaped.find('~', escape+1);
328 } while (escape != std::string::npos);
329 child = find_field(unescaped); // Take note find_field does not unescape keys when matching
330 } else {
331 child = find_field(key);
332 }
333 if(child.error()) {
334 return child; // we do not continue if there was an error
335 }
336 // If there is a /, we have to recurse and look up more of the path
337 if (slash != std::string_view::npos) {
338 child = child.at_pointer(json_pointer.substr(slash));
339 }
340 return child;
341}
342
343inline simdjson_result<value> object::at_path(std::string_view json_path) noexcept {
344 auto json_pointer = json_path_to_pointer_conversion(json_path);
345 if (json_pointer == "-1") {
347 }
348 return at_pointer(json_pointer);
349}
350
351#if SIMDJSON_SUPPORTS_CONCEPTS
352template <typename Func>
353 requires std::invocable<Func, value>
354#else
355template <typename Func>
356#endif
357inline error_code object::for_each_at_path_with_wildcard(std::string_view json_path, Func&& callback) noexcept {
358 auto result_pair = get_next_key_and_json_path(json_path);
359 std::string_view key = result_pair.first;
360 std::string_view remaining_path = result_pair.second;
361 // Empty key means the path segment could not be parsed (including malformed
362 // bracket-quoted keys). Match DOM at_path_with_wildcard and avoid treating
363 // "no progress" as a recursive lookup of "".
364 if (key.empty()) {
366 }
367 // Handle when its the case for wildcard
368 if (key == "*") {
369 // Loop through each field in the object
370 for (auto field : *this) {
371 value val;
372 SIMDJSON_TRY(field.value().get(val));
373 if (remaining_path.empty()) {
374 callback(val);
375 } else {
376 SIMDJSON_TRY(val.for_each_at_path_with_wildcard(remaining_path, callback));
377 }
378 }
379 return SUCCESS;
380 } else {
381 value val;
382 SIMDJSON_TRY(find_field(key).get(val));
383
384 if (remaining_path.empty()) {
385 callback(val);
386 return SUCCESS;
387 } else {
388 return val.for_each_at_path_with_wildcard(remaining_path, callback);
389 }
390 }
391}
392
393simdjson_inline simdjson_result<size_t> object::count_fields() & noexcept {
394 size_t count{0};
395 // Important: we do not consume any of the values.
396 for(simdjson_unused auto v : *this) { count++; }
397 // The above loop will always succeed, but we want to report errors.
398 if(iter.error()) { return iter.error(); }
399 // We need to move back at the start because we expect users to iterate through
400 // the object after counting the number of elements.
401 iter.reset_object();
402 return count;
403}
404
405simdjson_inline simdjson_result<bool> object::is_empty() & noexcept {
406#if SIMDJSON_DEVELOPMENT_CHECKS
407 if (locked) return OUT_OF_ORDER_ITERATION;
408#endif
409 bool is_not_empty;
410 auto error = iter.reset_object().get(is_not_empty);
411 if(error) { return error; }
412 return !is_not_empty;
413}
414
415simdjson_inline simdjson_result<bool> object::reset() & noexcept {
416#if SIMDJSON_DEVELOPMENT_CHECKS
417 if (locked) return OUT_OF_ORDER_ITERATION;
418#endif
419 return iter.reset_object();
420}
421
422simdjson_inline object_position object::get_current_position() const noexcept {
423 return object_position{iter.position(), iter.json_iter().depth()};
424}
425
426simdjson_inline error_code object::revert_position(object_position position) noexcept {
427#if SIMDJSON_DEVELOPMENT_CHECKS
428 if (locked) return OUT_OF_ORDER_ITERATION;
429#endif
430 // json_iterator::reenter_child() requires the live depth to be exactly
431 // one level shallower than the target (matching how every other depth
432 // transition in this iterator works), and under SIMDJSON_DEVELOPMENT_CHECKS
433 // additionally validates against the parser's per-depth container-start
434 // bookkeeping. Neither applies here: depending on what was captured and
435 // what has happened since (a scalar field fully consumed, a compound
436 // value left open, a find_field() miss that scanned past everything),
437 // the live depth when reverting can be any number of levels away from
438 // the captured one, and the captured depth is not necessarily a
439 // container's own start. reenter_at() moves directly, matching how
440 // reset_object() itself repositions without going through reenter_child().
441 iter.reenter_at(position.position, position.depth);
442 return SUCCESS;
443}
444
445#if SIMDJSON_DEVELOPMENT_CHECKS
446simdjson_inline void object::set_locked(bool _locked) noexcept {
447 locked = _locked;
448}
449#endif
450
451#if SIMDJSON_SUPPORTS_CONCEPTS && SIMDJSON_STATIC_REFLECTION
452
453template<constevalutil::fixed_string... FieldNames, typename T>
454 requires(std::is_class_v<T> && (sizeof...(FieldNames) > 0))
455simdjson_warn_unused simdjson_inline error_code object::extract_into(T& out) & noexcept {
456 // Helper to check if a field name matches any of the requested fields
457 auto should_extract = [](std::string_view field_name) constexpr -> bool {
458 return ((FieldNames.view() == field_name) || ...);
459 };
460
461 // Iterate through all members of T using reflection
462 template for (constexpr auto mem : std::define_static_array(
463 std::meta::nonstatic_data_members_of(^^T, std::meta::access_context::unchecked()))) {
464
465 if constexpr (!std::meta::is_const(mem) && std::meta::is_public(mem)) {
466 constexpr std::string_view key = std::define_static_string(std::meta::identifier_of(mem));
467
468 // Only extract this field if it's in our list of requested fields
469 if constexpr (should_extract(key)) {
470 // Try to find and extract the field
471 if constexpr (concepts::optional_type<decltype(out.[:mem:])>) {
472 // For optional fields, it's ok if they're missing
473 auto field_result = find_field_unordered(key);
474 if (!field_result.error()) {
475 auto error = field_result.get(out.[:mem:]);
476 if (error && error != NO_SUCH_FIELD) {
477 return error;
478 }
479 } else if (field_result.error() != NO_SUCH_FIELD) {
480 return field_result.error();
481 } else {
482 out.[:mem:].reset();
483 }
484 } else {
485 // For required fields (in the requested list), fail if missing
486 SIMDJSON_TRY((*this)[key].get(out.[:mem:]));
487 }
488 }
489 }
490 };
491
492 return SUCCESS;
493}
494
495#endif // SIMDJSON_SUPPORTS_CONCEPTS && SIMDJSON_STATIC_REFLECTION
496
497} // namespace ondemand
498} // namespace SIMDJSON_IMPLEMENTATION
499} // namespace simdjson
500
501namespace simdjson {
502
503simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object>::simdjson_result(SIMDJSON_IMPLEMENTATION::ondemand::object &&value) noexcept
504 : implementation_simdjson_result_base<SIMDJSON_IMPLEMENTATION::ondemand::object>(std::forward<SIMDJSON_IMPLEMENTATION::ondemand::object>(value)) {}
505simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object>::simdjson_result(error_code error) noexcept
506 : implementation_simdjson_result_base<SIMDJSON_IMPLEMENTATION::ondemand::object>(error) {}
507
508simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object_iterator> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object>::begin() & noexcept {
509 if (error()) { return error(); }
510 return first.begin();
511}
512simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object_iterator> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object>::begin() && noexcept {
513 if (error()) { return error(); }
514 return std::move(first).begin();
515}
516simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object_iterator> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object>::end() noexcept {
517 if (error()) { return error(); }
518 return first.end();
519}
520simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object>::find_field_unordered(std::string_view key) & noexcept {
521 if (error()) { return error(); }
522 return first.find_field_unordered(key);
523}
524simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object>::find_field_unordered(std::string_view key) && noexcept {
525 if (error()) { return error(); }
526 return std::forward<SIMDJSON_IMPLEMENTATION::ondemand::object>(first).find_field_unordered(key);
527}
528simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object>::operator[](std::string_view key) & noexcept {
529 if (error()) { return error(); }
530 return first[key];
531}
532simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object>::operator[](std::string_view key) && noexcept {
533 if (error()) { return error(); }
534 return std::forward<SIMDJSON_IMPLEMENTATION::ondemand::object>(first)[key];
535}
536simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object>::find_field(std::string_view key) & noexcept {
537 if (error()) { return error(); }
538 return first.find_field(key);
539}
540simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object>::find_field(std::string_view key) && noexcept {
541 if (error()) { return error(); }
542 return std::forward<SIMDJSON_IMPLEMENTATION::ondemand::object>(first).find_field(key);
543}
544
545simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object>::at_pointer(std::string_view json_pointer) noexcept {
546 if (error()) { return error(); }
547 return first.at_pointer(json_pointer);
548}
549
550simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object>::at_path(
551 std::string_view json_path) noexcept {
552 if (error()) {
553 return error();
554 }
555 return first.at_path(json_path);
556}
557
558#if SIMDJSON_SUPPORTS_CONCEPTS
559template <typename Func>
560 requires std::invocable<Func, SIMDJSON_IMPLEMENTATION::ondemand::value>
561#else
562template <typename Func>
563#endif
564simdjson_inline error_code simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object>::for_each_at_path_with_wildcard(std::string_view json_path, Func&& callback) noexcept {
565 if (error()) { return error(); }
566 return first.for_each_at_path_with_wildcard(json_path, std::forward<Func>(callback));
567}
568
569#if SIMDJSON_SUPPORTS_CONCEPTS
570template <typename Selector, typename Func>
571 requires SIMDJSON_IMPLEMENTATION::ondemand::key_selector_type<Selector> &&
572 std::is_invocable_v<Func&, std::size_t, SIMDJSON_IMPLEMENTATION::ondemand::value>
573simdjson_inline SIMDJSON_IMPLEMENTATION::ondemand::for_each_result
574simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object>::for_each(Func&& on_match)
575 noexcept(std::is_nothrow_invocable_v<Func&, std::size_t, SIMDJSON_IMPLEMENTATION::ondemand::value>) {
576 if (error()) { return {error(), 0}; }
577 return first.template for_each<Selector>(std::forward<Func>(on_match));
578}
579
580template <typename Selector, typename... Handlers>
581 requires SIMDJSON_IMPLEMENTATION::ondemand::key_selector_type<Selector> &&
582 (sizeof...(Handlers) == Selector::size()) &&
583 (SIMDJSON_IMPLEMENTATION::ondemand::key_selector_for_each_detail::field_handler<Handlers> && ...)
584simdjson_inline SIMDJSON_IMPLEMENTATION::ondemand::for_each_result
585simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object>::for_each(Handlers&&... on_match)
586 noexcept(SIMDJSON_IMPLEMENTATION::ondemand::key_selector_for_each_detail::nothrow_field_handlers_v<Handlers...>) {
587 if (error()) { return {error(), 0}; }
588 return first.template for_each<Selector>(std::forward<Handlers>(on_match)...);
589}
590
591template <constevalutil::fixed_string... Keys, typename... Handlers>
592 requires (sizeof...(Handlers) == sizeof...(Keys)) &&
593 (sizeof...(Keys) >= 1) && (sizeof...(Keys) <= 255) &&
594 (SIMDJSON_IMPLEMENTATION::ondemand::key_selector_for_each_detail::field_handler<Handlers> && ...)
595simdjson_inline SIMDJSON_IMPLEMENTATION::ondemand::for_each_result
596simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object>::for_each(Handlers&&... on_match)
597 noexcept(SIMDJSON_IMPLEMENTATION::ondemand::key_selector_for_each_detail::nothrow_field_handlers_v<Handlers...>) {
598 if (error()) { return {error(), 0}; }
599 return first.template for_each<Keys...>(std::forward<Handlers>(on_match)...);
600}
601#endif
602
603inline simdjson_result<bool> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object>::reset() noexcept {
604 if (error()) { return error(); }
605 return first.reset();
606}
607
608inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object_position> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object>::get_current_position() noexcept {
609 if (error()) { return error(); }
610 return first.get_current_position();
611}
612
613inline error_code simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object>::revert_position(SIMDJSON_IMPLEMENTATION::ondemand::object_position position) noexcept {
614 if (error()) { return error(); }
615 return first.revert_position(position);
616}
617
618inline simdjson_result<bool> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object>::is_empty() noexcept {
619 if (error()) { return error(); }
620 return first.is_empty();
621}
622
623simdjson_inline simdjson_result<size_t> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object>::count_fields() & noexcept {
624 if (error()) { return error(); }
625 return first.count_fields();
626}
627
628simdjson_inline simdjson_result<std::string_view> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object>::raw_json() noexcept {
629 if (error()) { return error(); }
630 return first.raw_json();
631}
632
633} // namespace simdjson
634
635#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:81
A forward-only JSON object field iterator.
Definition object.h:130
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:357
simdjson_inline object_position get_current_position() const noexcept
Get an opaque token representing the object's current scanning position.
Definition object-inl.h:422
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:27
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:260
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:234
simdjson_inline simdjson_result< object_iterator > begin() &noexcept
Get an iterator to the start of the object.
Definition object-inl.h:285
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:57
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:405
simdjson_result< bool > reset() &noexcept
Reset the iterator so that we are pointing back at the beginning of the object.
Definition object-inl.h:415
simdjson_result< value > at_path(std::string_view json_path) noexcept
Get the value associated with the given JSONPath expression.
Definition object-inl.h:343
simdjson_result< value > at_pointer(std::string_view json_pointer) noexcept
Get the value associated with the given JSON pointer.
Definition object-inl.h:303
simdjson_inline error_code revert_position(object_position position) noexcept
Return the object's scanning position to a snapshot previously obtained from get_current_position().
Definition object-inl.h:426
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:393
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...
@ object
A JSON object ( { "a": 1, "b" 2, ... } )
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.
An opaque snapshot of an object's scanning position, obtained from object::get_current_position() and...
Definition object.h:110
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