Skip to content

Commit 00f52d7

Browse files
committed
value_from supports conversion through helper types
1 parent baff1cb commit 00f52d7

File tree

10 files changed

+207
-50
lines changed

10 files changed

+207
-50
lines changed

doc/Jamfile

+2-2
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@ import boostbook ;
1414
import ../../../tools/docca/docca.jam ;
1515
import path ;
1616

17-
local include-prefix = [ path.root $(__file__:D) [ path.pwd ] ] ;
18-
include-prefix = [ path.native $(include-prefix:D)/include ] ;
17+
local include-prefix = [ path.join $(__file__:D) .. ] ;
18+
include-prefix = [ path.native $(include-prefix)/include ] ;
1919
docca.pyreference reference.qbk
2020
: [ glob-tree-ex ../include/boost/json : *.hpp *.ipp : detail impl ]
2121
externals.hpp

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>::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
@@ -928,8 +928,8 @@ value_to_impl( Impl impl, value_to_tag<T>, value const& jv, Ctx const& ctx )
928928
}
929929

930930
template< class Ctx, class T >
931-
using value_to_category = conversion_category<
932-
Ctx, T, value_to_conversion >;
931+
using value_to_attrs = conversion_attrs<
932+
Ctx, remove_cvref<T>, value_to_conversion>;
933933

934934
} // detail
935935

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

+48-22
Original file line numberDiff line numberDiff line change
@@ -317,14 +317,14 @@ using native_conversion_category = mp11::mp_cond<
317317
std::is_same<T, string>, string_conversion_tag>;
318318

319319
// generic conversions
320-
template< class T >
320+
template< class T, class Ctx >
321321
using generic_conversion_category = mp11::mp_cond<
322322
std::is_same<T, bool>, bool_conversion_tag,
323323
std::is_integral<T>, integral_conversion_tag,
324324
std::is_floating_point<T>, floating_point_conversion_tag,
325325
is_null_like<T>, null_like_conversion_tag,
326326
is_string_like<T>, string_like_conversion_tag,
327-
is_map_like<T>, map_like_conversion_tag,
327+
is_map_like<T, Ctx>, map_like_conversion_tag,
328328
is_sequence_like<T>, sequence_conversion_tag,
329329
is_tuple_like<T>, tuple_conversion_tag,
330330
is_described_class<T>, described_class_conversion_tag,
@@ -338,38 +338,57 @@ using generic_conversion_category = mp11::mp_cond<
338338
template< class T >
339339
using nested_type = typename T::type;
340340
template< class T1, class T2 >
341-
using conversion_category_impl_helper = mp11::mp_eval_if_not<
341+
using conversion_category_helper = mp11::mp_eval_if_not<
342342
std::is_same<detail::no_conversion_tag, T1>,
343343
T1,
344344
mp11::mp_eval_or_q, T1, mp11::mp_quote<nested_type>, T2>;
345+
346+
template< class T, class Ctx, class Def = T >
347+
using representation_helper = mp11::mp_eval_or<Def, represent_as_t, T, Ctx>;
348+
345349
template< class Ctx, class T, class Dir >
346-
struct conversion_category_impl
350+
struct conversion_attrs
347351
{
348-
using type = mp11::mp_fold<
352+
using representation = representation_helper<T, Ctx>;
353+
354+
using category = mp11::mp_fold<
349355
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>>,
356+
mp11::mp_defer<user_conversion_category, Ctx, representation, Dir>,
357+
mp11::mp_defer<native_conversion_category, representation>,
358+
mp11::mp_defer<generic_conversion_category, representation, Ctx>>,
353359
no_conversion_tag,
354-
conversion_category_impl_helper>;
360+
conversion_category_helper>;
355361
};
356-
template< class Ctx, class T, class Dir >
357-
using conversion_category =
358-
typename conversion_category_impl< Ctx, T, Dir >::type;
359362

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

