mirror of
https://github.com/nlohmann/json.git
synced 2026-02-17 00:54:00 +00:00
Reference tuple from json (#5016)
* Add reference handling to tuples Signed-off-by: Evelyn LePain <ava.lepain@gmail.com> * Remove template template type because pair isn't working Signed-off-by: Evelyn LePain <ava.lepain@gmail.com> * amalgamate std::tie changes Signed-off-by: Evelyn LePain <ava.lepain@gmail.com> * allow the elation of a move by removing the ref requirement Signed-off-by: Evelyn LePain <ava.lepain@gmail.com> * force all number_xxx_t to be interchangeable Signed-off-by: Evelyn LePain <ava.lepain@gmail.com> * Finally got amalgamate to work correctly Signed-off-by: Evelyn LePain <ava.lepain@gmail.com> * remove const version, add a test case for scrambled number representations. Signed-off-by: Evelyn LePain <ava.lepain@gmail.com> * Use the logical set of requirements instead of decltype because VS 2015 doesn't like it Signed-off-by: Evelyn LePain <ava.lepain@gmail.com> --------- Signed-off-by: Evelyn LePain <ava.lepain@gmail.com>
This commit is contained in:
@@ -26,6 +26,7 @@
|
||||
#include <nlohmann/detail/meta/identity_tag.hpp>
|
||||
#include <nlohmann/detail/meta/std_fs.hpp>
|
||||
#include <nlohmann/detail/meta/type_traits.hpp>
|
||||
#include <nlohmann/detail/meta/logic.hpp>
|
||||
#include <nlohmann/detail/string_concat.hpp>
|
||||
#include <nlohmann/detail/value_t.hpp>
|
||||
|
||||
@@ -446,13 +447,36 @@ inline void from_json(const BasicJsonType& j, ArithmeticType& val)
|
||||
}
|
||||
}
|
||||
|
||||
template<typename BasicJsonType, typename... Args, std::size_t... Idx>
|
||||
std::tuple<Args...> from_json_tuple_impl_base(BasicJsonType&& j, index_sequence<Idx...> /*unused*/)
|
||||
template<typename BasicJsonType, typename Type>
|
||||
detail::uncvref_t<Type> from_json_tuple_get_impl(BasicJsonType&& j, detail::identity_tag<Type> /*unused*/, detail::priority_tag<0> /*unused*/)
|
||||
{
|
||||
return std::make_tuple(std::forward<BasicJsonType>(j).at(Idx).template get<Args>()...);
|
||||
return std::forward<BasicJsonType>(j).template get<detail::uncvref_t<Type>>();
|
||||
}
|
||||
|
||||
template<typename BasicJsonType>
|
||||
template<typename BasicJsonType, typename Type,
|
||||
detail::enable_if_t<detail::is_compatible_reference_type<BasicJsonType, Type>::value, int> = 0>
|
||||
Type from_json_tuple_get_impl(BasicJsonType && j, detail::identity_tag<Type> /*unused*/, detail::priority_tag<1> /*unused*/)
|
||||
{
|
||||
return std::forward<BasicJsonType>(j).template get_ref<Type>();
|
||||
}
|
||||
|
||||
template<typename BasicJsonType, typename Type,
|
||||
detail::enable_if_t<std::is_arithmetic<uncvref_t<Type>>::value, int> = 0>
|
||||
detail::uncvref_t<Type> from_json_tuple_get_impl(BasicJsonType && j, detail::identity_tag<Type> /*unused*/, detail::priority_tag<2> /*unused*/)
|
||||
{
|
||||
return std::forward<BasicJsonType>(j).template get<detail::uncvref_t<Type>>();
|
||||
}
|
||||
|
||||
template<std::size_t PTagValue, typename BasicJsonType, typename... Types>
|
||||
using tuple_type = std::tuple < decltype(from_json_tuple_get_impl(std::declval<BasicJsonType>(), detail::identity_tag<Types> {}, detail::priority_tag<PTagValue> {}))... >;
|
||||
|
||||
template<std::size_t PTagValue, typename... Args, typename BasicJsonType, std::size_t... Idx>
|
||||
tuple_type<PTagValue, BasicJsonType, Args...> from_json_tuple_impl_base(BasicJsonType&& j, index_sequence<Idx...> /*unused*/)
|
||||
{
|
||||
return tuple_type<PTagValue, BasicJsonType, Args...>(from_json_tuple_get_impl(std::forward<BasicJsonType>(j).at(Idx), detail::identity_tag<Args> {}, detail::priority_tag<PTagValue> {})...);
|
||||
}
|
||||
|
||||
template<std::size_t PTagValue, typename BasicJsonType>
|
||||
std::tuple<> from_json_tuple_impl_base(BasicJsonType& /*unused*/, index_sequence<> /*unused*/)
|
||||
{
|
||||
return {};
|
||||
@@ -474,13 +498,15 @@ inline void from_json_tuple_impl(BasicJsonType&& j, std::pair<A1, A2>& p, priori
|
||||
template<typename BasicJsonType, typename... Args>
|
||||
std::tuple<Args...> from_json_tuple_impl(BasicJsonType&& j, identity_tag<std::tuple<Args...>> /*unused*/, priority_tag<2> /*unused*/)
|
||||
{
|
||||
return from_json_tuple_impl_base<BasicJsonType, Args...>(std::forward<BasicJsonType>(j), index_sequence_for<Args...> {});
|
||||
static_assert(cxpr_and<cxpr_or<cxpr_not<std::is_reference<Args>>, is_compatible_reference_type<BasicJsonType, Args>>...>::value,
|
||||
"Can not return a tuple containing references to types not contained in a Json, try Json::get_to()");
|
||||
return from_json_tuple_impl_base<1, Args...>(std::forward<BasicJsonType>(j), index_sequence_for<Args...> {});
|
||||
}
|
||||
|
||||
template<typename BasicJsonType, typename... Args>
|
||||
inline void from_json_tuple_impl(BasicJsonType&& j, std::tuple<Args...>& t, priority_tag<3> /*unused*/)
|
||||
{
|
||||
t = from_json_tuple_impl_base<BasicJsonType, Args...>(std::forward<BasicJsonType>(j), index_sequence_for<Args...> {});
|
||||
t = from_json_tuple_impl_base<2, Args...>(std::forward<BasicJsonType>(j), index_sequence_for<Args...> {});
|
||||
}
|
||||
|
||||
template<typename BasicJsonType, typename TupleRelated>
|
||||
|
||||
54
include/nlohmann/detail/meta/logic.hpp
Normal file
54
include/nlohmann/detail/meta/logic.hpp
Normal file
@@ -0,0 +1,54 @@
|
||||
#pragma once
|
||||
|
||||
#include <nlohmann/detail/macro_scope.hpp>
|
||||
|
||||
NLOHMANN_JSON_NAMESPACE_BEGIN
|
||||
namespace detail
|
||||
{
|
||||
#ifdef JSON_HAS_CPP_17
|
||||
|
||||
template<bool... Booleans>
|
||||
struct cxpr_or_impl : std::integral_constant < bool, (Booleans || ...) > {};
|
||||
|
||||
template<bool... Booleans>
|
||||
struct cxpr_and_impl : std::integral_constant < bool, (Booleans &&...) > {};
|
||||
|
||||
#else
|
||||
|
||||
template<bool... Booleans>
|
||||
struct cxpr_or_impl : std::false_type {};
|
||||
|
||||
template<bool... Booleans>
|
||||
struct cxpr_or_impl<true, Booleans...> : std::true_type {};
|
||||
|
||||
template<bool... Booleans>
|
||||
struct cxpr_or_impl<false, Booleans...> : cxpr_or_impl<Booleans...> {};
|
||||
|
||||
template<bool... Booleans>
|
||||
struct cxpr_and_impl : std::true_type {};
|
||||
|
||||
template<bool... Booleans>
|
||||
struct cxpr_and_impl<true, Booleans...> : cxpr_and_impl<Booleans...> {};
|
||||
|
||||
template<bool... Booleans>
|
||||
struct cxpr_and_impl<false, Booleans...> : std::false_type {};
|
||||
|
||||
#endif
|
||||
|
||||
template<class Boolean>
|
||||
struct cxpr_not : std::integral_constant < bool, !Boolean::value > {};
|
||||
|
||||
template<class... Booleans>
|
||||
struct cxpr_or : cxpr_or_impl<Booleans::value...> {};
|
||||
|
||||
template<bool... Booleans>
|
||||
struct cxpr_or_c : cxpr_or_impl<Booleans...> {};
|
||||
|
||||
template<class... Booleans>
|
||||
struct cxpr_and : cxpr_and_impl<Booleans::value...> {};
|
||||
|
||||
template<bool... Booleans>
|
||||
struct cxpr_and_c : cxpr_and_impl<Booleans...> {};
|
||||
|
||||
} // namespace detail
|
||||
NLOHMANN_JSON_NAMESPACE_END
|
||||
@@ -559,6 +559,28 @@ template<typename BasicJsonType, typename CompatibleType>
|
||||
struct is_compatible_type
|
||||
: is_compatible_type_impl<BasicJsonType, CompatibleType> {};
|
||||
|
||||
template<typename BasicJsonType, typename CompatibleReferenceType>
|
||||
struct is_compatible_reference_type_impl
|
||||
{
|
||||
using JsonType = uncvref_t<BasicJsonType>;
|
||||
using CVType = typename std::remove_reference<CompatibleReferenceType>::type;
|
||||
using Type = typename std::remove_cv<CVType>::type;
|
||||
constexpr static bool value = std::is_reference<CompatibleReferenceType>::value &&
|
||||
(!std::is_const<typename std::remove_reference<BasicJsonType>::type>::value || std::is_const<CVType>::value) &&
|
||||
(std::is_same<typename JsonType::boolean_t, Type>::value ||
|
||||
std::is_same<typename JsonType::number_float_t, Type>::value ||
|
||||
std::is_same<typename JsonType::number_integer_t, Type>::value ||
|
||||
std::is_same<typename JsonType::number_unsigned_t, Type>::value ||
|
||||
std::is_same<typename JsonType::string_t, Type>::value ||
|
||||
std::is_same<typename JsonType::binary_t, Type>::value ||
|
||||
std::is_same<typename JsonType::object_t, Type>::value ||
|
||||
std::is_same<typename JsonType::array_t, Type>::value);
|
||||
};
|
||||
|
||||
template<typename BasicJsonType, typename CompatibleReferenceType>
|
||||
struct is_compatible_reference_type
|
||||
: is_compatible_reference_type_impl<BasicJsonType, CompatibleReferenceType> {};
|
||||
|
||||
template<typename T1, typename T2>
|
||||
struct is_constructible_tuple : std::false_type {};
|
||||
|
||||
|
||||
@@ -4103,6 +4103,28 @@ template<typename BasicJsonType, typename CompatibleType>
|
||||
struct is_compatible_type
|
||||
: is_compatible_type_impl<BasicJsonType, CompatibleType> {};
|
||||
|
||||
template<typename BasicJsonType, typename CompatibleReferenceType>
|
||||
struct is_compatible_reference_type_impl
|
||||
{
|
||||
using JsonType = uncvref_t<BasicJsonType>;
|
||||
using CVType = typename std::remove_reference<CompatibleReferenceType>::type;
|
||||
using Type = typename std::remove_cv<CVType>::type;
|
||||
constexpr static bool value = std::is_reference<CompatibleReferenceType>::value &&
|
||||
(!std::is_const<typename std::remove_reference<BasicJsonType>::type>::value || std::is_const<CVType>::value) &&
|
||||
(std::is_same<typename JsonType::boolean_t, Type>::value ||
|
||||
std::is_same<typename JsonType::number_float_t, Type>::value ||
|
||||
std::is_same<typename JsonType::number_integer_t, Type>::value ||
|
||||
std::is_same<typename JsonType::number_unsigned_t, Type>::value ||
|
||||
std::is_same<typename JsonType::string_t, Type>::value ||
|
||||
std::is_same<typename JsonType::binary_t, Type>::value ||
|
||||
std::is_same<typename JsonType::object_t, Type>::value ||
|
||||
std::is_same<typename JsonType::array_t, Type>::value);
|
||||
};
|
||||
|
||||
template<typename BasicJsonType, typename CompatibleReferenceType>
|
||||
struct is_compatible_reference_type
|
||||
: is_compatible_reference_type_impl<BasicJsonType, CompatibleReferenceType> {};
|
||||
|
||||
template<typename T1, typename T2>
|
||||
struct is_constructible_tuple : std::false_type {};
|
||||
|
||||
@@ -4860,6 +4882,63 @@ NLOHMANN_JSON_NAMESPACE_END
|
||||
|
||||
// #include <nlohmann/detail/meta/type_traits.hpp>
|
||||
|
||||
// #include <nlohmann/detail/meta/logic.hpp>
|
||||
|
||||
|
||||
// #include <nlohmann/detail/macro_scope.hpp>
|
||||
|
||||
|
||||
NLOHMANN_JSON_NAMESPACE_BEGIN
|
||||
namespace detail
|
||||
{
|
||||
#ifdef JSON_HAS_CPP_17
|
||||
|
||||
template<bool... Booleans>
|
||||
struct cxpr_or_impl : std::integral_constant < bool, (Booleans || ...) > {};
|
||||
|
||||
template<bool... Booleans>
|
||||
struct cxpr_and_impl : std::integral_constant < bool, (Booleans &&...) > {};
|
||||
|
||||
#else
|
||||
|
||||
template<bool... Booleans>
|
||||
struct cxpr_or_impl : std::false_type {};
|
||||
|
||||
template<bool... Booleans>
|
||||
struct cxpr_or_impl<true, Booleans...> : std::true_type {};
|
||||
|
||||
template<bool... Booleans>
|
||||
struct cxpr_or_impl<false, Booleans...> : cxpr_or_impl<Booleans...> {};
|
||||
|
||||
template<bool... Booleans>
|
||||
struct cxpr_and_impl : std::true_type {};
|
||||
|
||||
template<bool... Booleans>
|
||||
struct cxpr_and_impl<true, Booleans...> : cxpr_and_impl<Booleans...> {};
|
||||
|
||||
template<bool... Booleans>
|
||||
struct cxpr_and_impl<false, Booleans...> : std::false_type {};
|
||||
|
||||
#endif
|
||||
|
||||
template<class Boolean>
|
||||
struct cxpr_not : std::integral_constant < bool, !Boolean::value > {};
|
||||
|
||||
template<class... Booleans>
|
||||
struct cxpr_or : cxpr_or_impl<Booleans::value...> {};
|
||||
|
||||
template<bool... Booleans>
|
||||
struct cxpr_or_c : cxpr_or_impl<Booleans...> {};
|
||||
|
||||
template<class... Booleans>
|
||||
struct cxpr_and : cxpr_and_impl<Booleans::value...> {};
|
||||
|
||||
template<bool... Booleans>
|
||||
struct cxpr_and_c : cxpr_and_impl<Booleans...> {};
|
||||
|
||||
} // namespace detail
|
||||
NLOHMANN_JSON_NAMESPACE_END
|
||||
|
||||
// #include <nlohmann/detail/string_concat.hpp>
|
||||
|
||||
// #include <nlohmann/detail/value_t.hpp>
|
||||
@@ -5282,13 +5361,36 @@ inline void from_json(const BasicJsonType& j, ArithmeticType& val)
|
||||
}
|
||||
}
|
||||
|
||||
template<typename BasicJsonType, typename... Args, std::size_t... Idx>
|
||||
std::tuple<Args...> from_json_tuple_impl_base(BasicJsonType&& j, index_sequence<Idx...> /*unused*/)
|
||||
template<typename BasicJsonType, typename Type>
|
||||
detail::uncvref_t<Type> from_json_tuple_get_impl(BasicJsonType&& j, detail::identity_tag<Type> /*unused*/, detail::priority_tag<0> /*unused*/)
|
||||
{
|
||||
return std::make_tuple(std::forward<BasicJsonType>(j).at(Idx).template get<Args>()...);
|
||||
return std::forward<BasicJsonType>(j).template get<detail::uncvref_t<Type>>();
|
||||
}
|
||||
|
||||
template<typename BasicJsonType>
|
||||
template<typename BasicJsonType, typename Type,
|
||||
detail::enable_if_t<detail::is_compatible_reference_type<BasicJsonType, Type>::value, int> = 0>
|
||||
Type from_json_tuple_get_impl(BasicJsonType && j, detail::identity_tag<Type> /*unused*/, detail::priority_tag<1> /*unused*/)
|
||||
{
|
||||
return std::forward<BasicJsonType>(j).template get_ref<Type>();
|
||||
}
|
||||
|
||||
template<typename BasicJsonType, typename Type,
|
||||
detail::enable_if_t<std::is_arithmetic<uncvref_t<Type>>::value, int> = 0>
|
||||
detail::uncvref_t<Type> from_json_tuple_get_impl(BasicJsonType && j, detail::identity_tag<Type> /*unused*/, detail::priority_tag<2> /*unused*/)
|
||||
{
|
||||
return std::forward<BasicJsonType>(j).template get<detail::uncvref_t<Type>>();
|
||||
}
|
||||
|
||||
template<std::size_t PTagValue, typename BasicJsonType, typename... Types>
|
||||
using tuple_type = std::tuple < decltype(from_json_tuple_get_impl(std::declval<BasicJsonType>(), detail::identity_tag<Types> {}, detail::priority_tag<PTagValue> {}))... >;
|
||||
|
||||
template<std::size_t PTagValue, typename... Args, typename BasicJsonType, std::size_t... Idx>
|
||||
tuple_type<PTagValue, BasicJsonType, Args...> from_json_tuple_impl_base(BasicJsonType&& j, index_sequence<Idx...> /*unused*/)
|
||||
{
|
||||
return tuple_type<PTagValue, BasicJsonType, Args...>(from_json_tuple_get_impl(std::forward<BasicJsonType>(j).at(Idx), detail::identity_tag<Args> {}, detail::priority_tag<PTagValue> {})...);
|
||||
}
|
||||
|
||||
template<std::size_t PTagValue, typename BasicJsonType>
|
||||
std::tuple<> from_json_tuple_impl_base(BasicJsonType& /*unused*/, index_sequence<> /*unused*/)
|
||||
{
|
||||
return {};
|
||||
@@ -5310,13 +5412,15 @@ inline void from_json_tuple_impl(BasicJsonType&& j, std::pair<A1, A2>& p, priori
|
||||
template<typename BasicJsonType, typename... Args>
|
||||
std::tuple<Args...> from_json_tuple_impl(BasicJsonType&& j, identity_tag<std::tuple<Args...>> /*unused*/, priority_tag<2> /*unused*/)
|
||||
{
|
||||
return from_json_tuple_impl_base<BasicJsonType, Args...>(std::forward<BasicJsonType>(j), index_sequence_for<Args...> {});
|
||||
static_assert(cxpr_and<cxpr_or<cxpr_not<std::is_reference<Args>>, is_compatible_reference_type<BasicJsonType, Args>>...>::value,
|
||||
"Can not return a tuple containing references to types not contained in a Json, try Json::get_to()");
|
||||
return from_json_tuple_impl_base<1, Args...>(std::forward<BasicJsonType>(j), index_sequence_for<Args...> {});
|
||||
}
|
||||
|
||||
template<typename BasicJsonType, typename... Args>
|
||||
inline void from_json_tuple_impl(BasicJsonType&& j, std::tuple<Args...>& t, priority_tag<3> /*unused*/)
|
||||
{
|
||||
t = from_json_tuple_impl_base<BasicJsonType, Args...>(std::forward<BasicJsonType>(j), index_sequence_for<Args...> {});
|
||||
t = from_json_tuple_impl_base<2, Args...>(std::forward<BasicJsonType>(j), index_sequence_for<Args...> {});
|
||||
}
|
||||
|
||||
template<typename BasicJsonType, typename TupleRelated>
|
||||
|
||||
@@ -281,6 +281,79 @@ TEST_CASE("constructors")
|
||||
// CHECK(std::get<2>(t) == j[2]); // commented out due to CI issue, see https://github.com/nlohmann/json/pull/3985 and https://github.com/nlohmann/json/issues/4025
|
||||
}
|
||||
|
||||
SECTION("std::tuple tie")
|
||||
{
|
||||
const auto a = 1.0;
|
||||
const auto* const b = "string";
|
||||
const auto c = 42;
|
||||
const auto d = std::vector<int> {0, 2};
|
||||
const size_t e = 1234;
|
||||
auto t = std::tie(a, b, c, d, e);
|
||||
json const j(t);
|
||||
|
||||
double a_out = 0;
|
||||
std::string b_out;
|
||||
int c_out = 0;
|
||||
std::vector<int> d_out;
|
||||
int64_t e_out = 0;
|
||||
auto t_out = std::tie(a_out, b_out, c_out, d_out, e_out);
|
||||
j.get_to(t_out);
|
||||
CHECK(a_out == a);
|
||||
CHECK(b_out == b);
|
||||
CHECK(c_out == c);
|
||||
CHECK(d_out == d);
|
||||
CHECK(e_out == e);
|
||||
}
|
||||
|
||||
SECTION("std::tuple of references to elements")
|
||||
{
|
||||
const auto a = 1.0;
|
||||
const auto* const b = "string";
|
||||
const auto c = 42;
|
||||
const size_t d = 1234;
|
||||
const auto t = std::tie(a, b, c, d);
|
||||
json const j(t);
|
||||
|
||||
auto t_out = j.get<std::tuple<const json::number_float_t&,
|
||||
const json::string_t&,
|
||||
const json::number_integer_t&,
|
||||
const json::number_unsigned_t&>>();
|
||||
CHECK(&std::get<0>(t_out) == j[0].get_ptr<const json::number_float_t*>());
|
||||
CHECK(&std::get<1>(t_out) == j[1].get_ptr<const json::string_t*>());
|
||||
CHECK(&std::get<2>(t_out) == j[2].get_ptr<const json::number_integer_t*>());
|
||||
CHECK(&std::get<3>(t_out) == j[3].get_ptr<const json::number_unsigned_t*>());
|
||||
CHECK(std::get<0>(t_out) == a);
|
||||
CHECK(std::get<1>(t_out) == b);
|
||||
CHECK(std::get<2>(t_out) == c);
|
||||
CHECK(std::get<3>(t_out) == d);
|
||||
}
|
||||
|
||||
SECTION("std::tuple mixed arithmetic types")
|
||||
{
|
||||
using j_float_t = json::number_float_t;
|
||||
using j_int_t = json::number_integer_t;
|
||||
using j_uint_t = json::number_unsigned_t;
|
||||
const j_float_t a = 1.0;
|
||||
const j_int_t b = 1234;
|
||||
const j_uint_t c = 42;
|
||||
json const j(std::tie(a, b, c, c));
|
||||
|
||||
auto t1 = j.get<std::tuple<j_int_t, j_uint_t, j_float_t, const j_uint_t&>>();
|
||||
j_uint_t a2 = 0;
|
||||
j_float_t b2 = 0;
|
||||
j_int_t c2 = 0;
|
||||
auto t2 = std::tie(a2, b2, c2);
|
||||
j.get_to(t2);
|
||||
|
||||
CHECK(std::get<0>(t1) == static_cast<j_int_t>(a));
|
||||
CHECK(std::get<1>(t1) == static_cast<j_uint_t>(b));
|
||||
CHECK(std::get<2>(t1) == static_cast<j_float_t>(c));
|
||||
// t1[3] exists only to force usage of the no-default-constructor version
|
||||
CHECK(a2 == static_cast<j_uint_t>(a));
|
||||
CHECK(b2 == static_cast<j_float_t>(b));
|
||||
CHECK(c2 == static_cast<j_int_t>(c));
|
||||
}
|
||||
|
||||
SECTION("std::pair/tuple/array failures")
|
||||
{
|
||||
json const j{1};
|
||||
|
||||
Reference in New Issue
Block a user