mirror of
https://github.com/nlohmann/json.git
synced 2026-07-11 13:05:11 +00:00
@@ -177,8 +177,11 @@ struct external_constructor<value_t::array>
|
||||
}
|
||||
|
||||
template < typename BasicJsonType, typename CompatibleArrayType,
|
||||
enable_if_t < !std::is_same<CompatibleArrayType, typename BasicJsonType::array_t>::value,
|
||||
int > = 0 >
|
||||
enable_if_t < !std::is_same<CompatibleArrayType, typename BasicJsonType::array_t>::value
|
||||
#if JSON_HAS_RANGES && !defined(__MINGW32__)
|
||||
&& !is_compatible_range_view<CompatibleArrayType>::value
|
||||
#endif
|
||||
, int > = 0 >
|
||||
static void construct(BasicJsonType& j, const CompatibleArrayType& arr)
|
||||
{
|
||||
using std::begin;
|
||||
@@ -218,6 +221,25 @@ struct external_constructor<value_t::array>
|
||||
j.set_parents();
|
||||
j.assert_invariant();
|
||||
}
|
||||
|
||||
// std::ranges does not work properly on MinGW due to incomplete C++20 support
|
||||
// see https://github.com/nlohmann/json/issues/4916
|
||||
#if JSON_HAS_RANGES && !defined(__MINGW32__)
|
||||
template<typename BasicJsonType, typename CompatibleArrayType,
|
||||
enable_if_t<is_compatible_range_view<std::remove_cvref_t<CompatibleArrayType>>::value, int> = 0>
|
||||
static void construct(BasicJsonType& j, CompatibleArrayType && arr)
|
||||
{
|
||||
j.m_data.m_value.destroy(j.m_data.m_type);
|
||||
j.m_data.m_type = value_t::array;
|
||||
j.m_data.m_value = value_t::array;
|
||||
for (auto&& x : std::forward<CompatibleArrayType>(arr))
|
||||
{
|
||||
j.m_data.m_value.array->push_back(x);
|
||||
j.set_parent(j.m_data.m_value.array->back());
|
||||
}
|
||||
j.assert_invariant();
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
template<>
|
||||
@@ -355,13 +377,29 @@ template < typename BasicJsonType, typename CompatibleArrayType,
|
||||
!is_compatible_object_type<BasicJsonType, CompatibleArrayType>::value&&
|
||||
!is_compatible_string_type<BasicJsonType, CompatibleArrayType>::value&&
|
||||
!std::is_same<typename BasicJsonType::binary_t, CompatibleArrayType>::value&&
|
||||
!is_basic_json<CompatibleArrayType>::value,
|
||||
!is_basic_json<CompatibleArrayType>::value
|
||||
#if JSON_HAS_RANGES && !defined(__MINGW32__)
|
||||
&& !is_compatible_range_view<CompatibleArrayType>::value
|
||||
#endif
|
||||
,
|
||||
int > = 0 >
|
||||
inline void to_json(BasicJsonType& j, const CompatibleArrayType& arr)
|
||||
{
|
||||
external_constructor<value_t::array>::construct(j, arr);
|
||||
}
|
||||
|
||||
#if JSON_HAS_RANGES && !defined(__MINGW32__)
|
||||
template < typename BasicJsonType, typename T,
|
||||
enable_if_t < is_compatible_range_view<std::remove_cvref_t<T>>::value
|
||||
&& !is_compatible_string_type<BasicJsonType, std::remove_cvref_t<T>>::value
|
||||
&& !is_compatible_object_type<BasicJsonType, std::remove_cvref_t<T>>::value
|
||||
&& !is_basic_json<std::remove_cvref_t<T>>::value, int > = 0 >
|
||||
inline void to_json(BasicJsonType& j, T && arr)
|
||||
{
|
||||
external_constructor<value_t::array>::construct(j, std::forward<T>(arr));
|
||||
}
|
||||
#endif
|
||||
|
||||
template<typename BasicJsonType>
|
||||
inline void to_json(BasicJsonType& j, const typename BasicJsonType::binary_t& bin)
|
||||
{
|
||||
|
||||
@@ -18,6 +18,9 @@
|
||||
#endif
|
||||
#include <nlohmann/detail/iterators/iterator_traits.hpp>
|
||||
#include <nlohmann/detail/macro_scope.hpp>
|
||||
#ifdef JSON_HAS_CPP_17
|
||||
#include <optional> // optional
|
||||
#endif
|
||||
#include <nlohmann/detail/meta/call_std/begin.hpp>
|
||||
#include <nlohmann/detail/meta/call_std/end.hpp>
|
||||
#include <nlohmann/detail/meta/cpp_future.hpp>
|
||||
@@ -450,6 +453,51 @@ struct is_constructible_string_type
|
||||
value_type_t, laundered_type >>::value;
|
||||
};
|
||||
|
||||
// Forward declarations: iteration_proxy.hpp includes this file, so we cannot
|
||||
// include it here.
|
||||
template<typename IteratorType> class iteration_proxy;
|
||||
template<typename IteratorType> class iteration_proxy_value;
|
||||
|
||||
// Identifies nlohmann's internal iteration-proxy types. These must be excluded
|
||||
// before evaluating any std::ranges concept to avoid circular constraints.
|
||||
template<typename T> struct is_iteration_proxy_type : std::false_type {};
|
||||
template<typename T> struct is_iteration_proxy_type<iteration_proxy<T>> : std::true_type {};
|
||||
template<typename T> struct is_iteration_proxy_type<iteration_proxy_value<T>> : std::true_type {};
|
||||
|
||||
// In C++26, std::optional satisfies std::ranges::view; exclude it so the
|
||||
// range-view overload does not hijack the optional serializer.
|
||||
#ifdef JSON_HAS_CPP_17
|
||||
template<typename T> struct is_range_view_optional_type : std::false_type {};
|
||||
template<typename T> struct is_range_view_optional_type<std::optional<T>> : std::true_type {};
|
||||
#else
|
||||
template<typename T> struct is_range_view_optional_type : std::false_type {};
|
||||
#endif
|
||||
|
||||
// std::ranges does not work properly on MinGW due to incomplete C++20 support
|
||||
// see https://github.com/nlohmann/json/issues/4916
|
||||
#if JSON_HAS_RANGES && !defined(__MINGW32__)
|
||||
|
||||
// SafeToCheck guards against types that trigger circular constraints when
|
||||
// std::ranges::view<T> is evaluated on GCC 12 / libstdc++ 12:
|
||||
// - iteration_proxy / iteration_proxy_value directly
|
||||
// - views wrapping the above (e.g. owning_view<iteration_proxy<...>>)
|
||||
// - views wrapping basic_json (e.g. ref_view<json>) — same circularity
|
||||
// via json's constructors → is_compatible_array_type → here
|
||||
// nlohmann's plain range_value_t (iterator_traits-based) is safe to call
|
||||
// before any std::ranges concept is touched, so we use it for the checks.
|
||||
template < typename T, bool SafeToCheck =
|
||||
!is_iteration_proxy_type<T>::value &&
|
||||
!is_iteration_proxy_type<detected_t<range_value_t, T>>::value &&
|
||||
!is_basic_json<detected_t<range_value_t, T>>::value &&
|
||||
!is_range_view_optional_type<T>::value >
|
||||
struct is_compatible_range_view : std::false_type {};
|
||||
|
||||
template<typename T>
|
||||
struct is_compatible_range_view<T, true>
|
||||
: std::bool_constant<std::ranges::view<T>> {};
|
||||
|
||||
#endif
|
||||
|
||||
template<typename BasicJsonType, typename CompatibleArrayType, typename = void>
|
||||
struct is_compatible_array_type_impl : std::false_type {};
|
||||
|
||||
@@ -461,13 +509,38 @@ struct is_compatible_array_type_impl <
|
||||
is_iterator_traits<iterator_traits<detected_t<iterator_t, CompatibleArrayType>>>::value&&
|
||||
// special case for types like std::filesystem::path whose iterator's value_type are themselves
|
||||
// c.f. https://github.com/nlohmann/json/pull/3073
|
||||
!std::is_same<CompatibleArrayType, detected_t<range_value_t, CompatibleArrayType>>::value >>
|
||||
!std::is_same<CompatibleArrayType, detected_t<range_value_t, CompatibleArrayType>>::value
|
||||
// When range-view support is enabled, std::ranges::view types (e.g. std::string_view,
|
||||
// filter_view) can match BOTH this iterator-based specialization AND the view-based one
|
||||
// below, causing ambiguity. Exclude views here so the two specializations are mutually
|
||||
// exclusive: this one handles plain iterable containers, the other handles views.
|
||||
#if JSON_HAS_RANGES && !defined(__MINGW32__)
|
||||
&& !is_compatible_range_view<CompatibleArrayType>::value
|
||||
#endif
|
||||
>>
|
||||
{
|
||||
static constexpr bool value =
|
||||
is_constructible<BasicJsonType,
|
||||
range_value_t<CompatibleArrayType>>::value;
|
||||
};
|
||||
|
||||
#if JSON_HAS_RANGES && !defined(__MINGW32__)
|
||||
template<typename BasicJsonType, typename CompatibleArrayType>
|
||||
struct is_compatible_array_type_impl <
|
||||
BasicJsonType, CompatibleArrayType,
|
||||
enable_if_t < is_compatible_range_view<CompatibleArrayType>::value
|
||||
&& !std::is_same<detected_t<range_value_t, CompatibleArrayType>, char>::value
|
||||
&& !std::is_same<detected_t<range_value_t, CompatibleArrayType>, wchar_t>::value >>
|
||||
{
|
||||
// CompatibleArrayType is a std::ranges::view here, so std::ranges::range_value_t
|
||||
// is safe and correctly handles C++20 iterators that may lack classic iterator_traits.
|
||||
static constexpr bool value =
|
||||
is_constructible<BasicJsonType,
|
||||
std::ranges::range_value_t<CompatibleArrayType>>::value;
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
template<typename BasicJsonType, typename CompatibleArrayType>
|
||||
struct is_compatible_array_type
|
||||
: is_compatible_array_type_impl<BasicJsonType, CompatibleArrayType> {};
|
||||
|
||||
@@ -3663,6 +3663,9 @@ NLOHMANN_JSON_NAMESPACE_END
|
||||
|
||||
// #include <nlohmann/detail/macro_scope.hpp>
|
||||
|
||||
#ifdef JSON_HAS_CPP_17
|
||||
#include <optional> // optional
|
||||
#endif
|
||||
// #include <nlohmann/detail/meta/call_std/begin.hpp>
|
||||
// __ _____ _____ _____
|
||||
// __| | __| | | | JSON for Modern C++
|
||||
@@ -4212,6 +4215,51 @@ struct is_constructible_string_type
|
||||
value_type_t, laundered_type >>::value;
|
||||
};
|
||||
|
||||
// Forward declarations: iteration_proxy.hpp includes this file, so we cannot
|
||||
// include it here.
|
||||
template<typename IteratorType> class iteration_proxy;
|
||||
template<typename IteratorType> class iteration_proxy_value;
|
||||
|
||||
// Identifies nlohmann's internal iteration-proxy types. These must be excluded
|
||||
// before evaluating any std::ranges concept to avoid circular constraints.
|
||||
template<typename T> struct is_iteration_proxy_type : std::false_type {};
|
||||
template<typename T> struct is_iteration_proxy_type<iteration_proxy<T>> : std::true_type {};
|
||||
template<typename T> struct is_iteration_proxy_type<iteration_proxy_value<T>> : std::true_type {};
|
||||
|
||||
// In C++26, std::optional satisfies std::ranges::view; exclude it so the
|
||||
// range-view overload does not hijack the optional serializer.
|
||||
#ifdef JSON_HAS_CPP_17
|
||||
template<typename T> struct is_range_view_optional_type : std::false_type {};
|
||||
template<typename T> struct is_range_view_optional_type<std::optional<T>> : std::true_type {};
|
||||
#else
|
||||
template<typename T> struct is_range_view_optional_type : std::false_type {};
|
||||
#endif
|
||||
|
||||
// std::ranges does not work properly on MinGW due to incomplete C++20 support
|
||||
// see https://github.com/nlohmann/json/issues/4916
|
||||
#if JSON_HAS_RANGES && !defined(__MINGW32__)
|
||||
|
||||
// SafeToCheck guards against types that trigger circular constraints when
|
||||
// std::ranges::view<T> is evaluated on GCC 12 / libstdc++ 12:
|
||||
// - iteration_proxy / iteration_proxy_value directly
|
||||
// - views wrapping the above (e.g. owning_view<iteration_proxy<...>>)
|
||||
// - views wrapping basic_json (e.g. ref_view<json>) — same circularity
|
||||
// via json's constructors → is_compatible_array_type → here
|
||||
// nlohmann's plain range_value_t (iterator_traits-based) is safe to call
|
||||
// before any std::ranges concept is touched, so we use it for the checks.
|
||||
template < typename T, bool SafeToCheck =
|
||||
!is_iteration_proxy_type<T>::value &&
|
||||
!is_iteration_proxy_type<detected_t<range_value_t, T>>::value &&
|
||||
!is_basic_json<detected_t<range_value_t, T>>::value &&
|
||||
!is_range_view_optional_type<T>::value >
|
||||
struct is_compatible_range_view : std::false_type {};
|
||||
|
||||
template<typename T>
|
||||
struct is_compatible_range_view<T, true>
|
||||
: std::bool_constant<std::ranges::view<T>> {};
|
||||
|
||||
#endif
|
||||
|
||||
template<typename BasicJsonType, typename CompatibleArrayType, typename = void>
|
||||
struct is_compatible_array_type_impl : std::false_type {};
|
||||
|
||||
@@ -4223,13 +4271,38 @@ struct is_compatible_array_type_impl <
|
||||
is_iterator_traits<iterator_traits<detected_t<iterator_t, CompatibleArrayType>>>::value&&
|
||||
// special case for types like std::filesystem::path whose iterator's value_type are themselves
|
||||
// c.f. https://github.com/nlohmann/json/pull/3073
|
||||
!std::is_same<CompatibleArrayType, detected_t<range_value_t, CompatibleArrayType>>::value >>
|
||||
!std::is_same<CompatibleArrayType, detected_t<range_value_t, CompatibleArrayType>>::value
|
||||
// When range-view support is enabled, std::ranges::view types (e.g. std::string_view,
|
||||
// filter_view) can match BOTH this iterator-based specialization AND the view-based one
|
||||
// below, causing ambiguity. Exclude views here so the two specializations are mutually
|
||||
// exclusive: this one handles plain iterable containers, the other handles views.
|
||||
#if JSON_HAS_RANGES && !defined(__MINGW32__)
|
||||
&& !is_compatible_range_view<CompatibleArrayType>::value
|
||||
#endif
|
||||
>>
|
||||
{
|
||||
static constexpr bool value =
|
||||
is_constructible<BasicJsonType,
|
||||
range_value_t<CompatibleArrayType>>::value;
|
||||
};
|
||||
|
||||
#if JSON_HAS_RANGES && !defined(__MINGW32__)
|
||||
template<typename BasicJsonType, typename CompatibleArrayType>
|
||||
struct is_compatible_array_type_impl <
|
||||
BasicJsonType, CompatibleArrayType,
|
||||
enable_if_t < is_compatible_range_view<CompatibleArrayType>::value
|
||||
&& !std::is_same<detected_t<range_value_t, CompatibleArrayType>, char>::value
|
||||
&& !std::is_same<detected_t<range_value_t, CompatibleArrayType>, wchar_t>::value >>
|
||||
{
|
||||
// CompatibleArrayType is a std::ranges::view here, so std::ranges::range_value_t
|
||||
// is safe and correctly handles C++20 iterators that may lack classic iterator_traits.
|
||||
static constexpr bool value =
|
||||
is_constructible<BasicJsonType,
|
||||
std::ranges::range_value_t<CompatibleArrayType>>::value;
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
template<typename BasicJsonType, typename CompatibleArrayType>
|
||||
struct is_compatible_array_type
|
||||
: is_compatible_array_type_impl<BasicJsonType, CompatibleArrayType> {};
|
||||
@@ -6205,8 +6278,11 @@ struct external_constructor<value_t::array>
|
||||
}
|
||||
|
||||
template < typename BasicJsonType, typename CompatibleArrayType,
|
||||
enable_if_t < !std::is_same<CompatibleArrayType, typename BasicJsonType::array_t>::value,
|
||||
int > = 0 >
|
||||
enable_if_t < !std::is_same<CompatibleArrayType, typename BasicJsonType::array_t>::value
|
||||
#if JSON_HAS_RANGES && !defined(__MINGW32__)
|
||||
&& !is_compatible_range_view<CompatibleArrayType>::value
|
||||
#endif
|
||||
, int > = 0 >
|
||||
static void construct(BasicJsonType& j, const CompatibleArrayType& arr)
|
||||
{
|
||||
using std::begin;
|
||||
@@ -6246,6 +6322,25 @@ struct external_constructor<value_t::array>
|
||||
j.set_parents();
|
||||
j.assert_invariant();
|
||||
}
|
||||
|
||||
// std::ranges does not work properly on MinGW due to incomplete C++20 support
|
||||
// see https://github.com/nlohmann/json/issues/4916
|
||||
#if JSON_HAS_RANGES && !defined(__MINGW32__)
|
||||
template<typename BasicJsonType, typename CompatibleArrayType,
|
||||
enable_if_t<is_compatible_range_view<std::remove_cvref_t<CompatibleArrayType>>::value, int> = 0>
|
||||
static void construct(BasicJsonType& j, CompatibleArrayType && arr)
|
||||
{
|
||||
j.m_data.m_value.destroy(j.m_data.m_type);
|
||||
j.m_data.m_type = value_t::array;
|
||||
j.m_data.m_value = value_t::array;
|
||||
for (auto&& x : std::forward<CompatibleArrayType>(arr))
|
||||
{
|
||||
j.m_data.m_value.array->push_back(x);
|
||||
j.set_parent(j.m_data.m_value.array->back());
|
||||
}
|
||||
j.assert_invariant();
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
template<>
|
||||
@@ -6383,13 +6478,29 @@ template < typename BasicJsonType, typename CompatibleArrayType,
|
||||
!is_compatible_object_type<BasicJsonType, CompatibleArrayType>::value&&
|
||||
!is_compatible_string_type<BasicJsonType, CompatibleArrayType>::value&&
|
||||
!std::is_same<typename BasicJsonType::binary_t, CompatibleArrayType>::value&&
|
||||
!is_basic_json<CompatibleArrayType>::value,
|
||||
!is_basic_json<CompatibleArrayType>::value
|
||||
#if JSON_HAS_RANGES && !defined(__MINGW32__)
|
||||
&& !is_compatible_range_view<CompatibleArrayType>::value
|
||||
#endif
|
||||
,
|
||||
int > = 0 >
|
||||
inline void to_json(BasicJsonType& j, const CompatibleArrayType& arr)
|
||||
{
|
||||
external_constructor<value_t::array>::construct(j, arr);
|
||||
}
|
||||
|
||||
#if JSON_HAS_RANGES && !defined(__MINGW32__)
|
||||
template < typename BasicJsonType, typename T,
|
||||
enable_if_t < is_compatible_range_view<std::remove_cvref_t<T>>::value
|
||||
&& !is_compatible_string_type<BasicJsonType, std::remove_cvref_t<T>>::value
|
||||
&& !is_compatible_object_type<BasicJsonType, std::remove_cvref_t<T>>::value
|
||||
&& !is_basic_json<std::remove_cvref_t<T>>::value, int > = 0 >
|
||||
inline void to_json(BasicJsonType& j, T && arr)
|
||||
{
|
||||
external_constructor<value_t::array>::construct(j, std::forward<T>(arr));
|
||||
}
|
||||
#endif
|
||||
|
||||
template<typename BasicJsonType>
|
||||
inline void to_json(BasicJsonType& j, const typename BasicJsonType::binary_t& bin)
|
||||
{
|
||||
|
||||
@@ -1165,6 +1165,46 @@ TEST_CASE("regression tests 2")
|
||||
}
|
||||
#endif
|
||||
|
||||
#if JSON_HAS_RANGES && !defined(__MINGW32__)
|
||||
SECTION("issue #4916 - constructing array from C++20 ranges view does not work")
|
||||
{
|
||||
std::vector<int> nums{1, 2, 37, 42, 21};
|
||||
auto filteredNums = nums | std::views::filter([](int i)
|
||||
{
|
||||
return i > 10;
|
||||
});
|
||||
json const j(filteredNums);
|
||||
CHECK(j.type() == json::value_t::array);
|
||||
CHECK(j == json({37, 42, 21}));
|
||||
}
|
||||
#endif
|
||||
|
||||
// owning_view is not available in libstdc++ < 12
|
||||
#if JSON_HAS_RANGES && !defined(__MINGW32__) && !(defined(__GLIBCXX__) && _GLIBCXX_RELEASE < 12)
|
||||
SECTION("issue #4916 - constructing array from prvalue C++20 ranges view (owning_view)")
|
||||
{
|
||||
json const j(std::vector<int> {1, 2, 37, 42, 21} | std::views::filter([](int i)
|
||||
{
|
||||
return i > 10;
|
||||
}));
|
||||
CHECK(j.type() == json::value_t::array);
|
||||
CHECK(j == json({37, 42, 21}));
|
||||
}
|
||||
#endif
|
||||
|
||||
#if JSON_HAS_RANGES && !defined(__MINGW32__)
|
||||
SECTION("issue #4916 - constructing array from C++20 transform view (prvalue elements)")
|
||||
{
|
||||
std::vector<int> nums{1, 2, 3};
|
||||
auto t = nums | std::views::transform([](int i) noexcept
|
||||
{
|
||||
return i * 2;
|
||||
});
|
||||
json const j(t);
|
||||
CHECK(j.type() == json::value_t::array);
|
||||
CHECK(j == json({2, 4, 6}));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST_CASE_TEMPLATE("issue #4798 - nlohmann::json::to_msgpack() encode float NaN as double", T, double, float) // NOLINT(readability-math-missing-parentheses, bugprone-throwing-static-initialization)
|
||||
|
||||
Reference in New Issue
Block a user