367+
template< class Ctx, class T, class Dir >
368+
using conversion_category = typename conversion_attrs<Ctx, T, Dir>::category;
369+
370+
template< class U >
371+
using is_not_void = mp11::mp_bool< !std::is_same<void, U>::value >;
372+
364373
template< class T, class Dir, class... Ctxs >
365-
struct conversion_category_impl< std::tuple<Ctxs...>, T, Dir >
374+
struct conversion_attrs< std::tuple<Ctxs...>, T, Dir >
366375
{
376+
using size = mp11::mp_size_t< sizeof...(Ctxs) >;
367377
using ctxs = mp11::mp_list< remove_cvref<Ctxs>... >;
368-
using cats = mp11::mp_list<
369-
conversion_category<remove_cvref<Ctxs>, T, Dir>... >;
370378

371379
template< class I >
372-
using exists = mp11::mp_less< I, mp11::mp_size<cats> >;
380+
using exists = mp11::mp_less<I, size>;
381+
382+
using reps = mp11::mp_list<
383+
representation_helper< T, remove_cvref<Ctxs>, void >... >;
384+
using r_index = mp11::mp_find_if< reps, is_not_void >;
385+
using representation = mp11::mp_eval_if<
386+
mp11::mp_not<exists<r_index>>,
387+
T,
388+
mp11::mp_at, reps, r_index>;
389+
390+
using cats = mp11::mp_list<
391+
conversion_category<remove_cvref<Ctxs>, representation, Dir>... >;
373392

374393
using context2 = mp11::mp_find< cats, full_context_conversion_tag >;
375394
using context1 = mp11::mp_find< cats, context_conversion_tag >;
@@ -379,7 +398,7 @@ struct conversion_category_impl< std::tuple<Ctxs...>, T, Dir >
379398
exists<context1>, context1,
380399
exists<context0>, context0,
381400
mp11::mp_true, mp11::mp_find_if< cats, any_conversion_tag > >;
382-
using type = mp11::mp_eval_or<
401+
using category = mp11::mp_eval_or<
383402
no_conversion_tag,
384403
mp11::mp_at, cats, index >;
385404
};
@@ -459,10 +478,10 @@ template< class T, class Dir, class... Ctxs >
459478
struct supported_context< std::tuple<Ctxs...>, T, Dir >
460479
{
461480
using Ctx = std::tuple<Ctxs...>;
462-
using impl = conversion_category_impl<Ctx, T, Dir>;
463-
using index = typename impl::index;
481+
using Attrs = conversion_attrs<Ctx, T, Dir>;
482+
using index = typename Attrs::index;
464483
using next_supported = supported_context<
465-
mp11::mp_at< typename impl::ctxs, index >, T, Dir >;
484+
mp11::mp_at< typename Attrs::ctxs, index >, T, Dir >;
466485
using type = typename next_supported::type;
467486

468487
static
@@ -511,12 +530,14 @@ struct is_sequence_like
511530
mp11::mp_valid<detail::begin_iterator_category, T>>
512531
{ };
513532

514-
template<class T>
533+
template<class T, class Ctx>
515534
struct is_map_like
516535
: mp11::mp_all<
517536
is_sequence_like<T>,
518537
mp11::mp_valid_and_true<detail::is_value_type_pair, T>,
519-
is_string_like<detail::key_type<T>>,
538+
is_string_like<
539+
detail::representation_helper<
540+
detail::remove_cvref< detail::key_type<T> >, Ctx>>,
520541
mp11::mp_valid_and_true<detail::has_unique_keys, T>>
521542
{ };
522543

@@ -566,6 +587,11 @@ struct is_optional_like
566587
mp11::mp_valid<detail::can_reset, T>>
567588
{ };
568589

590+
template< class T >
591+
struct represent_as<T, detail::no_context>
592+
: represent_as<T, void>
593+
{ };
594+
569595
} // namespace json
570596
} // namespace boost
571597

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 @ref result of `T`.

0 commit comments

Comments
 (0)