Skip to content

Commit a86add9

Browse files
committed
allow extra members for converted structs
1 parent 7088b07 commit a86add9

File tree

4 files changed

+193
-70
lines changed

4 files changed

+193
-70
lines changed

include/boost/json/detail/parse_into.hpp

Lines changed: 166 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -711,16 +711,16 @@ struct handler_tuple;
711711

712712
template< class P, template<class...> class L, class... V, std::size_t... I >
713713
struct handler_tuple< P, L<V...>, mp11::index_sequence<I...> >
714-
: handler_tuple_element< I, get_handler<V, P> >
714+
: handler_tuple_element<I, V>
715715
...
716716
{
717717
handler_tuple( handler_tuple const& ) = delete;
718718
handler_tuple& operator=( handler_tuple const& ) = delete;
719719

720720
template< class Access, class T >
721721
handler_tuple( Access access, T* pv, P* pp )
722-
: handler_tuple_element< I, get_handler<V, P> >(
723-
access( pv, mp11::mp_int<I>() ),
722+
: handler_tuple_element<I, V>(
723+
access( pv, mp11::mp_size_t<I>() ),
724724
pp )
725725
...
726726
{ }
@@ -803,10 +803,17 @@ class converting_handler<tuple_conversion_tag, T, P>
803803
{
804804

805805
private:
806+
using ElementTypes = tuple_element_list<T>;
807+
808+
template<class V>
809+
using ElementHandler = get_handler<V, converting_handler>;
810+
using InnerHandlers = mp11::mp_transform<ElementHandler, ElementTypes>;
811+
using HandlerTuple = handler_tuple<converting_handler, InnerHandlers>;
812+
806813
T* value_;
807814
P* parent_;
808815

809-
handler_tuple< converting_handler, tuple_element_list<T> > handlers_;
816+
HandlerTuple handlers_;
810817
int inner_active_ = -1;
811818

812819
public:
@@ -874,7 +881,7 @@ class converting_handler<tuple_conversion_tag, T, P>
874881

875882
struct do_on_array_begin
876883
{
877-
handler_tuple< converting_handler, tuple_element_list<T> >& handlers;
884+
HandlerTuple& handlers;
878885
system::error_code& ec;
879886

880887
template< class I >
@@ -905,7 +912,7 @@ class converting_handler<tuple_conversion_tag, T, P>
905912

906913
struct do_on_array_end
907914
{
908-
handler_tuple< converting_handler, tuple_element_list<T> >& handlers;
915+
HandlerTuple& handlers;
909916
system::error_code& ec;
910917

911918
template< class I >
@@ -966,6 +973,13 @@ using struct_element_list = mp11::mp_transform_q<
966973

967974
struct struct_accessor
968975
{
976+
template< class T >
977+
auto operator()( T*, mp11::mp_size< described_members<T> > ) const
978+
-> void*
979+
{
980+
return nullptr;
981+
}
982+
969983
template< class T, class I >
970984
auto operator()( T* t, I ) const
971985
-> described_member_t<T, mp11::mp_at< described_members<T>, I> >*
@@ -976,16 +990,132 @@ struct struct_accessor
976990
}
977991
};
978992

979-
template< class F >
980993
struct struct_key_searcher
981994
{
982-
F fn;
995+
string_view key;
996+
int& found;
997+
int index = 0;
998+
999+
struct_key_searcher(string_view key, int& found) noexcept
1000+
: key(key), found(found)
1001+
{}
9831002

9841003
template< class D >
9851004
void
986-
operator()( D ) const
1005+
operator()( D )
1006+
{
1007+
if( key == D::name )
1008+
found = index;
1009+
++index;
1010+
}
1011+
};
1012+
1013+
template<class P>
1014+
struct ignoring_handler
1015+
{
1016+
P* parent_;
1017+
std::size_t array_depth_ = 0;
1018+
std::size_t object_depth_ = 0;
1019+
1020+
ignoring_handler(ignoring_handler const&) = delete;
1021+
ignoring_handler& operator=(ignoring_handler const&) = delete;
1022+
1023+
ignoring_handler(void*, P* p) noexcept
1024+
: parent_(p)
1025+
{}
1026+
1027+
bool on_object_begin(system::error_code&)
1028+
{
1029+
++object_depth_;
1030+
return true;
1031+
}
1032+
1033+
bool on_object_end(system::error_code& ec)
1034+
{
1035+
BOOST_ASSERT( object_depth_ > 0 );
1036+
--object_depth_;
1037+
1038+
if( (array_depth_ + object_depth_) == 0 )
1039+
return parent_->signal_value(ec);
1040+
return true;
1041+
}
1042+
1043+
bool on_array_begin(system::error_code&)
1044+
{
1045+
++array_depth_;
1046+
return true;
1047+
}
1048+
1049+
bool on_array_end(system::error_code& ec)
1050+
{
1051+
BOOST_ASSERT( array_depth_ > 0 );
1052+
--array_depth_;
1053+
1054+
if( (array_depth_ + object_depth_) == 0 )
1055+
return parent_->signal_end(ec);
1056+
return true;
1057+
}
1058+
1059+
bool on_key_part(system::error_code&, string_view)
1060+
{
1061+
return true;
1062+
}
1063+
1064+
bool on_key(system::error_code&, string_view)
1065+
{
1066+
return true;
1067+
}
1068+
1069+
bool on_string_part(system::error_code&, string_view)
1070+
{
1071+
return true;
1072+
}
1073+
1074+
bool on_string(system::error_code& ec, string_view)
9871075
{
988-
fn( D::name ) ;
1076+
if( (array_depth_ + object_depth_) == 0 )
1077+
return parent_->signal_value(ec);
1078+
return true;
1079+
}
1080+
1081+
bool on_number_part(system::error_code&)
1082+
{
1083+
return true;
1084+
}
1085+
1086+
bool on_int64(system::error_code& ec, std::int64_t)
1087+
{
1088+
if( (array_depth_ + object_depth_) == 0 )
1089+
return parent_->signal_value(ec);
1090+
return true;
1091+
}
1092+
1093+
bool on_uint64(system::error_code& ec, std::uint64_t)
1094+
{
1095+
if( (array_depth_ + object_depth_) == 0 )
1096+
return parent_->signal_value(ec);
1097+
return true;
1098+
}
1099+
1100+
bool on_double(system::error_code& ec, double)
1101+
{
1102+
if( (array_depth_ + object_depth_) == 0 )
1103+
return parent_->signal_value(ec);
1104+
return true;
1105+
}
1106+
1107+
bool on_bool(system::error_code& ec, bool)
1108+
{
1109+
if( (array_depth_ + object_depth_) == 0 )
1110+
return parent_->signal_value(ec);
1111+
return true;
1112+
}
1113+
1114+
bool on_null(system::error_code& ec)
1115+
{
1116+
if( (array_depth_ + object_depth_) == 0 )
1117+
return parent_->signal_value(ec);
1118+
return true;
9891119
}
9901120
};
9911121

@@ -1000,14 +1130,22 @@ class converting_handler<described_class_conversion_tag, V, P>
10001130
#else
10011131

10021132
private:
1133+
using Dm = described_members<V>;
1134+
using Dt = struct_element_list<V>;
1135+
1136+
template<class T>
1137+
using MemberHandler = get_handler<T, converting_handler>;
1138+
using InnerHandlers = mp11::mp_push_back<
1139+
mp11::mp_transform<MemberHandler, Dt>,
1140+
ignoring_handler<converting_handler> >;
1141+
using InnerCount = mp11::mp_size<InnerHandlers>;
1142+
10031143
V* value_;
10041144
P* parent_;
10051145

10061146
std::string key_;
10071147

1008-
using Dm = described_members<V>;
1009-
1010-
handler_tuple< converting_handler, struct_element_list<V> > handlers_;
1148+
handler_tuple<converting_handler, InnerHandlers> handlers_;
10111149
int inner_active_ = -1;
10121150
std::size_t activated_ = 0;
10131151

@@ -1019,23 +1157,27 @@ class converting_handler<described_class_conversion_tag, V, P>
10191157
: value_(v), parent_(p), handlers_(struct_accessor(), v, this)
10201158
{}
10211159

1022-
struct is_optional_checker
1160+
struct is_required_checker
10231161
{
1162+
bool operator()( mp11::mp_size<Dt> ) const noexcept
1163+
{
1164+
return false;
1165+
}
1166+
10241167
template< class I >
1025-
bool operator()( I ) const noexcept
1168+
auto operator()( I ) const noexcept
10261169
{
1027-
using L = struct_element_list<V>;
1028-
using T = mp11::mp_at<L, I>;
1170+
using T = mp11::mp_at<Dt, I>;
10291171
return !is_optional_like<T>::value;
10301172
}
10311173
};
10321174

10331175
bool signal_value(system::error_code&)
10341176
{
10351177
BOOST_ASSERT( inner_active_ >= 0 );
1036-
bool required_member = mp11::mp_with_index< mp11::mp_size<Dm> >(
1178+
bool required_member = mp11::mp_with_index<InnerCount>(
10371179
inner_active_,
1038-
is_optional_checker{});
1180+
is_required_checker{});
10391181
if( required_member )
10401182
++activated_;
10411183

@@ -1060,7 +1202,7 @@ class converting_handler<described_class_conversion_tag, V, P>
10601202
auto f = [&](auto& handler) { return handler.fn ; }; \
10611203
using F = decltype(f); \
10621204
using H = decltype(handlers_); \
1063-
return mp11::mp_with_index< mp11::mp_size<Dm> >( \
1205+
return mp11::mp_with_index<InnerCount>( \
10641206
inner_active_, \
10651207
tuple_handler_op_invoker<H, F>{handlers_, f} );
10661208

@@ -1076,9 +1218,8 @@ class converting_handler<described_class_conversion_tag, V, P>
10761218
{
10771219
if( inner_active_ < 0 )
10781220
{
1079-
using L = struct_element_list<V>;
1080-
using C = mp11::mp_count_if<L, is_optional_like>;
1081-
constexpr int N = mp11::mp_size<L>::value - C::value;
1221+
using C = mp11::mp_count_if<Dt, is_optional_like>;
1222+
constexpr int N = mp11::mp_size<Dt>::value - C::value;
10821223
if( activated_ < N )
10831224
{
10841225
BOOST_JSON_FAIL( ec, error::size_mismatch );
@@ -1129,24 +1270,8 @@ class converting_handler<described_class_conversion_tag, V, P>
11291270
key = key_;
11301271
}
11311272

1132-
int i = 0;
1133-
1134-
auto f = [&](char const* name)
1135-
{
1136-
if( key == name )
1137-
inner_active_ = i;
1138-
++i;
1139-
};
1140-
1141-
mp11::mp_for_each<Dm>(
1142-
struct_key_searcher<decltype(f)>{f} );
1143-
1144-
if( inner_active_ < 0 )
1145-
{
1146-
BOOST_JSON_FAIL(ec, error::unknown_name);
1147-
return false;
1148-
}
1149-
1273+
inner_active_ = InnerCount::value - 1;
1274+
mp11::mp_for_each<Dm>( struct_key_searcher(key, inner_active_) );
11501275
return true;
11511276
}
11521277

include/boost/json/detail/value_to.hpp

Lines changed: 4 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -346,17 +346,13 @@ value_to_impl(
346346
*arr, ctx, boost::mp11::make_index_sequence<N>());
347347
}
348348

349-
template< class Ctx, class T, bool non_throwing = true >
349+
template< class Ctx, class T >
350350
struct to_described_member
351351
{
352352
using Ds = described_members<T>;
353353

354-
using result_type = mp11::mp_eval_if_c<
355-
!non_throwing, T, system::result, T>;
356-
357-
result_type& res;
354+
system::result<T>& res;
358355
object const& obj;
359-
std::size_t count;
360356
Ctx const& ctx;
361357

362358
template< class I >
@@ -375,7 +371,7 @@ struct to_described_member
375371
BOOST_IF_CONSTEXPR( !is_optional_like<M>::value )
376372
{
377373
system::error_code ec;
378-
BOOST_JSON_FAIL(ec, error::unknown_name);
374+
BOOST_JSON_FAIL(ec, error::size_mismatch);
379375
res = {boost::system::in_place_error, ec};
380376
}
381377
return;
@@ -391,10 +387,7 @@ struct to_described_member
391387
# pragma GCC diagnostic pop
392388
#endif
393389
if( member_res )
394-
{
395390
(*res).* D::pointer = std::move(*member_res);
396-
++count;
397-
}
398391
else
399392
res = {boost::system::in_place_error, member_res.error()};
400393
}
@@ -421,7 +414,7 @@ value_to_impl(
421414
return res;
422415
}
423416

424-
to_described_member< Ctx, T > member_converter{ res, *obj, 0u, ctx };
417+
to_described_member<Ctx, T> member_converter{res, *obj, ctx};
425418

426419
using Ds = typename decltype(member_converter)::Ds;
427420
constexpr std::size_t N = mp11::mp_size<Ds>::value;
@@ -430,14 +423,6 @@ value_to_impl(
430423
if( !res )
431424
return res;
432425

433-
if( member_converter.count != obj->size() )
434-
{
435-
system::error_code ec;
436-
BOOST_JSON_FAIL(ec, error::size_mismatch);
437-
res = {boost::system::in_place_error, ec};
438-
return res;
439-
}
440-
441426
return res;
442427
}
443428

0 commit comments

Comments
 (0)