Skip to content

Commit

Permalink
refactor parse_into tuple handler
Browse files Browse the repository at this point in the history
  • Loading branch information
grisumbras committed Aug 14, 2023
1 parent 311c9f1 commit 9e02410
Show file tree
Hide file tree
Showing 2 changed files with 109 additions and 69 deletions.
174 changes: 107 additions & 67 deletions include/boost/json/detail/parse_into.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -595,74 +595,94 @@ class converting_handler<map_like_conversion_tag, V, P>
};

// 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<std::size_t I, class T> struct handler_tuple_element
template<std::size_t I, class T>
struct handler_tuple_element
{
template< class... Args >
handler_tuple_element( Args&& ... args )
: t_( static_cast<Args&&>(args)... )
{}

T t_;
};

template<class S, class... T> struct handler_tuple_impl;
template<std::size_t I, class T>
T&
get( handler_tuple_element<I, T>& e )
{
return e.t_;
}

template<
class P,
class LV,
class S = mp11::make_index_sequence<mp11::mp_size<LV>::value> >
struct handler_tuple;

template<std::size_t... I, class... T>
struct handler_tuple_impl<mp11::index_sequence<I...>, T...>
: handler_tuple_element<I, T>...
template< class P, template<class...> class L, class... V, std::size_t... I >
struct handler_tuple< P, L<V...>, mp11::index_sequence<I...> >
: handler_tuple_element< I, get_handler<V, P> >
...
{
template<class... A>
handler_tuple_impl( A... a )
: handler_tuple_element<I, T>{{ 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<V, P> >(
access( pv, mp11::mp_int<I>() ), pp )
...
{ }
};

template<class P, class... V>
struct handler_tuple
: public handler_tuple_impl<
mp11::index_sequence_for<V...>, get_handler<V, P>...>
{
using base_type = handler_tuple_impl<
mp11::index_sequence_for<V...>, get_handler<V, P>...>;
#if defined(BOOST_MSVC) && BOOST_MSVC < 1910

template<class... A>
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<I::value, 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<T> > >;
};
template< class T >
using tuple_element_list = typename tuple_element_list_impl<T>::type;

template<std::size_t I, class T>
T&
get( handler_tuple_element<I, T>& 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<I::value, 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<T> > >;

template< class P, template<class...> class L, class... V >
struct tuple_inner_handlers<P, L<V...>>
{
handler_tuple<P, V...> handlers_;
#endif

template<std::size_t... I>
tuple_inner_handlers(
L<V...>* pv, P* pp, mp11::index_sequence<I...> )
: handlers_( std::make_pair( &get<I>(*pv), pp )... )
{}
struct tuple_accessor
{
template< class T, class I >
auto operator()( T* t, I ) const -> tuple_element_t<I::value, T>*
{
using std::get;
return &get<I::value>(*t);
}
};

#endif
// #endif

template< class T, class P >
class converting_handler<tuple_conversion_tag, T, P>
{
#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" );
Expand All @@ -673,20 +693,15 @@ class converting_handler<tuple_conversion_tag, T, P>
T* value_;
P* parent_;

tuple_inner_handlers<converting_handler, T> inner_;
handler_tuple< converting_handler, tuple_element_list<T> > handlers_;
int inner_active_ = -1;

public:
converting_handler( converting_handler const& ) = delete;
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<T>::value >())
: value_(v) , parent_(p) , handlers_(tuple_accessor(), v, this)
{}

void signal_value()
Expand All @@ -713,7 +728,7 @@ class converting_handler<tuple_conversion_tag, T, P>
return false; \
} \
return mp11::mp_with_index<N>( inner_active_, [&](auto I){ \
return get<I>( inner_.handlers_ ).fn; \
return get<I>( handlers_ ).fn; \
});

bool on_object_begin( error_code& ec )
Expand Down Expand Up @@ -743,7 +758,7 @@ class converting_handler<tuple_conversion_tag, T, P>
}

return mp11::mp_with_index<N>( inner_active_, [&](auto I){
return get<I>( inner_.handlers_ ).on_array_begin(ec);
return get<I>( handlers_ ).on_array_begin(ec);
});
}

Expand All @@ -766,7 +781,7 @@ class converting_handler<tuple_conversion_tag, T, P>
}

return mp11::mp_with_index<N>( inner_active_, [&](auto I){
return get<I>( inner_.handlers_ ).on_array_end( n, ec );
return get<I>( handlers_ ).on_array_end( n, ec );
});
}

Expand Down Expand Up @@ -826,23 +841,48 @@ class converting_handler<tuple_conversion_tag, T, P>
};

// described struct handler
template<class P, class T, class L>
struct struct_inner_handlers;
#if defined(BOOST_MSVC) && BOOST_MSVC < 1910

template<class P, class T, template<class...> class L, class... D>
struct struct_inner_handlers<P, T, L<D...>>
template< class T >
struct struct_element_list_impl
{
handler_tuple<P, described_member_t<T, D>...> handlers_;
template< class D >
using helper = described_member_t<T, D>;

struct_inner_handlers( T* pv, P* pp )
: handlers_( std::make_pair( &(pv->*D::pointer), pp )... )
{}
using type = mp11::mp_transform<
helper,
describe::describe_members<T, describe::mod_public> >;
};
template< class T >
using struct_element_list = typename struct_element_list_impl<T>::type;

#else

template< class T >
using struct_element_list = mp11::mp_transform_q<
mp11::mp_bind_front< described_member_t, T >,
describe::describe_members<T, describe::mod_public> >;

#endif

struct struct_accessor
{
template< class T, class I >
auto operator()( T* t, I ) const
-> described_member_t<T,
mp11::mp_at<
describe::describe_members<T, describe::mod_public>, I> >*
{
using Ds = describe::describe_members<T, describe::mod_public>;
using D = mp11::mp_at<Ds, I>;
return &(t->*D::pointer);
}
};

template<class V, class P>
class converting_handler<described_class_conversion_tag, V, P>
{
#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" );
Expand All @@ -857,15 +897,15 @@ class converting_handler<described_class_conversion_tag, V, P>

using Dm = describe::describe_members<V, describe::mod_public>;

struct_inner_handlers<converting_handler, V, Dm> inner_;
handler_tuple< converting_handler, struct_element_list<V> > handlers_;
int inner_active_ = -1;

public:
converting_handler( converting_handler const& ) = delete;
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()
Expand All @@ -889,7 +929,7 @@ class converting_handler<described_class_conversion_tag, V, P>
return false; \
} \
return mp11::mp_with_index<mp11::mp_size<Dm>>( inner_active_, [&](auto I) { \
return get<I>( inner_.handlers_ ).fn; \
return get<I>( handlers_ ).fn; \
});

bool on_object_begin( error_code& ec )
Expand Down
4 changes: 2 additions & 2 deletions test/parse_into.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<std::pair<int, float>>( {} );
testParseInto<std::pair<int, float>>( { 1, 3.14f } );

Expand All @@ -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<X>( {} );
testParseInto<X>( { 1, 3.14f, "hello" } );

Expand Down

0 comments on commit 9e02410

Please sign in to comment.