// // Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com) // Copyright (c) 2020 Krystian Stasiowski (sdkrystian@gmail.com) // Copyright (c) 2021 Dmitry Arkhipov (grisumbras@gmail.com) // // 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_DETAIL_VALUE_TO_HPP #define BOOST_JSON_DETAIL_VALUE_TO_HPP #include #include #include #include BOOST_JSON_NS_BEGIN template struct value_to_tag { }; template struct has_value_to; template::value && std::is_same::value>::type> T value_to(U const&); namespace detail { template>::value > 0)>::type* = nullptr> void try_reserve( T&, std::size_t size, priority_tag<2>) { constexpr std::size_t N = std::tuple_size>::value; if ( N != size ) { detail::throw_invalid_argument( "target array size does not match source array size", BOOST_JSON_SOURCE_POS); } } template().reserve(0))>* = nullptr> void try_reserve( T& cont, std::size_t size, priority_tag<1>) { cont.reserve(size); } template void try_reserve( T&, std::size_t, priority_tag<0>) { } template>::value > 0)>::type* = nullptr> typename remove_cvref::iterator inserter( T& target, priority_tag<1>) { return target.begin(); } template std::insert_iterator inserter( T& target, priority_tag<0>) { return std::inserter(target, end(target)); } //---------------------------------------------------------- // Use native conversion // identity conversion inline value tag_invoke( value_to_tag, value const& jv) { return jv; } // object inline object tag_invoke( value_to_tag, value const& jv) { return jv.as_object(); } // array inline array tag_invoke( value_to_tag, value const& jv) { return jv.as_array(); } // string inline string tag_invoke( value_to_tag, value const& jv) { return jv.as_string(); } // bool inline bool tag_invoke( value_to_tag, value const& jv) { return jv.as_bool(); } // integral and floating point template::value>::type* = nullptr> T tag_invoke( value_to_tag, value const& jv) { return jv.to_number(); } //---------------------------------------------------------- // Use generic conversion // string-like types // NOTE: original check for size used is_convertible but // MSVC-140 selects wrong specialisation if used template::value && std::is_convertible().data()), const char*>::value && std::is_integral().size())>::value >::type* = nullptr> T value_to_generic( const value& jv, priority_tag<3>) { auto& str = jv.as_string(); return T(str.data(), str.size()); } // map-like containers; should go before other containers in order to be able // to tell them apart template::pair_value_type>::value && std::is_constructible::pair_key_type, string_view>::value>::type* = nullptr> T value_to_generic( const value& jv, priority_tag<2>) { using value_type = typename container_traits::value_type; const object& obj = jv.as_object(); T result; try_reserve(result, obj.size(), priority_tag<2>()); for (const auto& val : obj) result.insert(value_type{typename map_traits:: pair_key_type(val.key()), value_to::pair_value_type>(val.value())}); return result; } // all other containers; should go before tuple-like in order to handle // std::array with this overload template:: value_type>::value>::type* = nullptr> T value_to_generic( const value& jv, priority_tag<1>) { const array& arr = jv.as_array(); T result; detail::try_reserve(result, arr.size(), priority_tag<2>()); std::transform(arr.begin(), arr.end(), detail::inserter(result, priority_tag<1>()), [](value const& val) { return value_to::value_type>(val); }); return result; } template T make_tuple_like(const array& arr, boost::mp11::index_sequence) { return T(value_to::type>(arr[Is])...); } // tuple-like types template>::value > 0)>::type* = nullptr> T value_to_generic( const value& jv, priority_tag<0>) { auto& arr = jv.as_array(); constexpr std::size_t N = std::tuple_size>::value; if ( N != arr.size() ) { detail::throw_invalid_argument( "array size does not match tuple size", BOOST_JSON_SOURCE_POS); } return make_tuple_like(arr, boost::mp11::make_index_sequence()); } // Matches containers template::value && !std::is_arithmetic::value>::type, decltype( value_to_generic(std::declval(), priority_tag<2>()))>* = nullptr> T tag_invoke( value_to_tag, value const& jv) { return value_to_generic( jv, priority_tag<3>()); } //---------------------------------------------------------- // Calls to value_to are forwarded to this function // so we can use ADL and hide the built-in tag_invoke // overloads in the detail namespace template&>(), std::declval()))>* = nullptr> T value_to_impl( value_to_tag tag, value const& jv) { return tag_invoke(tag, jv); } } // detail BOOST_JSON_NS_END #endif