Coverage Report

Created: 2026-09-28 07:02

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/simdjson/include/simdjson/generic/ondemand/object-inl.h
Line
Count
Source
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
23
namespace simdjson {
24
namespace SIMDJSON_IMPLEMENTATION {
25
namespace ondemand {
26
27
0
simdjson_inline simdjson_result<value> object::find_field_unordered(const std::string_view key) & noexcept {
28
0
  bool has_value;
29
0
  SIMDJSON_TRY( iter.find_field_unordered_raw(key).get(has_value) );
30
0
  if (!has_value) {
31
0
    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
0
    return NO_SUCH_FIELD;
33
0
  }
34
0
  return value(iter.child());
35
0
}
36
0
simdjson_inline simdjson_result<value> object::find_field_unordered(const std::string_view key) && noexcept {
37
0
  bool has_value;
38
0
  SIMDJSON_TRY( iter.find_field_unordered_raw(key).get(has_value) );
39
0
  if (!has_value) {
40
0
    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
0
    return NO_SUCH_FIELD;
42
0
  }
43
0
  return value(iter.child());
44
0
}
45
0
simdjson_inline simdjson_result<value> object::operator[](const std::string_view key) & noexcept {
46
0
#if SIMDJSON_DEVELOPMENT_CHECKS
47
0
  if (locked) return OUT_OF_ORDER_ITERATION;
48
0
#endif
49
0
  return find_field_unordered(key);
50
0
}
51
0
simdjson_inline simdjson_result<value> object::operator[](const std::string_view key) && noexcept {
52
0
#if SIMDJSON_DEVELOPMENT_CHECKS
53
0
  if (locked) return OUT_OF_ORDER_ITERATION;
54
0
#endif
55
0
  return std::forward<object>(*this).find_field_unordered(key);
56
0
}
57
6.83k
simdjson_inline simdjson_result<value> object::find_field(const std::string_view key) & noexcept {
58
6.83k
#if SIMDJSON_DEVELOPMENT_CHECKS
59
6.83k
  if (locked) return OUT_OF_ORDER_ITERATION;
60
6.83k
#endif
61
6.83k
  bool has_value;
62
6.83k
  SIMDJSON_TRY( iter.find_field_raw(key).get(has_value) );
63
5.08k
  if (!has_value) {
64
1.49k
    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
1.49k
    return NO_SUCH_FIELD;
66
1.49k
  }
67
3.58k
  return value(iter.child());
68
5.08k
}
69
0
simdjson_inline simdjson_result<value> object::find_field(const std::string_view key) && noexcept {
70
0
#if SIMDJSON_DEVELOPMENT_CHECKS
71
0
  if (locked) return OUT_OF_ORDER_ITERATION;
72
0
#endif
73
0
  bool has_value;
74
0
  SIMDJSON_TRY( iter.find_field_raw(key).get(has_value) );
75
0
  if (!has_value) {
76
0
    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
0
    return NO_SUCH_FIELD;
78
0
  }
79
0
  return value(iter.child());
80
0
}
81
82
#if SIMDJSON_SUPPORTS_CONCEPTS
83
template <typename Selector, typename Func>
84
  requires key_selector_type<Selector> &&
85
           std::is_invocable_v<Func&, std::size_t, value>
86
simdjson_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
161
namespace 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.
168
template <typename Tuple, std::size_t... Is>
169
simdjson_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
198
template <typename Selector, typename... Handlers>
199
  requires key_selector_type<Selector> &&
200
           (sizeof...(Handlers) == Selector::size()) &&
201
           (key_selector_for_each_detail::field_handler<Handlers> && ...)
202
simdjson_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
215
template <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> && ...)
219
simdjson_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
226
11.6k
simdjson_inline simdjson_result<object> object::start(value_iterator &iter) noexcept {
227
11.6k
  SIMDJSON_TRY( iter.start_object().error() );
228
10.9k
  return object(iter);
229
11.6k
}
230
3.45k
simdjson_inline simdjson_result<object> object::start_root(value_iterator &iter) noexcept {
231
3.45k
  SIMDJSON_TRY( iter.start_root_object().error() );
232
3.42k
  return object(iter);
233
3.45k
}
234
0
simdjson_warn_unused simdjson_inline error_code object::consume() noexcept {
235
0
  if(iter.is_at_key()) {
236
0
    /**
237
0
     * whenever you are pointing at a key, calling skip_child() is
238
0
     * unsafe because you will hit a string and you will assume that
239
0
     * it is string value, and this mistake will lead you to make bad
240
0
     * depth computation.
241
0
     */
242
0
    /**
243
0
     * We want to 'consume' the key. We could really
244
0
     * just do _json_iter->return_current_and_advance(); at this
245
0
     * point, but, for clarity, we will use the high-level API to
246
0
     * eat the key. We assume that the compiler optimizes away
247
0
     * most of the work.
248
0
     */
249
0
    simdjson_unused raw_json_string actual_key;
250
0
    auto error = iter.field_key().get(actual_key);
251
0
    if (error) { iter.abandon(); return error; };
252
0
    // Let us move to the value while we are at it.
253
0
    if ((error = iter.field_value())) { iter.abandon(); return error; }
254
0
  }
255
0
  auto error_skip = iter.json_iter().skip_child(iter.depth()-1);
256
0
  if(error_skip) { iter.abandon(); }
257
0
  return error_skip;
258
0
}
259
260
0
simdjson_inline simdjson_result<std::string_view> object::raw_json() noexcept {
261
0
#if SIMDJSON_DEVELOPMENT_CHECKS
262
0
  if (locked) return OUT_OF_ORDER_ITERATION;
263
0
#endif
264
0
  const uint8_t * starting_point{iter.peek_start()};
265
0
  auto error = consume();
266
0
  if(error) { return error; }
267
0
  const uint8_t * final_point{iter._json_iter->peek()};
268
0
  return std::string_view(reinterpret_cast<const char*>(starting_point), size_t(final_point - starting_point));
269
0
}
270
271
0
simdjson_inline simdjson_result<object> object::started(value_iterator &iter) noexcept {
272
0
  SIMDJSON_TRY( iter.started_object().error() );
273
0
  return object(iter);
274
0
}
275
276
0
simdjson_inline object object::resume(const value_iterator &iter) noexcept {
277
0
  return iter;
278
0
}
279
280
simdjson_inline object::object(const value_iterator &_iter) noexcept
281
14.3k
  : iter{_iter}
282
14.3k
{
283
14.3k
}
284
285
6.13k
simdjson_inline simdjson_result<object_iterator> object::begin() noexcept {
286
6.13k
#if SIMDJSON_DEVELOPMENT_CHECKS
287
6.13k
  if (!iter.is_at_iterator_start() || locked) { return OUT_OF_ORDER_ITERATION; }
288
6.13k
  return object_iterator(iter, this);
289
0
#endif
290
0
  return object_iterator(iter);
291
6.13k
}
292
6.13k
simdjson_inline simdjson_result<object_iterator> object::end() noexcept {
293
6.13k
  return object_iterator(iter);
294
6.13k
}
295
296
3.54k
inline simdjson_result<value> object::at_pointer(std::string_view json_pointer) noexcept {
297
3.54k
  if (json_pointer[0] != '/') { return INVALID_JSON_POINTER; }
298
3.54k
  json_pointer = json_pointer.substr(1);
299
3.54k
  size_t slash = json_pointer.find('/');
300
3.54k
  std::string_view key = json_pointer.substr(0, slash);
301
  // Grab the child with the given key
302
3.54k
  simdjson_result<value> child;
303
304
  // If there is an escape character in the key, unescape it and then get the child.
305
3.54k
  size_t escape = key.find('~');
306
3.54k
  if (escape != std::string_view::npos) {
307
    // Unescape the key
308
849
    std::string unescaped(key);
309
512k
    do {
310
512k
      switch (unescaped[escape+1]) {
311
106k
        case '0':
312
106k
          unescaped.replace(escape, 2, "~");
313
106k
          break;
314
405k
        case '1':
315
405k
          unescaped.replace(escape, 2, "/");
316
405k
          break;
317
0
        default:
318
0
          return INVALID_JSON_POINTER; // "Unexpected ~ escape character in JSON pointer");
319
512k
      }
320
512k
      escape = unescaped.find('~', escape+1);
321
512k
    } while (escape != std::string::npos);
322
849
    child = find_field(unescaped);  // Take note find_field does not unescape keys when matching
323
2.69k
  } else {
324
2.69k
    child = find_field(key);
325
2.69k
  }
326
3.54k
  if(child.error()) {
327
1.76k
    return child; // we do not continue if there was an error
328
1.76k
  }
329
  // If there is a /, we have to recurse and look up more of the path
330
1.77k
  if (slash != std::string_view::npos) {
331
1.73k
    child = child.at_pointer(json_pointer.substr(slash));
332
1.73k
  }
333
1.77k
  return child;
334
3.54k
}
335
336
1.71k
inline simdjson_result<value> object::at_path(std::string_view json_path) noexcept {
337
1.71k
  auto json_pointer = json_path_to_pointer_conversion(json_path);
338
1.71k
  if (json_pointer == "-1") {
339
158
    return INVALID_JSON_POINTER;
340
158
  }
341
1.55k
  return at_pointer(json_pointer);
342
1.71k
}
343
344
#if SIMDJSON_SUPPORTS_CONCEPTS
345
template <typename Func>
346
  requires std::invocable<Func, value>
347
#else
348
template <typename Func>
349
#endif
350
9.90k
inline error_code object::for_each_at_path_with_wildcard(std::string_view json_path, Func&& callback) noexcept {
351
9.90k
  auto result_pair = get_next_key_and_json_path(json_path);
352
9.90k
  std::string_view key = result_pair.first;
353
9.90k
  std::string_view remaining_path = result_pair.second;
354
  // Empty key means the path segment could not be parsed (including malformed
355
  // bracket-quoted keys). Match DOM at_path_with_wildcard and avoid treating
356
  // "no progress" as a recursive lookup of "".
357
9.90k
  if (key.empty()) {
358
476
    return INVALID_JSON_POINTER;
359
476
  }
360
  // Handle when its the case for wildcard
361
9.43k
  if (key == "*") {
362
    // Loop through each field in the object
363
12.2k
    for (auto field : *this) {
364
12.2k
      value val;
365
12.2k
      SIMDJSON_TRY(field.value().get(val));
366
11.7k
      if (remaining_path.empty()) {
367
5.95k
        callback(val);
368
5.95k
      } else {
369
5.81k
        SIMDJSON_TRY(val.for_each_at_path_with_wildcard(remaining_path, callback));
370
5.47k
      }
371
11.7k
    }
372
5.34k
    return SUCCESS;
373
6.13k
  } else {
374
3.29k
    value val;
375
3.29k
    SIMDJSON_TRY(find_field(key).get(val));
376
377
1.81k
    if (remaining_path.empty()) {
378
534
      callback(val);
379
534
      return SUCCESS;
380
1.27k
    } else {
381
1.27k
      return val.for_each_at_path_with_wildcard(remaining_path, callback);
382
1.27k
    }
383
1.81k
  }
384
9.43k
}
fuzz_atpath.cpp:simdjson::error_code simdjson::fallback::ondemand::object::for_each_at_path_with_wildcard<(anonymous namespace)::fuzz_ondemand(std::__1::basic_string_view<char, std::__1::char_traits<char> >, std::__1::basic_string_view<char, std::__1::char_traits<char> >)::$_0&>(std::__1::basic_string_view<char, std::__1::char_traits<char> >, (anonymous namespace)::fuzz_ondemand(std::__1::basic_string_view<char, std::__1::char_traits<char> >, std::__1::basic_string_view<char, std::__1::char_traits<char> >)::$_0&)
Line
Count
Source
350
8.19k
inline error_code object::for_each_at_path_with_wildcard(std::string_view json_path, Func&& callback) noexcept {
351
8.19k
  auto result_pair = get_next_key_and_json_path(json_path);
352
8.19k
  std::string_view key = result_pair.first;
353
8.19k
  std::string_view remaining_path = result_pair.second;
354
  // Empty key means the path segment could not be parsed (including malformed
355
  // bracket-quoted keys). Match DOM at_path_with_wildcard and avoid treating
356
  // "no progress" as a recursive lookup of "".
357
8.19k
  if (key.empty()) {
358
209
    return INVALID_JSON_POINTER;
359
209
  }
360
  // Handle when its the case for wildcard
361
7.98k
  if (key == "*") {
362
    // Loop through each field in the object
363
6.35k
    for (auto field : *this) {
364
6.35k
      value val;
365
6.35k
      SIMDJSON_TRY(field.value().get(val));
366
6.09k
      if (remaining_path.empty()) {
367
3.90k
        callback(val);
368
3.90k
      } else {
369
2.18k
        SIMDJSON_TRY(val.for_each_at_path_with_wildcard(remaining_path, callback));
370
1.96k
      }
371
6.09k
    }
372
5.21k
    return SUCCESS;
373
5.70k
  } else {
374
2.28k
    value val;
375
2.28k
    SIMDJSON_TRY(find_field(key).get(val));
376
377
1.72k
    if (remaining_path.empty()) {
378
529
      callback(val);
379
529
      return SUCCESS;
380
1.19k
    } else {
381
1.19k
      return val.for_each_at_path_with_wildcard(remaining_path, callback);
382
1.19k
    }
383
1.72k
  }
384
7.98k
}
fuzz_atpath.cpp:simdjson::error_code simdjson::fallback::ondemand::object::for_each_at_path_with_wildcard<(anonymous namespace)::fuzz_ondemand(std::__1::basic_string_view<char, std::__1::char_traits<char> >, std::__1::basic_string_view<char, std::__1::char_traits<char> >)::$_0>(std::__1::basic_string_view<char, std::__1::char_traits<char> >, (anonymous namespace)::fuzz_ondemand(std::__1::basic_string_view<char, std::__1::char_traits<char> >, std::__1::basic_string_view<char, std::__1::char_traits<char> >)::$_0&&)
Line
Count
Source
350
1.71k
inline error_code object::for_each_at_path_with_wildcard(std::string_view json_path, Func&& callback) noexcept {
351
1.71k
  auto result_pair = get_next_key_and_json_path(json_path);
352
1.71k
  std::string_view key = result_pair.first;
353
1.71k
  std::string_view remaining_path = result_pair.second;
354
  // Empty key means the path segment could not be parsed (including malformed
355
  // bracket-quoted keys). Match DOM at_path_with_wildcard and avoid treating
356
  // "no progress" as a recursive lookup of "".
357
1.71k
  if (key.empty()) {
358
267
    return INVALID_JSON_POINTER;
359
267
  }
360
  // Handle when its the case for wildcard
361
1.44k
  if (key == "*") {
362
    // Loop through each field in the object
363
5.86k
    for (auto field : *this) {
364
5.86k
      value val;
365
5.86k
      SIMDJSON_TRY(field.value().get(val));
366
5.68k
      if (remaining_path.empty()) {
367
2.05k
        callback(val);
368
3.63k
      } else {
369
3.63k
        SIMDJSON_TRY(val.for_each_at_path_with_wildcard(remaining_path, callback));
370
3.51k
      }
371
5.68k
    }
372
136
    return SUCCESS;
373
1.01k
  } else {
374
1.01k
    value val;
375
1.01k
    SIMDJSON_TRY(find_field(key).get(val));
376
377
91
    if (remaining_path.empty()) {
378
5
      callback(val);
379
5
      return SUCCESS;
380
86
    } else {
381
86
      return val.for_each_at_path_with_wildcard(remaining_path, callback);
382
86
    }
383
91
  }
384
1.44k
}
385
386
0
simdjson_inline simdjson_result<size_t> object::count_fields() & noexcept {
387
0
  size_t count{0};
388
0
  // Important: we do not consume any of the values.
389
0
  for(simdjson_unused auto v : *this) { count++; }
390
0
  // The above loop will always succeed, but we want to report errors.
391
0
  if(iter.error()) { return iter.error(); }
392
0
  // We need to move back at the start because we expect users to iterate through
393
0
  // the object after counting the number of elements.
394
0
  iter.reset_object();
395
0
  return count;
396
0
}
397
398
0
simdjson_inline simdjson_result<bool> object::is_empty() & noexcept {
399
0
#if SIMDJSON_DEVELOPMENT_CHECKS
400
0
  if (locked) return OUT_OF_ORDER_ITERATION;
401
0
#endif
402
0
  bool is_not_empty;
403
0
  auto error = iter.reset_object().get(is_not_empty);
404
0
  if(error) { return error; }
405
0
  return !is_not_empty;
406
0
}
407
408
0
simdjson_inline simdjson_result<bool> object::reset() & noexcept {
409
0
#if SIMDJSON_DEVELOPMENT_CHECKS
410
0
  if (locked) return OUT_OF_ORDER_ITERATION;
411
0
#endif
412
0
  return iter.reset_object();
413
0
}
414
415
0
simdjson_inline object_position object::get_current_position() const noexcept {
416
0
  return object_position{iter.position(), iter.json_iter().depth()};
417
0
}
418
419
0
simdjson_inline error_code object::revert_position(object_position position) noexcept {
420
0
#if SIMDJSON_DEVELOPMENT_CHECKS
421
0
  if (locked) return OUT_OF_ORDER_ITERATION;
422
0
#endif
423
0
  // json_iterator::reenter_child() requires the live depth to be exactly
424
0
  // one level shallower than the target (matching how every other depth
425
0
  // transition in this iterator works), and under SIMDJSON_DEVELOPMENT_CHECKS
426
0
  // additionally validates against the parser's per-depth container-start
427
0
  // bookkeeping. Neither applies here: depending on what was captured and
428
0
  // what has happened since (a scalar field fully consumed, a compound
429
0
  // value left open, a find_field() miss that scanned past everything),
430
0
  // the live depth when reverting can be any number of levels away from
431
0
  // the captured one, and the captured depth is not necessarily a
432
0
  // container's own start. reenter_at() moves directly, matching how
433
0
  // reset_object() itself repositions without going through reenter_child().
434
0
  iter.reenter_at(position.position, position.depth);
435
0
  return SUCCESS;
436
0
}
437
438
#if SIMDJSON_DEVELOPMENT_CHECKS
439
12.2k
simdjson_inline void object::set_locked(bool _locked) noexcept {
440
12.2k
  locked = _locked;
441
12.2k
}
442
#endif
443
444
#if SIMDJSON_SUPPORTS_CONCEPTS && SIMDJSON_STATIC_REFLECTION
445
446
template<constevalutil::fixed_string... FieldNames, typename T>
447
  requires(std::is_class_v<T> && (sizeof...(FieldNames) > 0))
448
simdjson_warn_unused simdjson_inline error_code object::extract_into(T& out) & noexcept {
449
  // Helper to check if a field name matches any of the requested fields
450
  auto should_extract = [](std::string_view field_name) constexpr -> bool {
451
    return ((FieldNames.view() == field_name) || ...);
452
  };
453
454
  // Iterate through all members of T using reflection
455
  template for (constexpr auto mem : std::define_static_array(
456
      std::meta::nonstatic_data_members_of(^^T, std::meta::access_context::unchecked()))) {
457
458
    if constexpr (!std::meta::is_const(mem) && std::meta::is_public(mem)) {
459
      constexpr std::string_view key = std::define_static_string(std::meta::identifier_of(mem));
460
461
      // Only extract this field if it's in our list of requested fields
462
      if constexpr (should_extract(key)) {
463
        // Try to find and extract the field
464
        if constexpr (concepts::optional_type<decltype(out.[:mem:])>) {
465
          // For optional fields, it's ok if they're missing
466
          auto field_result = find_field_unordered(key);
467
          if (!field_result.error()) {
468
            auto error = field_result.get(out.[:mem:]);
469
            if (error && error != NO_SUCH_FIELD) {
470
              return error;
471
            }
472
          } else if (field_result.error() != NO_SUCH_FIELD) {
473
            return field_result.error();
474
          } else {
475
            out.[:mem:].reset();
476
          }
477
        } else {
478
          // For required fields (in the requested list), fail if missing
479
          SIMDJSON_TRY((*this)[key].get(out.[:mem:]));
480
        }
481
      }
482
    }
483
  };
484
485
  return SUCCESS;
486
}
487
488
#endif // SIMDJSON_SUPPORTS_CONCEPTS && SIMDJSON_STATIC_REFLECTION
489
490
} // namespace ondemand
491
} // namespace SIMDJSON_IMPLEMENTATION
492
} // namespace simdjson
493
494
namespace simdjson {
495
496
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object>::simdjson_result(SIMDJSON_IMPLEMENTATION::ondemand::object &&value) noexcept
497
14.3k
    : implementation_simdjson_result_base<SIMDJSON_IMPLEMENTATION::ondemand::object>(std::forward<SIMDJSON_IMPLEMENTATION::ondemand::object>(value)) {}
498
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object>::simdjson_result(error_code error) noexcept
499
830
    : implementation_simdjson_result_base<SIMDJSON_IMPLEMENTATION::ondemand::object>(error) {}
500
501
0
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object_iterator> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object>::begin() noexcept {
502
0
  if (error()) { return error(); }
503
0
  return first.begin();
504
0
}
505
0
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object_iterator> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object>::end() noexcept {
506
0
  if (error()) { return error(); }
507
0
  return first.end();
508
0
}
509
0
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object>::find_field_unordered(std::string_view key) & noexcept {
510
0
  if (error()) { return error(); }
511
0
  return first.find_field_unordered(key);
512
0
}
513
0
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object>::find_field_unordered(std::string_view key) && noexcept {
514
0
  if (error()) { return error(); }
515
0
  return std::forward<SIMDJSON_IMPLEMENTATION::ondemand::object>(first).find_field_unordered(key);
516
0
}
517
0
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object>::operator[](std::string_view key) & noexcept {
518
0
  if (error()) { return error(); }
519
0
  return first[key];
520
0
}
521
0
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object>::operator[](std::string_view key) && noexcept {
522
0
  if (error()) { return error(); }
523
0
  return std::forward<SIMDJSON_IMPLEMENTATION::ondemand::object>(first)[key];
524
0
}
525
0
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object>::find_field(std::string_view key) & noexcept {
526
0
  if (error()) { return error(); }
527
0
  return first.find_field(key);
528
0
}
529
0
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object>::find_field(std::string_view key) && noexcept {
530
0
  if (error()) { return error(); }
531
0
  return std::forward<SIMDJSON_IMPLEMENTATION::ondemand::object>(first).find_field(key);
532
0
}
533
534
1.98k
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object>::at_pointer(std::string_view json_pointer) noexcept {
535
1.98k
  if (error()) { return error(); }
536
1.98k
  return first.at_pointer(json_pointer);
537
1.98k
}
538
539
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object>::at_path(
540
1.72k
    std::string_view json_path) noexcept {
541
1.72k
  if (error()) {
542
12
    return error();
543
12
  }
544
1.71k
  return first.at_path(json_path);
545
1.72k
}
546
547
#if SIMDJSON_SUPPORTS_CONCEPTS
548
template <typename Func>
549
  requires std::invocable<Func, SIMDJSON_IMPLEMENTATION::ondemand::value>
550
#else
551
template <typename Func>
552
#endif
553
9.91k
simdjson_inline error_code simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object>::for_each_at_path_with_wildcard(std::string_view json_path, Func&& callback) noexcept {
554
9.91k
  if (error()) { return error(); }
555
9.90k
  return first.for_each_at_path_with_wildcard(json_path, std::forward<Func>(callback));
556
9.91k
}
fuzz_atpath.cpp:simdjson::error_code simdjson::simdjson_result<simdjson::fallback::ondemand::object>::for_each_at_path_with_wildcard<(anonymous namespace)::fuzz_ondemand(std::__1::basic_string_view<char, std::__1::char_traits<char> >, std::__1::basic_string_view<char, std::__1::char_traits<char> >)::$_0&>(std::__1::basic_string_view<char, std::__1::char_traits<char> >, (anonymous namespace)::fuzz_ondemand(std::__1::basic_string_view<char, std::__1::char_traits<char> >, std::__1::basic_string_view<char, std::__1::char_traits<char> >)::$_0&)
Line
Count
Source
553
8.19k
simdjson_inline error_code simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object>::for_each_at_path_with_wildcard(std::string_view json_path, Func&& callback) noexcept {
554
8.19k
  if (error()) { return error(); }
555
8.19k
  return first.for_each_at_path_with_wildcard(json_path, std::forward<Func>(callback));
556
8.19k
}
fuzz_atpath.cpp:simdjson::error_code simdjson::simdjson_result<simdjson::fallback::ondemand::object>::for_each_at_path_with_wildcard<(anonymous namespace)::fuzz_ondemand(std::__1::basic_string_view<char, std::__1::char_traits<char> >, std::__1::basic_string_view<char, std::__1::char_traits<char> >)::$_0>(std::__1::basic_string_view<char, std::__1::char_traits<char> >, (anonymous namespace)::fuzz_ondemand(std::__1::basic_string_view<char, std::__1::char_traits<char> >, std::__1::basic_string_view<char, std::__1::char_traits<char> >)::$_0&&)
Line
Count
Source
553
1.72k
simdjson_inline error_code simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object>::for_each_at_path_with_wildcard(std::string_view json_path, Func&& callback) noexcept {
554
1.72k
  if (error()) { return error(); }
555
1.71k
  return first.for_each_at_path_with_wildcard(json_path, std::forward<Func>(callback));
556
1.72k
}
557
558
#if SIMDJSON_SUPPORTS_CONCEPTS
559
template <typename Selector, typename Func>
560
  requires SIMDJSON_IMPLEMENTATION::ondemand::key_selector_type<Selector> &&
561
           std::is_invocable_v<Func&, std::size_t, SIMDJSON_IMPLEMENTATION::ondemand::value>
562
simdjson_inline SIMDJSON_IMPLEMENTATION::ondemand::for_each_result
563
simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object>::for_each(Func&& on_match)
564
    noexcept(std::is_nothrow_invocable_v<Func&, std::size_t, SIMDJSON_IMPLEMENTATION::ondemand::value>) {
565
  if (error()) { return {error(), 0}; }
566
  return first.template for_each<Selector>(std::forward<Func>(on_match));
567
}
568
569
template <typename Selector, typename... Handlers>
570
  requires SIMDJSON_IMPLEMENTATION::ondemand::key_selector_type<Selector> &&
571
           (sizeof...(Handlers) == Selector::size()) &&
572
           (SIMDJSON_IMPLEMENTATION::ondemand::key_selector_for_each_detail::field_handler<Handlers> && ...)
573
simdjson_inline SIMDJSON_IMPLEMENTATION::ondemand::for_each_result
574
simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object>::for_each(Handlers&&... on_match)
575
    noexcept(SIMDJSON_IMPLEMENTATION::ondemand::key_selector_for_each_detail::nothrow_field_handlers_v<Handlers...>) {
576
  if (error()) { return {error(), 0}; }
577
  return first.template for_each<Selector>(std::forward<Handlers>(on_match)...);
578
}
579
580
template <constevalutil::fixed_string... Keys, typename... Handlers>
581
  requires (sizeof...(Handlers) == sizeof...(Keys)) &&
582
           (sizeof...(Keys) >= 1) && (sizeof...(Keys) <= 255) &&
583
           (SIMDJSON_IMPLEMENTATION::ondemand::key_selector_for_each_detail::field_handler<Handlers> && ...)
584
simdjson_inline SIMDJSON_IMPLEMENTATION::ondemand::for_each_result
585
simdjson_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<Keys...>(std::forward<Handlers>(on_match)...);
589
}
590
#endif
591
592
0
inline simdjson_result<bool> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object>::reset() noexcept {
593
0
  if (error()) { return error(); }
594
0
  return first.reset();
595
0
}
596
597
0
inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object_position> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object>::get_current_position() noexcept {
598
0
  if (error()) { return error(); }
599
0
  return first.get_current_position();
600
0
}
601
602
0
inline error_code simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object>::revert_position(SIMDJSON_IMPLEMENTATION::ondemand::object_position position) noexcept {
603
0
  if (error()) { return error(); }
604
0
  return first.revert_position(position);
605
0
}
606
607
0
inline simdjson_result<bool> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object>::is_empty() noexcept {
608
0
  if (error()) { return error(); }
609
0
  return first.is_empty();
610
0
}
611
612
0
simdjson_inline  simdjson_result<size_t> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object>::count_fields() & noexcept {
613
0
  if (error()) { return error(); }
614
0
  return first.count_fields();
615
0
}
616
617
0
simdjson_inline  simdjson_result<std::string_view> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object>::raw_json() noexcept {
618
0
  if (error()) { return error(); }
619
0
  return first.raw_json();
620
0
}
621
622
} // namespace simdjson
623
624
#endif // SIMDJSON_GENERIC_ONDEMAND_OBJECT_INL_H