1#ifndef SIMDJSON_GENERIC_ONDEMAND_OBJECT_INL_H
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"
14#if SIMDJSON_SUPPORTS_CONCEPTS
17#if SIMDJSON_STATIC_REFLECTION
18#include "simdjson/generic/ondemand/json_string_builder.h"
24namespace SIMDJSON_IMPLEMENTATION {
29 SIMDJSON_TRY( iter.find_field_unordered_raw(key).get(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());
34 return value(iter.child());
38 SIMDJSON_TRY( iter.find_field_unordered_raw(key).get(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());
43 return value(iter.child());
46#if SIMDJSON_DEVELOPMENT_CHECKS
49 return find_field_unordered(key);
51simdjson_inline simdjson_result<value> object::operator[](
const std::string_view key) &&
noexcept {
52#if SIMDJSON_DEVELOPMENT_CHECKS
55 return std::forward<object>(*this).find_field_unordered(key);
58#if SIMDJSON_DEVELOPMENT_CHECKS
62 SIMDJSON_TRY( iter.find_field_raw(key).get(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());
67 return value(iter.child());
70#if SIMDJSON_DEVELOPMENT_CHECKS
74 SIMDJSON_TRY( iter.find_field_raw(key).get(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());
79 return value(iter.child());
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>) {
94#if SIMDJSON_DEVELOPMENT_CHECKS
99 value_iterator it = iter;
100 std::size_t matched = 0;
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()) {
110 if constexpr (Selector::window.ok) {
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);
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);
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());
137 if constexpr (std::is_convertible_v<
decltype(on_match(idx, matched_value)),
error_code>) {
141 if ((error = on_match(idx, matched_value))) {
return {error, matched}; }
143 on_match(idx, matched_value);
145 if (++matched >= Selector::size()) {
break; }
152 if (!it.is_open()) {
break; }
155 if ((error = it.skip_child())) { it.abandon();
return {error, matched}; }
156 if ((error = it.has_next_field().error())) {
return {error, matched}; }
161namespace key_selector_for_each_detail {
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...>) {
172 auto try_one = [&](
auto Ic) {
173 constexpr std::size_t I =
decltype(Ic)::value;
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>) {
181 if constexpr (std::is_convertible_v<
decltype(h(v)), error_code>) {
192 (try_one(std::integral_constant<std::size_t, Is>{}), ...);
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)...);
208 return this->
template for_each<Selector>(
210 return key_selector_for_each_detail::dispatch_value(
211 i, handlers, v, std::make_index_sequence<Selector::size()>{});
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)...);
226simdjson_inline simdjson_result<object> object::start(value_iterator &iter)
noexcept {
227 SIMDJSON_TRY( iter.start_object().error() );
230simdjson_inline simdjson_result<object> object::start_root(value_iterator &iter)
noexcept {
231 SIMDJSON_TRY( iter.start_root_object().error() );
235 if(iter.is_at_key()) {
250 auto error = iter.field_key().get(actual_key);
251 if (error) { iter.abandon();
return error; };
253 if ((error = iter.field_value())) { iter.abandon();
return error; }
255 auto error_skip = iter.json_iter().skip_child(iter.depth()-1);
256 if(error_skip) { iter.abandon(); }
261#if SIMDJSON_DEVELOPMENT_CHECKS
264 const uint8_t * starting_point{iter.peek_start()};
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));
272 SIMDJSON_TRY( iter.started_object().error() );
276simdjson_inline
object object::resume(
const value_iterator &iter)
noexcept {
280simdjson_inline
object::object(
const value_iterator &_iter) noexcept
286#if SIMDJSON_DEVELOPMENT_CHECKS
293#if SIMDJSON_DEVELOPMENT_CHECKS
305 json_pointer = json_pointer.substr(1);
306 size_t slash = json_pointer.find(
'/');
307 std::string_view key = json_pointer.substr(0, slash);
312 size_t escape = key.find(
'~');
313 if (escape != std::string_view::npos) {
315 std::string unescaped(key);
317 switch (unescaped[escape+1]) {
319 unescaped.replace(escape, 2,
"~");
322 unescaped.replace(escape, 2,
"/");
327 escape = unescaped.find(
'~', escape+1);
328 }
while (escape != std::string::npos);
329 child = find_field(unescaped);
331 child = find_field(key);
337 if (slash != std::string_view::npos) {
338 child = child.at_pointer(json_pointer.substr(slash));
345 if (json_pointer ==
"-1") {
348 return at_pointer(json_pointer);
351#if SIMDJSON_SUPPORTS_CONCEPTS
352template <
typename Func>
353 requires std::invocable<Func, value>
355template <
typename Func>
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;
370 for (
auto field : *
this) {
373 if (remaining_path.empty()) {
382 SIMDJSON_TRY(find_field(key).get(val));
384 if (remaining_path.empty()) {
396 for(simdjson_unused
auto v : *
this) { count++; }
398 if(iter.error()) {
return iter.
error(); }
406#if SIMDJSON_DEVELOPMENT_CHECKS
410 auto error = iter.reset_object().get(is_not_empty);
411 if(error) {
return error; }
412 return !is_not_empty;
416#if SIMDJSON_DEVELOPMENT_CHECKS
419 return iter.reset_object();
427#if SIMDJSON_DEVELOPMENT_CHECKS
441 iter.reenter_at(position.position, position.depth);
445#if SIMDJSON_DEVELOPMENT_CHECKS
446simdjson_inline
void object::set_locked(
bool _locked)
noexcept {
451#if SIMDJSON_SUPPORTS_CONCEPTS && SIMDJSON_STATIC_REFLECTION
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 {
457 auto should_extract = [](std::string_view field_name)
constexpr ->
bool {
458 return ((FieldNames.view() == field_name) || ...);
462 template for (
constexpr auto mem : std::define_static_array(
463 std::meta::nonstatic_data_members_of(^^T, std::meta::access_context::unchecked()))) {
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));
469 if constexpr (should_extract(key)) {
471 if constexpr (concepts::optional_type<
decltype(out.[:mem:])>) {
473 auto field_result = find_field_unordered(key);
474 if (!field_result.error()) {
475 auto error = field_result.get(out.[:mem:]);
480 return field_result.error();
486 SIMDJSON_TRY((*
this)[key].get(out.[:mem:]));
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) {}
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();
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();
516simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object_iterator> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object>::end() noexcept {
517 if (error()) {
return error(); }
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);
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);
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(); }
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];
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);
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);
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);
550simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object>::at_path(
551 std::string_view json_path)
noexcept {
555 return first.at_path(json_path);
558#if SIMDJSON_SUPPORTS_CONCEPTS
559template <
typename Func>
560 requires std::invocable<Func, SIMDJSON_IMPLEMENTATION::ondemand::value>
562template <
typename Func>
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));
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));
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)...);
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)...);
603inline simdjson_result<bool> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object>::reset() noexcept {
604 if (error()) {
return error(); }
605 return first.reset();
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();
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);
618inline simdjson_result<bool> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object>::is_empty() noexcept {
619 if (error()) {
return error(); }
620 return first.is_empty();
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();
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();
A JSON field (key/value pair) in an object.
simdjson_inline ondemand::value & value() &noexcept
Get the field value.
A forward-only JSON object field iterator.
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...
simdjson_inline object_position get_current_position() const noexcept
Get an opaque token representing the object's current scanning position.
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.
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 ...
simdjson_warn_unused simdjson_inline error_code consume() noexcept
Go to the end of the object, no matter where you are right now.
simdjson_inline simdjson_result< object_iterator > begin() &noexcept
Get an iterator to the start of the object.
simdjson_inline simdjson_result< value > find_field(std::string_view key) &noexcept
Look up a field by name on an object (order-sensitive).
simdjson_result< bool > is_empty() &noexcept
This method scans the beginning of the object and checks whether the object is empty.
simdjson_result< bool > reset() &noexcept
Reset the iterator so that we are pointing back at the beginning of the object.
simdjson_result< value > at_path(std::string_view json_path) noexcept
Get the value associated with the given JSONPath expression.
simdjson_result< value > at_pointer(std::string_view json_pointer) noexcept
Get the value associated with the given JSON pointer.
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().
simdjson_inline simdjson_result< size_t > count_fields() &noexcept
This method scans the object and counts the number of key-value pairs.
A string escaped per JSON rules, terminated with quote (").
An ephemeral JSON value returned during iteration.
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.
error_code
All possible errors returned by simdjson.
@ OUT_OF_ORDER_ITERATION
tried to iterate an array or object out of order (checked when SIMDJSON_DEVELOPMENT_CHECKS=1)
@ NO_SUCH_FIELD
JSON field not found in object.
@ INVALID_JSON_POINTER
Invalid JSON pointer syntax.
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...
The result of a simdjson operation that could fail.
simdjson_inline error_code error() const noexcept
The error.