Skip to content

Commit 31154de

Browse files
committed
value_from supports conversion through helper types
1 parent 57d42f0 commit 31154de

File tree

10 files changed

+284
-52
lines changed

10 files changed

+284
-52
lines changed

include/boost/json/conversion.hpp

+7-1
Original file line numberDiff line numberDiff line change
@@ -234,7 +234,7 @@ struct is_sequence_like;
234234
235235
@see @ref value_from, @ref value_to
236236
*/
237-
template<class T>
237+
template<class T, class Context>
238238
struct is_map_like;
239239

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

440+
template< class T, class Context = void >
441+
struct represent_as;
442+
443+
template< class T, class Context = void >
444+
using represent_as_t = typename represent_as<T, Context>::type;
445+
440446
} // namespace json
441447
} // namespace boost
442448

include/boost/json/detail/parse_into.hpp

+2-1
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,8 @@ class converting_handler;
7979

8080
// get_handler
8181
template< class V, class P >
82-
using get_handler = converting_handler< generic_conversion_category<V>, V, P >;
82+
using get_handler = converting_handler<
83+
generic_conversion_category<V, no_context>, V, P>;
8384

8485
template<error E> class handler_error_base
8586
{

include/boost/json/detail/value_from.hpp

+22-9
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,12 @@
2222

2323
namespace boost {
2424
namespace json {
25-
2625
namespace detail {
2726

27+
template< class Ctx, class T >
28+
using value_from_attrs = conversion_attrs<
29+
Ctx, remove_cvref<T>, value_from_conversion>;
30+
2831
template< class Ctx, class T >
2932
struct append_tuple_element {
3033
array& arr;
@@ -41,6 +44,21 @@ struct append_tuple_element {
4144
}
4245
};
4346

47+
template< class T, class Ctx >
48+
using to_representation_result = mp11::mp_if<
49+
std::is_same<
50+
remove_cvref<T>, typename value_from_attrs<Ctx, T>::representation >,
51+
T&&,
52+
typename value_from_attrs<Ctx, T>::representation>;
53+
54+
template< class Ctx, class T >
55+
to_representation_result< T, Ctx >
56+
to_representation( T&& t )
57+
{
58+
using R = to_representation_result< T, Ctx >;
59+
return static_cast<R>( static_cast<T&&>(t) );
60+
}
61+
4462
//----------------------------------------------------------
4563
// User-provided conversion
4664

@@ -107,9 +125,11 @@ value_from_impl( map_like_conversion_tag, value& jv, T&& from, Ctx const& ctx )
107125
object& obj = jv.emplace_object();
108126
obj.reserve(detail::try_size(from, size_implementation<T>()));
109127
for (auto&& elem : from)
128+
{
110129
obj.emplace(
111-
get<0>(elem),
130+
to_representation<Ctx>( get<0>(elem) ),
112131
value_from( get<1>(elem), ctx, obj.storage() ));
132+
}
113133
}
114134

115135
// ranges
@@ -257,13 +277,6 @@ value_from_impl( path_conversion_tag, value& jv, T&& from, Ctx const& )
257277
jv.emplace_string().assign(sv);
258278
}
259279

260-
//----------------------------------------------------------
261-
// Contextual conversions
262-
263-
template< class Ctx, class T >
264-
using value_from_category = conversion_category<
265-
Ctx, T, value_from_conversion >;
266-
267280
} // detail
268281

269282
#ifndef BOOST_NO_CXX17_HDR_OPTIONAL

include/boost/json/detail/value_to.hpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -818,8 +818,8 @@ value_to_impl( Impl impl, value_to_tag<T>, value const& jv, Ctx const& ctx )
818818
}
819819

820820
template< class Ctx, class T >
821-
using value_to_category = conversion_category<
822-
Ctx, T, value_to_conversion >;
821+
using value_to_attrs = conversion_attrs<
822+
Ctx, remove_cvref<T>, value_to_conversion>;
823823

