@@ -32,6 +32,9 @@ namespace boost {
3232namespace json {
3333namespace detail {
3434
35+ struct no_context
36+ {};
37+
3538#ifdef __cpp_lib_nonmember_container_access
3639using 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 >
321324using 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<
338341template < class T >
339342using nested_type = typename T::type;
340343template < 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+
345396template < 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
360410template < class T >
361411using 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+
364417template < 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-
390444template <class T , class Dir >
391445using can_convert = mp11::mp_not<
392446 std::is_same<
@@ -456,10 +510,10 @@ template< class T, class Dir, class... Ctxs >
456510struct 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 >
512566struct 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
0 commit comments