libcarla/include/system/boost/json/detail/value_from.hpp
2024-10-18 13:19:59 +08:00

196 lines
5.0 KiB
C++

//
// Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com)
// Copyright (c) 2020 Krystian Stasiowski (sdkrystian@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_FROM_HPP
#define BOOST_JSON_DETAIL_VALUE_FROM_HPP
#include <boost/json/storage_ptr.hpp>
#include <boost/json/value.hpp>
#include <boost/json/detail/value_traits.hpp>
BOOST_JSON_NS_BEGIN
struct value_from_tag { };
template<class T, class = void>
struct has_value_from;
namespace detail {
// The integral_constant parameter here is an
// rvalue reference to make the standard conversion
// sequence to that parameter better, see
// http://eel.is/c++draft/over.ics.rank#3.2.6
template<std::size_t N, class T>
void
tuple_to_array(
T&&,
array&,
std::integral_constant<std::size_t, N>&&)
{
}
template<std::size_t N, std::size_t I, class T>
void
tuple_to_array(
T&& t,
array& arr,
const std::integral_constant<std::size_t, I>&)
{
using std::get;
arr.emplace_back(value_from(
get<I>(std::forward<T>(t)), arr.storage()));
return detail::tuple_to_array<N>(std::forward<T>(t),
arr, std::integral_constant<std::size_t, I + 1>());
}
//----------------------------------------------------------
// User-provided conversion
template<class T, void_t<decltype(tag_invoke(value_from_tag(),
std::declval<value&>(), std::declval<T&&>()))>* = nullptr>
void
value_from_helper(
value& jv,
T&& from,
priority_tag<5>)
{
tag_invoke(value_from_tag(), jv, std::forward<T>(from));
}
//----------------------------------------------------------
// Native conversion
template<class T, typename std::enable_if<
detail::value_constructible<T>::value>::type* = nullptr>
void
value_from_helper(
value& jv,
T&& from,
priority_tag<4>)
{
jv = std::forward<T>(from);
}
template<class T, typename std::enable_if<
std::is_same<detail::remove_cvref<T>,
std::nullptr_t>::value>::type* = nullptr>
void
value_from_helper(
value& jv,
T&&,
priority_tag<4>)
{
// do nothing
BOOST_ASSERT(jv.is_null());
(void)jv;
}
//----------------------------------------------------------
// Generic conversions
// string-like types
// NOTE: original check for size used is_convertible but
// MSVC-140 selects wrong specialisation if used
template<class T, typename std::enable_if<
std::is_constructible<remove_cvref<T>, const char*, std::size_t>::value &&
std::is_convertible<decltype(std::declval<T&>().data()), const char*>::value &&
std::is_integral<decltype(std::declval<T&>().size())>::value
>::type* = nullptr>
void
value_from_helper(
value& jv,
T&& from,
priority_tag<3>)
{
jv.emplace_string().assign(
from.data(), from.size());
}
// map-like types; should go before ranges, so that we can differentiate
// map-like and other ranges
template<class T, typename std::enable_if<
map_traits<T>::has_unique_keys &&
has_value_from<typename map_traits<T>::pair_value_type>::value &&
std::is_convertible<typename map_traits<T>::pair_key_type,
string_view>::value>::type* = nullptr>
void
value_from_helper(
value& jv,
T&& from,
priority_tag<2>)
{
using std::get;
object& obj = jv.emplace_object();
obj.reserve(container_traits<T>::try_size(from));
for (auto&& elem : from)
obj.emplace(get<0>(elem), value_from(
get<1>(elem), obj.storage()));
}
// ranges; should go before tuple-like in order for std::array being handled
// by this overload
template<class T, typename std::enable_if<
has_value_from<typename container_traits<T>::
value_type>::value>::type* = nullptr>
void
value_from_helper(
value& jv,
T&& from,
priority_tag<1>)
{
array& result = jv.emplace_array();
result.reserve(container_traits<T>::try_size(from));
for (auto&& elem : from)
result.emplace_back(
value_from(elem, result.storage()));
}
// tuple-like types
template<class T, typename std::enable_if<
(std::tuple_size<remove_cvref<T>>::value > 0)>::type* = nullptr>
void
value_from_helper(
value& jv,
T&& from,
priority_tag<0>)
{
constexpr std::size_t n =
std::tuple_size<remove_cvref<T>>::value;
array& arr = jv.emplace_array();
arr.reserve(n);
detail::tuple_to_array<n>(std::forward<T>(from),
arr, std::integral_constant<std::size_t, 0>());
}
//----------------------------------------------------------
// Calls to value_from are forwarded to this function
// so we can use ADL and hide the built-in tag_invoke
// overloads in the detail namespace
template<class T, class = void_t<
decltype(detail::value_from_helper(std::declval<value&>(),
std::declval<T&&>(), priority_tag<5>()))>>
value
value_from_impl(
T&& from,
storage_ptr sp)
{
value jv(std::move(sp));
detail::value_from_helper(jv, std::forward<T>(from), priority_tag<5>());
return jv;
}
} // detail
BOOST_JSON_NS_END
#endif