824824
} // detail
825825

include/boost/json/fwd.hpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ struct is_string_like;
4545
template<class T>
4646
struct is_sequence_like;
4747

48-
template<class T>
48+
template<class T, class Context = void>
4949
struct is_map_like;
5050

5151
template<class T>

include/boost/json/impl/conversion.hpp

+81-25
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@ namespace boost {
3232
namespace json {
3333
namespace detail {
3434

35+
struct no_context
36+
{};
37+
3538
#ifdef __cpp_lib_nonmember_container_access
3639
using std::size;
3740
#endif
@@ -317,14 +320,14 @@ using native_conversion_category = mp11::mp_cond<
317320
std::is_same<T, string>, string_conversion_tag>;
318321

319322
// generic conversions
320-
template< class T >
323+
template< class T, class Ctx >
321324
using generic_conversion_category = mp11::mp_cond<
322325
std::is_same<T, bool>, bool_conversion_tag,
323326
std::is_integral<T>, integral_conversion_tag,
324327
std::is_floating_point<T>, floating_point_conversion_tag,
325328
is_null_like<T>, null_like_conversion_tag,
326329
is_string_like<T>, string_like_conversion_tag,
327-
is_map_like<T>, map_like_conversion_tag,
330+
is_map_like<T, Ctx>, map_like_conversion_tag,
328331
is_sequence_like<T>, sequence_conversion_tag,
329332
is_tuple_like<T>, tuple_conversion_tag,
330333
is_described_class<T>, described_class_conversion_tag,
@@ -338,38 +341,92 @@ using generic_conversion_category = mp11::mp_cond<
338341
template< class T >
339342
using nested_type = typename T::type;
340343
template< class T1, class T2 >
341-
using conversion_category_impl_helper = mp11::mp_eval_if_not<
344+
using conversion_category_helper = mp11::mp_eval_if_not<
342345
std::is_same<detail::no_conversion_tag, T1>,
343346
T1,
344347
mp11::mp_eval_or_q, T1, mp11::mp_quote<nested_type>, T2>;
348+
349+
template< class Ctx >
350+
using fix_context = mp11::mp_if< std::is_same<Ctx, no_context>, void, Ctx>;
351+
352+
template<class T, class Ctx>
353+
using representation_or_void = mp11::mp_eval_or<void, represent_as_t, T, Ctx>;
354+
355+
template< class U >
356+
using is_not_void = mp11::mp_bool< !std::is_same<void, U>::value >;
357+
358+
template< class T, class Ctxs >
359+
struct representation_helper
360+
{
361+
using size = mp11::mp_size<Ctxs>;
362+
363+
template< class I >
364+
using exists = mp11::mp_less<I, size>;
365+
366+
template< class Ctx >
367+
using step = representation_or_void<T, Ctx>;
368+
using reps = mp11::mp_transform<step, Ctxs>;
369+
using r_index = mp11::mp_find_if< reps, is_not_void >;
370+
371+
using type = mp11::mp_eval_if<
372+
mp11::mp_not< exists<r_index> >,
373+
T,
374+
mp11::mp_at, reps, r_index>;
375+
};
376+
377+
template< class T, class Ctx >
378+
struct conversion_representation_impl
379+
: representation_helper< T, mp11::mp_list<Ctx, void> >
380+
{};
381+
382+
template< class T >
383+
struct conversion_representation_impl<T, no_context>
384+
: representation_helper< T, mp11::mp_list<void> >
385+
{};
386+
387+
template< class T, class... Ctxs >
388+
struct conversion_representation_impl< T, std::tuple<Ctxs...> >
389+
: representation_helper< T, mp11::mp_list<remove_cvref<Ctxs>..., void> >
390+
{};
391+
392+
template< class T, class Ctx >
393+
using conversion_representation
394+
= typename conversion_representation_impl<T, Ctx>::type;
395+
345396
template< class Ctx, class T, class Dir >
346-
struct conversion_category_impl
397+
struct conversion_attrs
347398
{
348-
using type = mp11::mp_fold<
399+
using representation = conversion_representation<T, Ctx>;
400+
401+
using category = mp11::mp_fold<
349402
mp11::mp_list<
350-
mp11::mp_defer<user_conversion_category, Ctx, T, Dir>,
351-
mp11::mp_defer<native_conversion_category, T>,
352-
mp11::mp_defer<generic_conversion_category, T>>,
403+
mp11::mp_defer<user_conversion_category, Ctx, representation, Dir>,
404+
mp11::mp_defer<native_conversion_category, representation>,
405+
mp11::mp_defer<generic_conversion_category, representation, Ctx>>,
353406
no_conversion_tag,
354-
conversion_category_impl_helper>;
407+
conversion_category_helper>;
355408
};
356-
template< class Ctx, class T, class Dir >
357-
using conversion_category =
358-
typename conversion_category_impl< Ctx, T, Dir >::type;
359409

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

414+
template< class Ctx, class T, class Dir >
415+
using conversion_category = typename conversion_attrs<Ctx, T, Dir>::category;
416+
364417
template< class T, class Dir, class... Ctxs >
365-
struct conversion_category_impl< std::tuple<Ctxs...>, T, Dir >
418+
struct conversion_attrs< std::tuple<Ctxs...>, T, Dir >
366419
{
420+
using size = mp11::mp_size_t< sizeof...(Ctxs) >;
367421
using ctxs = mp11::mp_list< remove_cvref<Ctxs>... >;
368-
using cats = mp11::mp_list<
369-
conversion_category<remove_cvref<Ctxs>, T, Dir>... >;
370422

371423
template< class I >
372-
using exists = mp11::mp_less< I, mp11::mp_size<cats> >;
424+
using exists = mp11::mp_less<I, size>;
425+
426+
using representation = conversion_representation< T, std::tuple<Ctxs...> >;
427+
428+
using cats = mp11::mp_list<
429+
conversion_category<remove_cvref<Ctxs>, representation, Dir>... >;
373430

374431
using context2 = mp11::mp_find< cats, full_context_conversion_tag >;
375432
using context1 = mp11::mp_find< cats, context_conversion_tag >;
@@ -379,14 +436,11 @@ struct conversion_category_impl< std::tuple<Ctxs...>, T, Dir >
379436
exists<context1>, context1,
380437
exists<context0>, context0,
381438
mp11::mp_true, mp11::mp_find_if< cats, any_conversion_tag > >;
382-
using type = mp11::mp_eval_or<
439+
using category = mp11::mp_eval_or<
383440
no_conversion_tag,
384441
mp11::mp_at, cats, index >;
385442
};
386443

387-
struct no_context
388-
{};
389-
390444
template <class T, class Dir>
391445
using can_convert = mp11::mp_not<
392446
std::is_same<
@@ -456,10 +510,10 @@ template< class T, class Dir, class... Ctxs >
456510
struct supported_context< std::tuple<Ctxs...>, T, Dir >
457511
{
458512
using Ctx = std::tuple<Ctxs...>;
459-
using impl = conversion_category_impl<Ctx, T, Dir>;
460-
using index = typename impl::index;
513+
using Attrs = conversion_attrs<Ctx, T, Dir>;
514+
using index = typename Attrs::index;
461515
using next_supported = supported_context<
462-
mp11::mp_at< typename impl::ctxs, index >, T, Dir >;
516+
mp11::mp_at< typename Attrs::ctxs, index >, T, Dir >;
463517
using type = typename next_supported::type;
464518

465519
static
@@ -508,12 +562,14 @@ struct is_sequence_like
508562
mp11::mp_valid<detail::begin_iterator_category, T>>
509563
{ };
510564

511-
template<class T>
565+
template<class T, class Ctx>
512566
struct is_map_like
513567
: mp11::mp_all<
514568
is_sequence_like<T>,
515569
mp11::mp_valid_and_true<detail::is_value_type_pair, T>,
516-
is_string_like<detail::key_type<T>>,
570+
is_string_like<
571+
detail::conversion_representation<
572+
detail::remove_cvref< detail::key_type<T> >, Ctx>>,
517573
mp11::mp_valid_and_true<detail::has_unique_keys, T>>
518574
{ };
519575

include/boost/json/impl/serializer.hpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -818,7 +818,7 @@ template<class T, bool StackEmpty>
818818
bool
819819
write_impl(writer& w, stream& ss)
820820
{
821-
using cat = detail::generic_conversion_category<T>;
821+
using cat = detail::generic_conversion_category<T, detail::no_context>;
822822
return write_impl<T, StackEmpty>( cat(), w, ss );
823823
}
824824

include/boost/json/value_from.hpp

+10-4
Original file line numberDiff line numberDiff line change
@@ -83,11 +83,17 @@ value_from(
8383
Context const& ctx,
8484
value& jv)
8585
{
86-
using bare_T = detail::remove_cvref<T>;
86+
using Attrs = detail::value_from_attrs<Context, T>;
8787
BOOST_STATIC_ASSERT(detail::conversion_round_trips<
88-
Context, bare_T, detail::value_from_conversion>::value);
89-
using cat = detail::value_from_category<Context, bare_T>;
90-
detail::value_from_impl( cat(), jv, std::forward<T>(t), ctx );
88+
Context,
89+
typename Attrs::representation,
90+
detail::value_from_conversion>::value);
91+
92+
detail::value_from_impl(
93+
typename Attrs::category(),
94+
jv,
95+
detail::to_representation<Context>( static_cast<T&&>(t) ),
96+
ctx );
9197
}
9298

9399
/** Convert an object of type `T` to @ref value.

include/boost/json/value_to.hpp

+17-8
Original file line numberDiff line numberDiff line change
@@ -89,11 +89,16 @@ T
8989
value_to( value const& jv, Context const& ctx )
9090
{
9191
BOOST_STATIC_ASSERT(! std::is_reference<T>::value);
92-
using bare_T = detail::remove_cvref<T>;
92+
93+
using Attrs = detail::value_to_attrs<Context, T>;
9394
BOOST_STATIC_ASSERT(detail::conversion_round_trips<
94-
Context, bare_T, detail::value_to_conversion>::value);
95-
using cat = detail::value_to_category<Context, bare_T>;
96-
return detail::value_to_impl( cat(), value_to_tag<bare_T>(), jv, ctx );
95+
Context,
96+
typename Attrs::representation,
97+
detail::value_to_conversion>::value);
98+
99+
using bare_T = detail::remove_cvref<T>;
100+
return detail::value_to_impl(
101+
typename Attrs::category(), value_to_tag<bare_T>(), jv, ctx);
97102
}
98103

99104
/** Convert a @ref value to an object of type `T`.
@@ -223,12 +228,16 @@ typename result_for<T, value>::type
223228
try_value_to( value const& jv, Context const& ctx )
224229
{
225230
BOOST_STATIC_ASSERT(! std::is_reference<T>::value);
226-
using bare_T = detail::remove_cvref<T>;
231+
232+
using Attrs = detail::value_to_attrs<Context, T>;
227233
BOOST_STATIC_ASSERT(detail::conversion_round_trips<
228-
Context, bare_T, detail::value_to_conversion>::value);
229-
using cat = detail::value_to_category<Context, bare_T>;
234+
Context,
235+
typename Attrs::representation,
236+
detail::value_to_conversion>::value);
237+
238+
using bare_T = detail::remove_cvref<T>;
230239
return detail::value_to_impl(
231-
cat(), try_value_to_tag<bare_T>(), jv, ctx );
240+
typename Attrs::category(), try_value_to_tag<bare_T>(), jv, ctx );
232241
}
233242

234243
/** Convert a @ref value to a `boost::system::result<T>`.

0 commit comments

Comments
 (0)