Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Conversion to/from proxy types #1025

Draft
wants to merge 1 commit into
base: develop
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions doc/Jamfile
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ import boostbook ;
import ../../../tools/docca/docca.jam ;
import path ;

local include-prefix = [ path.root $(__file__:D) [ path.pwd ] ] ;
include-prefix = [ path.native $(include-prefix:D)/include ] ;
local include-prefix = [ path.join $(__file__:D) .. ] ;
include-prefix = [ path.native $(include-prefix)/include ] ;
docca.pyreference reference.qbk
: [ glob-tree-ex ../include/boost/json : *.hpp *.ipp : detail impl ]
externals.hpp
Expand Down
8 changes: 7 additions & 1 deletion include/boost/json/conversion.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,7 @@ struct is_sequence_like;

@see @ref value_from, @ref value_to
*/
template<class T>
template<class T, class Context>
struct is_map_like;

/** Determine if `T` can be treated like a tuple during conversions.
Expand Down Expand Up @@ -437,6 +437,12 @@ struct is_variant_like;
template<class T>
struct is_optional_like;

template< class T, class Context = void >
struct represent_as;

template< class T, class Context = void >
using represent_as_t = typename represent_as<T>::type;

} // namespace json
} // namespace boost

Expand Down
3 changes: 2 additions & 1 deletion include/boost/json/detail/parse_into.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,8 @@ class converting_handler;

// get_handler
template< class V, class P >
using get_handler = converting_handler< generic_conversion_category<V>, V, P >;
using get_handler = converting_handler<
generic_conversion_category<V, no_context>, V, P>;

template<error E> class handler_error_base
{
Expand Down
31 changes: 22 additions & 9 deletions include/boost/json/detail/value_from.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,12 @@

namespace boost {
namespace json {

namespace detail {

template< class Ctx, class T >
using value_from_attrs = conversion_attrs<
Ctx, remove_cvref<T>, value_from_conversion>;

template< class Ctx, class T >
struct append_tuple_element {
array& arr;
Expand All @@ -41,6 +44,21 @@ struct append_tuple_element {
}
};

template< class T, class Ctx >
using to_representation_result = mp11::mp_if<
std::is_same<
remove_cvref<T>, typename value_from_attrs<Ctx, T>::representation >,
T&&,
typename value_from_attrs<Ctx, T>::representation>;

template< class Ctx, class T >
to_representation_result< T, Ctx >
to_representation( T&& t )
{
using R = to_representation_result< T, Ctx >;
return static_cast<R>( static_cast<T&&>(t) );
}

//----------------------------------------------------------
// User-provided conversion

Expand Down Expand Up @@ -107,9 +125,11 @@ value_from_impl( map_like_conversion_tag, value& jv, T&& from, Ctx const& ctx )
object& obj = jv.emplace_object();
obj.reserve(detail::try_size(from, size_implementation<T>()));
for (auto&& elem : from)
{
obj.emplace(
get<0>(elem),
to_representation<Ctx>( get<0>(elem) ),
value_from( get<1>(elem), ctx, obj.storage() ));
}
}

// ranges
Expand Down Expand Up @@ -257,13 +277,6 @@ value_from_impl( path_conversion_tag, value& jv, T&& from, Ctx const& )
jv.emplace_string().assign(sv);
}

//----------------------------------------------------------
// Contextual conversions

template< class Ctx, class T >
using value_from_category = conversion_category<
Ctx, T, value_from_conversion >;

} // detail

#ifndef BOOST_NO_CXX17_HDR_OPTIONAL
Expand Down
4 changes: 2 additions & 2 deletions include/boost/json/detail/value_to.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -928,8 +928,8 @@ value_to_impl( Impl impl, value_to_tag<T>, value const& jv, Ctx const& ctx )
}

template< class Ctx, class T >
using value_to_category = conversion_category<
Ctx, T, value_to_conversion >;
using value_to_attrs = conversion_attrs<
Ctx, remove_cvref<T>, value_to_conversion>;

} // detail

Expand Down
2 changes: 1 addition & 1 deletion include/boost/json/fwd.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ struct is_string_like;
template<class T>
struct is_sequence_like;

template<class T>
template<class T, class Context = void>
struct is_map_like;

template<class T>
Expand Down
70 changes: 48 additions & 22 deletions include/boost/json/impl/conversion.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -317,14 +317,14 @@ using native_conversion_category = mp11::mp_cond<
std::is_same<T, string>, string_conversion_tag>;

// generic conversions
template< class T >
template< class T, class Ctx >
using generic_conversion_category = mp11::mp_cond<
std::is_same<T, bool>, bool_conversion_tag,
std::is_integral<T>, integral_conversion_tag,
std::is_floating_point<T>, floating_point_conversion_tag,
is_null_like<T>, null_like_conversion_tag,
is_string_like<T>, string_like_conversion_tag,
is_map_like<T>, map_like_conversion_tag,
is_map_like<T, Ctx>, map_like_conversion_tag,
is_sequence_like<T>, sequence_conversion_tag,
is_tuple_like<T>, tuple_conversion_tag,
is_described_class<T>, described_class_conversion_tag,
Expand All @@ -338,38 +338,57 @@ using generic_conversion_category = mp11::mp_cond<
template< class T >
using nested_type = typename T::type;
template< class T1, class T2 >
using conversion_category_impl_helper = mp11::mp_eval_if_not<
using conversion_category_helper = mp11::mp_eval_if_not<
std::is_same<detail::no_conversion_tag, T1>,
T1,
mp11::mp_eval_or_q, T1, mp11::mp_quote<nested_type>, T2>;

template< class T, class Ctx, class Def = T >
using representation_helper = mp11::mp_eval_or<Def, represent_as_t, T, Ctx>;

template< class Ctx, class T, class Dir >
struct conversion_category_impl
struct conversion_attrs
{
using type = mp11::mp_fold<
using representation = representation_helper<T, Ctx>;

using category = mp11::mp_fold<
mp11::mp_list<
mp11::mp_defer<user_conversion_category, Ctx, T, Dir>,
mp11::mp_defer<native_conversion_category, T>,
mp11::mp_defer<generic_conversion_category, T>>,
mp11::mp_defer<user_conversion_category, Ctx, representation, Dir>,
mp11::mp_defer<native_conversion_category, representation>,
mp11::mp_defer<generic_conversion_category, representation, Ctx>>,
no_conversion_tag,
conversion_category_impl_helper>;
conversion_category_helper>;
};
template< class Ctx, class T, class Dir >
using conversion_category =
typename conversion_category_impl< Ctx, T, Dir >::type;

template< class T >
using any_conversion_tag = mp11::mp_not<
std::is_same< T, no_conversion_tag > >;

template< class Ctx, class T, class Dir >
using conversion_category = typename conversion_attrs<Ctx, T, Dir>::category;

template< class U >
using is_not_void = mp11::mp_bool< !std::is_same<void, U>::value >;

template< class T, class Dir, class... Ctxs >
struct conversion_category_impl< std::tuple<Ctxs...>, T, Dir >
struct conversion_attrs< std::tuple<Ctxs...>, T, Dir >
{
using size = mp11::mp_size_t< sizeof...(Ctxs) >;
using ctxs = mp11::mp_list< remove_cvref<Ctxs>... >;
using cats = mp11::mp_list<
conversion_category<remove_cvref<Ctxs>, T, Dir>... >;

template< class I >
using exists = mp11::mp_less< I, mp11::mp_size<cats> >;
using exists = mp11::mp_less<I, size>;

using reps = mp11::mp_list<
representation_helper< T, remove_cvref<Ctxs>, void >... >;
using r_index = mp11::mp_find_if< reps, is_not_void >;
using representation = mp11::mp_eval_if<
mp11::mp_not<exists<r_index>>,
T,
mp11::mp_at, reps, r_index>;

using cats = mp11::mp_list<
conversion_category<remove_cvref<Ctxs>, representation, Dir>... >;

using context2 = mp11::mp_find< cats, full_context_conversion_tag >;
using context1 = mp11::mp_find< cats, context_conversion_tag >;
Expand All @@ -379,7 +398,7 @@ struct conversion_category_impl< std::tuple<Ctxs...>, T, Dir >
exists<context1>, context1,
exists<context0>, context0,
mp11::mp_true, mp11::mp_find_if< cats, any_conversion_tag > >;
using type = mp11::mp_eval_or<
using category = mp11::mp_eval_or<
no_conversion_tag,
mp11::mp_at, cats, index >;
};
Expand Down Expand Up @@ -459,10 +478,10 @@ template< class T, class Dir, class... Ctxs >
struct supported_context< std::tuple<Ctxs...>, T, Dir >
{
using Ctx = std::tuple<Ctxs...>;
using impl = conversion_category_impl<Ctx, T, Dir>;
using index = typename impl::index;
using Attrs = conversion_attrs<Ctx, T, Dir>;
using index = typename Attrs::index;
using next_supported = supported_context<
mp11::mp_at< typename impl::ctxs, index >, T, Dir >;
mp11::mp_at< typename Attrs::ctxs, index >, T, Dir >;
using type = typename next_supported::type;

static
Expand Down Expand Up @@ -511,12 +530,14 @@ struct is_sequence_like
mp11::mp_valid<detail::begin_iterator_category, T>>
{ };

template<class T>
template<class T, class Ctx>
struct is_map_like
: mp11::mp_all<
is_sequence_like<T>,
mp11::mp_valid_and_true<detail::is_value_type_pair, T>,
is_string_like<detail::key_type<T>>,
is_string_like<
detail::representation_helper<
detail::remove_cvref< detail::key_type<T> >, Ctx>>,
mp11::mp_valid_and_true<detail::has_unique_keys, T>>
{ };

Expand Down Expand Up @@ -566,6 +587,11 @@ struct is_optional_like
mp11::mp_valid<detail::can_reset, T>>
{ };

template< class T >
struct represent_as<T, detail::no_context>
: represent_as<T, void>
{ };

} // namespace json
} // namespace boost

Expand Down
14 changes: 10 additions & 4 deletions include/boost/json/value_from.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -83,11 +83,17 @@ value_from(
Context const& ctx,
value& jv)
{
using bare_T = detail::remove_cvref<T>;
using Attrs = detail::value_from_attrs<Context, T>;
BOOST_STATIC_ASSERT(detail::conversion_round_trips<
Context, bare_T, detail::value_from_conversion>::value);
using cat = detail::value_from_category<Context, bare_T>;
detail::value_from_impl( cat(), jv, std::forward<T>(t), ctx );
Context,
typename Attrs::representation,
detail::value_from_conversion>::value);

detail::value_from_impl(
typename Attrs::category(),
jv,
detail::to_representation<Context>( static_cast<T&&>(t) ),
ctx );
}

/** Convert an object of type `T` to @ref value.
Expand Down
25 changes: 17 additions & 8 deletions include/boost/json/value_to.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -89,11 +89,16 @@ T
value_to( value const& jv, Context const& ctx )
{
BOOST_STATIC_ASSERT(! std::is_reference<T>::value);
using bare_T = detail::remove_cvref<T>;

using Attrs = detail::value_to_attrs<Context, T>;
BOOST_STATIC_ASSERT(detail::conversion_round_trips<
Context, bare_T, detail::value_to_conversion>::value);
using cat = detail::value_to_category<Context, bare_T>;
return detail::value_to_impl( cat(), value_to_tag<bare_T>(), jv, ctx );
Context,
typename Attrs::representation,
detail::value_to_conversion>::value);

using bare_T = detail::remove_cvref<T>;
return detail::value_to_impl(
typename Attrs::category(), value_to_tag<bare_T>(), jv, ctx);
}

/** Convert a @ref value to an object of type `T`.
Expand Down Expand Up @@ -223,12 +228,16 @@ typename result_for<T, value>::type
try_value_to( value const& jv, Context const& ctx )
{
BOOST_STATIC_ASSERT(! std::is_reference<T>::value);
using bare_T = detail::remove_cvref<T>;

using Attrs = detail::value_to_attrs<Context, T>;
BOOST_STATIC_ASSERT(detail::conversion_round_trips<
Context, bare_T, detail::value_to_conversion>::value);
using cat = detail::value_to_category<Context, bare_T>;
Context,
typename Attrs::representation,
detail::value_to_conversion>::value);

using bare_T = detail::remove_cvref<T>;
return detail::value_to_impl(
cat(), try_value_to_tag<bare_T>(), jv, ctx );
typename Attrs::category(), try_value_to_tag<bare_T>(), jv, ctx );
}

/** Convert a @ref value to a @ref result of `T`.
Expand Down
Loading
Loading