From 04843f1e144e22493af7f917dc32fc15b010f968 Mon Sep 17 00:00:00 2001 From: Dmitry Arkhipov Date: Sun, 13 Aug 2023 22:58:50 +0300 Subject: [PATCH] refactor parse_into tuple handler --- include/boost/json/detail/parse_into.hpp | 174 ++++++++++++++--------- include/boost/json/impl/conversion.hpp | 21 +++ test/parse_into.cpp | 4 +- 3 files changed, 130 insertions(+), 69 deletions(-) diff --git a/include/boost/json/detail/parse_into.hpp b/include/boost/json/detail/parse_into.hpp index 398cdf36c..49417b9c7 100644 --- a/include/boost/json/detail/parse_into.hpp +++ b/include/boost/json/detail/parse_into.hpp @@ -595,74 +595,94 @@ class converting_handler }; // tuple handler -#if defined(BOOST_MSVC) && BOOST_MSVC < 1910 - -// MSVC 2015 can't handle handler_tuple_impl - -#else +// #if defined(BOOST_MSVC) && BOOST_MSVC < 1910 +// +// // MSVC 2015 can't handle handler_tuple_impl +// +// #else -template struct handler_tuple_element +template +struct handler_tuple_element { + template< class... Args > + handler_tuple_element( Args&& ... args ) + : t_( static_cast(args)... ) + {} + T t_; }; -template struct handler_tuple_impl; +template +T& +get( handler_tuple_element& e ) +{ + return e.t_; +} + +template< + class P, + class LV, + class S = mp11::make_index_sequence::value> > +struct handler_tuple; -template -struct handler_tuple_impl, T...> - : handler_tuple_element... +template< class P, template class L, class... V, std::size_t... I > +struct handler_tuple< P, L, mp11::index_sequence > + : handler_tuple_element< I, get_handler > + ... { - template - handler_tuple_impl( A... a ) - : handler_tuple_element{{ a.first, a.second }}... + handler_tuple( handler_tuple const& ) = delete; + handler_tuple& operator=( handler_tuple const& ) = delete; + + template< class Access, class T > + handler_tuple( Access access, T* pv, P* pp ) + : handler_tuple_element< I, get_handler >( + access( pv, mp11::mp_int() ), pp ) + ... { } }; -template -struct handler_tuple - : public handler_tuple_impl< - mp11::index_sequence_for, get_handler...> -{ - using base_type = handler_tuple_impl< - mp11::index_sequence_for, get_handler...>; +#if defined(BOOST_MSVC) && BOOST_MSVC < 1910 - template - handler_tuple( A... a ) - : base_type( a... ) - { } +template< class T > +struct tuple_element_list_impl +{ + template< class I > + using tuple_element_helper = tuple_element_t; - handler_tuple( handler_tuple const& ) = delete; - handler_tuple& operator=( handler_tuple const& ) = delete; + using type = mp11::mp_transform< + tuple_element_helper, + mp11::mp_iota< std::tuple_size > >; }; +template< class T > +using tuple_element_list = typename tuple_element_list_impl::type; -template -T& -get( handler_tuple_element& e ) -{ - return e.t_; -} +#else -template< class P, class T > -struct tuple_inner_handlers; +template< class I, class T > +using tuple_element_helper = tuple_element_t; +template< class T > +using tuple_element_list = mp11::mp_transform_q< + mp11::mp_bind_back< tuple_element_helper, T>, + mp11::mp_iota< std::tuple_size > >; -template< class P, template class L, class... V > -struct tuple_inner_handlers> -{ - handler_tuple handlers_; +#endif - template - tuple_inner_handlers( - L* pv, P* pp, mp11::index_sequence ) - : handlers_( std::make_pair( &get(*pv), pp )... ) - {} +struct tuple_accessor +{ + template< class T, class I > + auto operator()( T* t, I ) const -> tuple_element_t* + { + using std::get; + return &get(*t); + } }; -#endif +// #endif template< class T, class P > class converting_handler { -#if BOOST_CXX_VERSION < 201400L || ( defined(BOOST_MSVC) && BOOST_MSVC < 1910 ) +#if BOOST_CXX_VERSION < 201400L // || ( defined(BOOST_MSVC) && BOOST_MSVC < 1910 ) static_assert( sizeof(T) == 0, "Tuple support for parse_into requires C++14 or MSVC 2017 or later" ); @@ -673,7 +693,7 @@ class converting_handler T* value_; P* parent_; - tuple_inner_handlers inner_; + handler_tuple< converting_handler, tuple_element_list > handlers_; int inner_active_ = -1; public: @@ -681,12 +701,7 @@ class converting_handler converting_handler& operator=( converting_handler const& ) = delete; converting_handler( T* v, P* p ) - : value_( v ) - , parent_( p ) - , inner_( - v, - this, - mp11::make_index_sequence< std::tuple_size::value >()) + : value_(v) , parent_(p) , handlers_(tuple_accessor(), v, this) {} void signal_value() @@ -713,7 +728,7 @@ class converting_handler return false; \ } \ return mp11::mp_with_index( inner_active_, [&](auto I){ \ - return get( inner_.handlers_ ).fn; \ + return get( handlers_ ).fn; \ }); bool on_object_begin( error_code& ec ) @@ -743,7 +758,7 @@ class converting_handler } return mp11::mp_with_index( inner_active_, [&](auto I){ - return get( inner_.handlers_ ).on_array_begin(ec); + return get( handlers_ ).on_array_begin(ec); }); } @@ -766,7 +781,7 @@ class converting_handler } return mp11::mp_with_index( inner_active_, [&](auto I){ - return get( inner_.handlers_ ).on_array_end( n, ec ); + return get( handlers_ ).on_array_end( n, ec ); }); } @@ -826,23 +841,48 @@ class converting_handler }; // described struct handler -template -struct struct_inner_handlers; +#if defined(BOOST_MSVC) && BOOST_MSVC < 1910 -template class L, class... D> -struct struct_inner_handlers> +template< class T > +struct struct_element_list_impl { - handler_tuple...> handlers_; + template< class D > + using helper = described_member_t; - struct_inner_handlers( T* pv, P* pp ) - : handlers_( std::make_pair( &(pv->*D::pointer), pp )... ) - {} + using type = mp11::mp_transform< + helper, + describe::describe_members >; +}; +template< class T > +using struct_element_list = typename struct_element_list_impl::type; + +#else + +template< class T > +using struct_element_list = mp11::mp_transform_q< + mp11::mp_bind_front< described_member_t, T >, + describe::describe_members >; + +#endif + +struct struct_accessor +{ + template< class T, class I > + auto operator()( T* t, I ) const + -> described_member_t, I> >* + { + using Ds = describe::describe_members; + using D = mp11::mp_at; + return &(t->*D::pointer); + } }; template class converting_handler { -#if BOOST_CXX_VERSION < 201400L || ( defined(BOOST_MSVC) && BOOST_MSVC < 1910 ) +#if BOOST_CXX_VERSION < 201400L // || ( defined(BOOST_MSVC) && BOOST_MSVC < 1910 ) static_assert( sizeof(V) == 0, "Struct support for parse_into requires C++14 or MSVC 2017 or later" ); @@ -857,7 +897,7 @@ class converting_handler using Dm = describe::describe_members; - struct_inner_handlers inner_; + handler_tuple< converting_handler, struct_element_list > handlers_; int inner_active_ = -1; public: @@ -865,7 +905,7 @@ class converting_handler converting_handler& operator=( converting_handler const& ) = delete; converting_handler( V* v, P* p ) - : value_(v), parent_(p), inner_(v, this) + : value_(v), parent_(p), handlers_(struct_accessor(), v, this) {} void signal_value() @@ -889,7 +929,7 @@ class converting_handler return false; \ } \ return mp11::mp_with_index>( inner_active_, [&](auto I) { \ - return get( inner_.handlers_ ).fn; \ + return get( handlers_ ).fn; \ }); bool on_object_begin( error_code& ec ) diff --git a/include/boost/json/impl/conversion.hpp b/include/boost/json/impl/conversion.hpp index 8b008fbee..d455b0c2e 100644 --- a/include/boost/json/impl/conversion.hpp +++ b/include/boost/json/impl/conversion.hpp @@ -219,10 +219,31 @@ using described_non_public_members = describe::describe_members< template< class T > using described_bases = describe::describe_bases< T, describe::mod_any_access>; + +#if defined(BOOST_MSVC) && BOOST_MSVC < 1920 + +template< class T > +struct described_member_t_impl; + +template< class T, class C > +struct described_member_t_impl +{ + using type = T; +}; + +template< class T, class D > +using described_member_t = remove_cvref< + typename described_member_t_impl< + remove_cvref >::type>; + +#else + template< class T, class D > using described_member_t = remove_cvref().* D::pointer )>; +#endif + // user conversion (via tag_invoke) template< class Ctx, class T, class Dir > using user_conversion_category = mp11::mp_cond< diff --git a/test/parse_into.cpp b/test/parse_into.cpp index 498c78f87..d8c2c9521 100644 --- a/test/parse_into.cpp +++ b/test/parse_into.cpp @@ -174,7 +174,7 @@ class parse_into_test void testTuple() { -#if BOOST_CXX_VERSION >= 201402L && ( !defined(BOOST_MSVC) || BOOST_MSVC >= 1910 ) +#if BOOST_CXX_VERSION >= 201402L // && ( !defined(BOOST_MSVC) || BOOST_MSVC >= 1910 ) testParseInto>( {} ); testParseInto>( { 1, 3.14f } ); @@ -199,7 +199,7 @@ class parse_into_test void testStruct() { -#if BOOST_CXX_VERSION >= 201402L && ( !defined(BOOST_MSVC) || BOOST_MSVC >= 1910 ) +#if BOOST_CXX_VERSION >= 201402L // && ( !defined(BOOST_MSVC) || BOOST_MSVC >= 1910 ) testParseInto( {} ); testParseInto( { 1, 3.14f, "hello" } );