// // Copyright (c) 2020 Krystian Stasiowski (sdkrystian@gmail.com) // Copyright (c) 2022 Dmitry Arkhipov (grisumbras@yandex.ru) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // // Official repository: https://github.com/boostorg/json // #ifndef BOOST_JSON_IMPL_CONVERSION_HPP #define BOOST_JSON_IMPL_CONVERSION_HPP #include #include #include #include #include #include #include #include #include #include #ifndef BOOST_NO_CXX17_HDR_VARIANT # include #endif // BOOST_NO_CXX17_HDR_VARIANT BOOST_JSON_NS_BEGIN namespace detail { #ifdef __cpp_lib_nonmember_container_access using std::size; #endif template using tuple_element_t = typename std::tuple_element::type; template using iterator_type = decltype(std::begin(std::declval())); template using iterator_traits = std::iterator_traits< iterator_type >; template using value_type = typename iterator_traits::value_type; template using mapped_type = tuple_element_t< 1, value_type >; // had to make the metafunction always succeeding in order to make it work // with msvc 14.0 template using key_type_helper = tuple_element_t< 0, value_type >; template using key_type = mp11::mp_eval_or< void, key_type_helper, T>; template using are_begin_and_end_same = std::is_same< iterator_type, decltype(std::end(std::declval()))>; template using begin_iterator_category = typename std::iterator_traits< iterator_type>::iterator_category; template using has_positive_tuple_size = mp11::mp_bool< (std::tuple_size::value > 0) >; template using has_unique_keys = has_positive_tuple_size().emplace( std::declval>()))>; template struct is_value_type_pair_helper : std::false_type { }; template struct is_value_type_pair_helper> : std::true_type { }; template using is_value_type_pair = is_value_type_pair_helper>; template using has_size_member_helper = std::is_convertible().size()), std::size_t>; template using has_size_member = mp11::mp_valid_and_true; template using has_free_size_helper = std::is_convertible< decltype(size(std::declval())), std::size_t>; template using has_free_size = mp11::mp_valid_and_true; template using size_implementation = mp11::mp_cond< has_size_member, mp11::mp_int<3>, has_free_size, mp11::mp_int<2>, std::is_array, mp11::mp_int<1>, mp11::mp_true, mp11::mp_int<0>>; template std::size_t try_size(T&& cont, mp11::mp_int<3>) { return cont.size(); } template std::size_t try_size(T& cont, mp11::mp_int<2>) { return size(cont); } template std::size_t try_size(T(&)[N], mp11::mp_int<1>) { return N; } template std::size_t try_size(T&, mp11::mp_int<0>) { return 0; } using value_from_conversion = mp11::mp_true; using value_to_conversion = mp11::mp_false; struct user_conversion_tag { }; struct native_conversion_tag { }; struct value_conversion_tag : native_conversion_tag { }; struct object_conversion_tag : native_conversion_tag { }; struct array_conversion_tag : native_conversion_tag { }; struct string_conversion_tag : native_conversion_tag { }; struct bool_conversion_tag : native_conversion_tag { }; struct number_conversion_tag : native_conversion_tag { }; struct null_like_conversion_tag { }; struct string_like_conversion_tag { }; struct map_like_conversion_tag { }; struct sequence_conversion_tag { }; struct tuple_conversion_tag { }; struct described_class_conversion_tag { }; struct described_enum_conversion_tag { }; struct no_conversion_tag { }; template using has_user_conversion_from_impl = decltype(tag_invoke( value_from_tag(), std::declval(), std::declval())); template using has_user_conversion_to_impl = decltype(tag_invoke(value_to_tag(), std::declval())); template using has_nonthrowing_user_conversion_to_impl = decltype(tag_invoke( try_value_to_tag(), std::declval() )); template using has_user_conversion = mp11::mp_if< std::is_same, mp11::mp_valid, mp11::mp_or< mp11::mp_valid, mp11::mp_valid>>; template< class T > using described_non_public_members = describe::describe_members< T, describe::mod_private | describe::mod_protected>; template< class T > using described_bases = describe::describe_bases< T, describe::mod_any_access>; template using conversion_implementation = mp11::mp_cond< // user conversion (via tag_invoke) has_user_conversion, user_conversion_tag, // native conversions (constructors and member functions of value) std::is_same, value_conversion_tag, std::is_same, array_conversion_tag, std::is_same, object_conversion_tag, std::is_same, string_conversion_tag, std::is_same, bool_conversion_tag, std::is_arithmetic, number_conversion_tag, // generic conversions is_null_like, null_like_conversion_tag, is_string_like, string_like_conversion_tag, is_map_like, map_like_conversion_tag, is_sequence_like, sequence_conversion_tag, is_tuple_like, tuple_conversion_tag, is_described_class, described_class_conversion_tag, is_described_enum, described_enum_conversion_tag, // failed to find a suitable implementation mp11::mp_true, no_conversion_tag>; template using can_convert = mp11::mp_not< std::is_same< detail::conversion_implementation, detail::no_conversion_tag>>; template using value_from_implementation = conversion_implementation; template using value_to_implementation = conversion_implementation; template using conversion_round_trips_helper = mp11::mp_or< std::is_same, std::is_same, std::is_same>; template using conversion_round_trips = conversion_round_trips_helper< conversion_implementation, conversion_implementation>>; template< class T1, class T2 > struct copy_cref_helper { using type = remove_cvref; }; template< class T1, class T2 > using copy_cref = typename copy_cref_helper< T1, T2 >::type; template< class T1, class T2 > struct copy_cref_helper { using type = remove_cvref const; }; template< class T1, class T2 > struct copy_cref_helper { using type = copy_cref&; }; template< class T1, class T2 > struct copy_cref_helper { using type = copy_cref&&; }; template< class Rng, class Traits > using forwarded_value_helper = mp11::mp_if< std::is_convertible< typename Traits::reference, copy_cref >, copy_cref, typename Traits::value_type >; template< class Rng > using forwarded_value = forwarded_value_helper< Rng, iterator_traits< Rng > >; } // namespace detail template struct result_for { using type = result< detail::remove_cvref >; }; template struct is_string_like : std::is_convertible { }; template struct is_sequence_like : mp11::mp_all< mp11::mp_valid_and_true, mp11::mp_valid> { }; template struct is_map_like : mp11::mp_all< is_sequence_like, mp11::mp_valid_and_true, is_string_like>, mp11::mp_valid_and_true> { }; template struct is_tuple_like : mp11::mp_valid_and_true { }; template<> struct is_null_like : std::true_type { }; #ifndef BOOST_NO_CXX17_HDR_VARIANT template<> struct is_null_like : std::true_type { }; #endif // BOOST_NO_CXX17_HDR_VARIANT template struct is_described_class : mp11::mp_and< describe::has_describe_members, mp11::mp_not< std::is_union >, mp11::mp_empty< mp11::mp_eval_or< mp11::mp_list<>, detail::described_non_public_members, T>>, mp11::mp_empty< mp11::mp_eval_or, detail::described_bases, T>>> { }; template struct is_described_enum : describe::has_describe_enumerators { }; BOOST_JSON_NS_END #endif // BOOST_JSON_IMPL_CONVERSION_HPP