@@ -140,9 +140,9 @@ namespace glz
140
140
GLZ_MATCH_COLON (); \
141
141
GLZ_SKIP_WS ();
142
142
143
- template <opts Opts, class T , size_t I, class Func , class Tuple , class Value >
143
+ template <opts Opts, class T , size_t I, class Value , class ... SelectedIndex >
144
144
requires (glaze_object_t <T> || reflectable<T>)
145
- void decode_index (Func&& func, Tuple&& tuple, Value&& value, is_context auto && ctx, auto && it, auto && end)
145
+ void decode_index (Value&& value, is_context auto && ctx, auto && it, auto && end, SelectedIndex&&... selected_index )
146
146
{
147
147
static constexpr auto TargetKey = glz::get<I>(reflect<T>::keys);
148
148
static constexpr auto Length = TargetKey.size ();
@@ -200,13 +200,31 @@ namespace glz
200
200
GLZ_SKIP_WS ();
201
201
GLZ_MATCH_COLON ();
202
202
GLZ_SKIP_WS ();
203
+
204
+ using V = refl_t <T, I>;
203
205
204
- // invoke on the value
205
- if constexpr (glaze_object_t <T>) {
206
- std::forward<Func>(func)(get<I>(reflect<T>::values), I);
206
+ if constexpr (const_value_v<V>) {
207
+ if constexpr (Opts.error_on_const_read ) {
208
+ ctx.error = error_code::attempt_const_read;
209
+ }
210
+ else {
211
+ // do not read anything into the const value
212
+ skip_value<JSON>::op<Opts>(ctx, it, end);
213
+ }
207
214
}
208
215
else {
209
- std::forward<Func>(func)(get<I>(std::forward<Tuple>(tuple)), I);
216
+ if constexpr (glaze_object_t <T>) {
217
+ from<JSON, std::remove_cvref_t <V>>::template op<ws_handled<Opts>()>(
218
+ get_member (value, get<I>(reflect<T>::values)), ctx, it, end);
219
+ }
220
+ else {
221
+ from<JSON, std::remove_cvref_t <V>>::template op<ws_handled<Opts>()>(
222
+ get_member (value, get<I>(to_tuple (value))), ctx, it, end);
223
+ }
224
+ }
225
+
226
+ if constexpr (Opts.error_on_missing_keys || is_partial_read<T> || Opts.partial_read ) {
227
+ ((selected_index = I), ...);
210
228
}
211
229
}
212
230
else [[unlikely]] {
@@ -258,10 +276,10 @@ namespace glz
258
276
}
259
277
}
260
278
261
- template <opts Opts, class T , auto & HashInfo, class Func , class Value >
279
+ template <opts Opts, class T , auto & HashInfo, class Value , class ... SelectedIndex >
262
280
requires (glaze_object_t <T> || reflectable<T>)
263
- GLZ_ALWAYS_INLINE constexpr void parse_and_invoke (Func&& func, Value&& value, is_context auto && ctx, auto && it,
264
- auto && end)
281
+ GLZ_ALWAYS_INLINE constexpr void parse_and_invoke (Value&& value, is_context auto && ctx, auto && it,
282
+ auto && end, SelectedIndex&&... selected_index )
265
283
{
266
284
constexpr auto type = HashInfo.type ;
267
285
constexpr auto N = reflect<T>::size;
@@ -271,12 +289,7 @@ namespace glz
271
289
}
272
290
273
291
if constexpr (N == 1 ) {
274
- if constexpr (glaze_object_t <T>) {
275
- decode_index<Opts, T, 0 >(func, nullptr , value, ctx, it, end);
276
- }
277
- else {
278
- decode_index<Opts, T, 0 >(func, to_tuple (value), value, ctx, it, end);
279
- }
292
+ decode_index<Opts, T, 0 >(value, ctx, it, end, selected_index...);
280
293
}
281
294
else {
282
295
const auto index = decode_hash<JSON, T, HashInfo, HashInfo.type >::op (it, end);
@@ -303,23 +316,10 @@ namespace glz
303
316
}
304
317
}
305
318
306
- // We see better performance with an array of function pointers than a glz::jump_table here.
307
- if constexpr (glaze_object_t <T>) {
308
- static constexpr auto decoders = [&]<size_t ... I>(std::index_sequence<I...>) constexpr {
309
- return std::array{&decode_index<Opts, T, I, decltype (func), decltype (nullptr ), decltype (value),
310
- decltype (ctx), decltype (it), decltype (end)>...};
311
- }(std::make_index_sequence<N>{});
312
-
313
- decoders[index ](std::forward<Func>(func), nullptr , value, ctx, it, end);
314
- }
315
- else {
316
- static constexpr auto decoders = [&]<size_t ... I>(std::index_sequence<I...>) constexpr {
317
- return std::array{&decode_index<Opts, T, I, decltype (func), decltype (to_tuple (value)),
318
- decltype (value), decltype (ctx), decltype (it), decltype (end)>...};
319
- }(std::make_index_sequence<N>{});
320
-
321
- decoders[index ](std::forward<Func>(func), to_tuple (value), value, ctx, it, end);
322
- }
319
+ // We see better performance function pointers than a glz::jump_table here.
320
+ visit<N>([&]<size_t I>() {
321
+ decode_index<Opts, T, I>(value, ctx, it, end, selected_index...);
322
+ }, index );
323
323
}
324
324
}
325
325
@@ -1966,35 +1966,21 @@ namespace glz
1966
1966
it = start; // reset the iterator
1967
1967
}
1968
1968
}
1969
-
1970
- parse_and_invoke<Opts, T, hash_info<T>>(
1971
- [&](auto && element, const size_t index ) {
1972
- if constexpr (Opts.error_on_missing_keys || is_partial_read<T> || Opts.partial_read ) {
1973
- fields[index ] = true ;
1974
- }
1975
- else {
1976
- (void )index ;
1977
- }
1978
-
1979
- using V = decltype (get_member (value, element));
1980
-
1981
- if constexpr (const_value_v<V>) {
1982
- if constexpr (Opts.error_on_const_read ) {
1983
- ctx.error = error_code::attempt_const_read;
1984
- }
1985
- else {
1986
- // do not read anything into the const value
1987
- skip_value<JSON>::op<Opts>(ctx, it, end);
1988
- }
1989
- }
1990
- else {
1991
- from<JSON, std::remove_cvref_t <V>>::template op<ws_handled<Opts>()>(
1992
- get_member (value, element), ctx, it, end);
1993
- }
1994
- },
1995
- value, ctx, it, end);
1996
- if (bool (ctx.error )) [[unlikely]]
1997
- return ;
1969
+
1970
+ if constexpr (Opts.error_on_missing_keys || is_partial_read<T> || Opts.partial_read ) {
1971
+ size_t index = num_members;
1972
+ parse_and_invoke<Opts, T, hash_info<T>>(value, ctx, it, end, index );
1973
+ if (bool (ctx.error )) [[unlikely]]
1974
+ return ;
1975
+ if (index < num_members) {
1976
+ fields[index ] = true ;
1977
+ }
1978
+ }
1979
+ else {
1980
+ parse_and_invoke<Opts, T, hash_info<T>>(value, ctx, it, end);
1981
+ if (bool (ctx.error )) [[unlikely]]
1982
+ return ;
1983
+ }
1998
1984
}
1999
1985
else {
2000
1986
// For types like std::map, std::unordered_map
0 commit comments