mirror of
https://github.com/nlohmann/json.git
synced 2026-07-12 13:35:13 +00:00
Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 722c03495f | |||
| c197feff81 | |||
| b2b47c69b1 | |||
| 6a406ee141 | |||
| ca76c37650 | |||
| fe2bcc080f | |||
| c60217e801 |
@@ -51,6 +51,38 @@ represent a byte array in modern C++.
|
|||||||
|
|
||||||
The default values for `BinaryType` is `#!cpp std::vector<std::uint8_t>`.
|
The default values for `BinaryType` is `#!cpp std::vector<std::uint8_t>`.
|
||||||
|
|
||||||
|
#### Custom BinaryType behavior
|
||||||
|
|
||||||
|
When a custom `BinaryType` is configured (other than the default `#!cpp std::vector<std::uint8_t>`), you can assign
|
||||||
|
values of that type directly to a `basic_json` instance, and they will automatically be recognized as binary values
|
||||||
|
rather than arrays:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
using custom_json = nlohmann::basic_json<
|
||||||
|
nlohmann::ordered_map, // ObjectType
|
||||||
|
std::vector, // ArrayType
|
||||||
|
std::string, // StringType
|
||||||
|
bool, // BooleanType
|
||||||
|
std::int64_t, // NumberIntegerType
|
||||||
|
std::uint64_t, // NumberUnsignedType
|
||||||
|
double, // NumberFloatType
|
||||||
|
std::allocator, // AllocatorType
|
||||||
|
nlohmann::adl_serializer,
|
||||||
|
std::vector<std::byte> // Custom BinaryType
|
||||||
|
>;
|
||||||
|
|
||||||
|
std::vector<std::byte> data{std::byte{1}, std::byte{2}, std::byte{3}};
|
||||||
|
custom_json j = data; // Creates a binary value, not an array
|
||||||
|
assert(j.is_binary());
|
||||||
|
|
||||||
|
// Round-tripping works seamlessly
|
||||||
|
auto extracted = j.get<std::vector<std::byte>>();
|
||||||
|
assert(extracted == data);
|
||||||
|
```
|
||||||
|
|
||||||
|
This automatic type detection is a convenience feature that only applies to custom (non-default) `BinaryType` configurations.
|
||||||
|
The default `nlohmann::json` continues to treat `#!cpp std::vector<std::uint8_t>` as arrays for backward compatibility.
|
||||||
|
|
||||||
#### Storage
|
#### Storage
|
||||||
|
|
||||||
Binary Arrays are stored as pointers in a `basic_json` type. That is, for any access to array values, a pointer of the
|
Binary Arrays are stored as pointers in a `basic_json` type. That is, for any access to array values, a pointer of the
|
||||||
|
|||||||
@@ -38,7 +38,8 @@ When the macro is not defined, the library will define it to its default value.
|
|||||||
|
|
||||||
Diagnostic messages can also be controlled with the CMake option
|
Diagnostic messages can also be controlled with the CMake option
|
||||||
[`JSON_Diagnostics`](../../integration/cmake.md#json_diagnostics) (`OFF` by default)
|
[`JSON_Diagnostics`](../../integration/cmake.md#json_diagnostics) (`OFF` by default)
|
||||||
which defines `JSON_DIAGNOSTICS` accordingly.
|
which defines `JSON_DIAGNOSTICS` accordingly. Note this only applies when building the
|
||||||
|
library from source — see the pre-installed-package caveat on that page.
|
||||||
|
|
||||||
## Examples
|
## Examples
|
||||||
|
|
||||||
|
|||||||
@@ -47,6 +47,28 @@ json j = {{"one", 1}, {"two", 2}};
|
|||||||
auto m = j.get<std::map<std::string, int>>(); // {{"one", 1}, {"two", 2}}
|
auto m = j.get<std::map<std::string, int>>(); // {{"one", 1}, {"two", 2}}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
`#!cpp std::pair` and `#!cpp std::tuple` are also supported, converting positionally to and from a JSON array:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
json j = {1.0, "hello", 42};
|
||||||
|
auto t = j.get<std::tuple<double, std::string, int>>(); // {1.0, "hello", 42}
|
||||||
|
```
|
||||||
|
|
||||||
|
!!! info "Extracting references into a tuple"
|
||||||
|
|
||||||
|
A tuple type may also hold references (e.g. `#!cpp std::tuple<double&, std::string&>`) to avoid copying: `get`
|
||||||
|
then returns a tuple of references pointing directly at the elements stored inside the `basic_json` array,
|
||||||
|
rather than a tuple of copies:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
json j = {1.0, "hello"};
|
||||||
|
auto refs = j.get<std::tuple<double&, std::string&>>();
|
||||||
|
std::get<1>(refs) = "world"; // modifies j[1] in place
|
||||||
|
```
|
||||||
|
|
||||||
|
A referenced type must be one the library actually stores (or an arithmetic type it can convert to/from);
|
||||||
|
otherwise this is a compile error.
|
||||||
|
|
||||||
## Implicit conversions
|
## Implicit conversions
|
||||||
|
|
||||||
By default, a JSON value implicitly converts to a compatible C++ type, so the explicit `get` call can often be omitted:
|
By default, a JSON value implicitly converts to a compatible C++ type, so the explicit `get` call can often be omitted:
|
||||||
@@ -136,6 +158,20 @@ std::vector<int> numbers = {1, 2, 3};
|
|||||||
json j = numbers; // [1,2,3]
|
json j = numbers; // [1,2,3]
|
||||||
```
|
```
|
||||||
|
|
||||||
|
!!! info "Constructing from a C++20 range view"
|
||||||
|
|
||||||
|
A `json` array can also be constructed directly from a C++20 range view (`std::ranges::view`), such as the result
|
||||||
|
of `std::views::filter` or `std::views::transform` -- no intermediate container is needed:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
std::vector<int> nums{1, 2, 37, 42, 21};
|
||||||
|
auto filtered = nums | std::views::filter([](int i) { return i > 10; });
|
||||||
|
json j(filtered); // [37,42,21]
|
||||||
|
```
|
||||||
|
|
||||||
|
This requires [`JSON_HAS_RANGES`](../api/macros/json_has_ranges.md) to be enabled and is unavailable on MinGW due
|
||||||
|
to incomplete C++20 ranges support there.
|
||||||
|
|
||||||
## Your own types
|
## Your own types
|
||||||
|
|
||||||
The conversions above are built in for standard types. To make the same syntax work for **your own** types, provide
|
The conversions above are built in for standard types. To make the same syntax work for **your own** types, provide
|
||||||
|
|||||||
@@ -135,6 +135,31 @@ Enable CI build targets. The exact targets are used during the several CI steps
|
|||||||
|
|
||||||
Enable [extended diagnostic messages](../home/exceptions.md#extended-diagnostic-messages) by defining macro [`JSON_DIAGNOSTICS`](../api/macros/json_diagnostics.md). This option is `OFF` by default.
|
Enable [extended diagnostic messages](../home/exceptions.md#extended-diagnostic-messages) by defining macro [`JSON_DIAGNOSTICS`](../api/macros/json_diagnostics.md). This option is `OFF` by default.
|
||||||
|
|
||||||
|
!!! warning "Does not apply to a pre-installed package"
|
||||||
|
|
||||||
|
This option only takes effect when building nlohmann/json from source as part of your own
|
||||||
|
CMake project (e.g. via [`FetchContent`](#fetchcontent) or [`add_subdirectory`](#external)).
|
||||||
|
It has **no effect** on a package that was already built and installed elsewhere (Homebrew,
|
||||||
|
vcpkg, a system package, etc.) — the resulting compile definition is baked into the exported
|
||||||
|
`nlohmann_jsonTargets.cmake` at install time, and `set(JSON_Diagnostics ON)` before
|
||||||
|
`find_package()` does not change it (verified against the Homebrew-installed package: the
|
||||||
|
exported target still carries a fixed `$<$<BOOL:OFF>:JSON_DIAGNOSTICS=1>`, regardless of any
|
||||||
|
variable set in the consuming project).
|
||||||
|
|
||||||
|
To enable extended diagnostics for a pre-installed package, override the imported target's
|
||||||
|
property directly after `find_package()`:
|
||||||
|
|
||||||
|
```cmake
|
||||||
|
find_package(nlohmann_json REQUIRED)
|
||||||
|
set_target_properties(nlohmann_json::nlohmann_json PROPERTIES
|
||||||
|
INTERFACE_COMPILE_DEFINITIONS "JSON_DIAGNOSTICS=1")
|
||||||
|
```
|
||||||
|
|
||||||
|
This only works cleanly when your project is the sole consumer of that imported target. If
|
||||||
|
nlohmann_json is pulled in from more than one place in your dependency graph with different
|
||||||
|
`JSON_DIAGNOSTICS` values, you may see a `"JSON_DIAGNOSTICS" redefined` compiler error, since
|
||||||
|
conflicting `-D` flags can end up on the same compile command line.
|
||||||
|
|
||||||
### `JSON_Diagnostic_Positions`
|
### `JSON_Diagnostic_Positions`
|
||||||
|
|
||||||
Enable position diagnostics by defining macro [`JSON_DIAGNOSTIC_POSITIONS`](../api/macros/json_diagnostic_positions.md). This option is `OFF` by default.
|
Enable position diagnostics by defining macro [`JSON_DIAGNOSTIC_POSITIONS`](../api/macros/json_diagnostic_positions.md). This option is `OFF` by default.
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
#include <unordered_map> // unordered_map
|
#include <unordered_map> // unordered_map
|
||||||
#include <utility> // pair, declval
|
#include <utility> // pair, declval
|
||||||
#include <valarray> // valarray
|
#include <valarray> // valarray
|
||||||
|
#include <vector> // vector
|
||||||
|
|
||||||
#include <nlohmann/detail/exceptions.hpp>
|
#include <nlohmann/detail/exceptions.hpp>
|
||||||
#include <nlohmann/detail/macro_scope.hpp>
|
#include <nlohmann/detail/macro_scope.hpp>
|
||||||
@@ -332,6 +333,7 @@ template < typename BasicJsonType, typename ConstructibleArrayType,
|
|||||||
!is_constructible_object_type<BasicJsonType, ConstructibleArrayType>::value&&
|
!is_constructible_object_type<BasicJsonType, ConstructibleArrayType>::value&&
|
||||||
!is_constructible_string_type<BasicJsonType, ConstructibleArrayType>::value&&
|
!is_constructible_string_type<BasicJsonType, ConstructibleArrayType>::value&&
|
||||||
!std::is_same<ConstructibleArrayType, typename BasicJsonType::binary_t>::value&&
|
!std::is_same<ConstructibleArrayType, typename BasicJsonType::binary_t>::value&&
|
||||||
|
!is_compatible_binary_type<BasicJsonType, ConstructibleArrayType>::value&&
|
||||||
!is_basic_json<ConstructibleArrayType>::value,
|
!is_basic_json<ConstructibleArrayType>::value,
|
||||||
int > = 0 >
|
int > = 0 >
|
||||||
auto from_json(const BasicJsonType& j, ConstructibleArrayType& arr)
|
auto from_json(const BasicJsonType& j, ConstructibleArrayType& arr)
|
||||||
@@ -377,6 +379,25 @@ inline void from_json(const BasicJsonType& j, typename BasicJsonType::binary_t&
|
|||||||
bin = *j.template get_ptr<const typename BasicJsonType::binary_t*>();
|
bin = *j.template get_ptr<const typename BasicJsonType::binary_t*>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template < typename BasicJsonType, typename CompatibleArrayType,
|
||||||
|
enable_if_t < is_compatible_binary_type<BasicJsonType, CompatibleArrayType>::value,
|
||||||
|
int > = 0 >
|
||||||
|
inline void from_json(const BasicJsonType& j, CompatibleArrayType& bin)
|
||||||
|
{
|
||||||
|
if (j.is_binary())
|
||||||
|
{
|
||||||
|
bin = static_cast<CompatibleArrayType>(*j.template get_ptr<const typename BasicJsonType::binary_t*>());
|
||||||
|
}
|
||||||
|
else if (j.is_array())
|
||||||
|
{
|
||||||
|
from_json_array_impl(j, bin, priority_tag<3> {});
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
JSON_THROW(type_error::create(302, concat("type must be binary or array, but is ", j.type_name()), &j));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
template<typename BasicJsonType, typename ConstructibleObjectType,
|
template<typename BasicJsonType, typename ConstructibleObjectType,
|
||||||
enable_if_t<is_constructible_object_type<BasicJsonType, ConstructibleObjectType>::value, int> = 0>
|
enable_if_t<is_constructible_object_type<BasicJsonType, ConstructibleObjectType>::value, int> = 0>
|
||||||
inline void from_json(const BasicJsonType& j, ConstructibleObjectType& obj)
|
inline void from_json(const BasicJsonType& j, ConstructibleObjectType& obj)
|
||||||
|
|||||||
@@ -177,8 +177,11 @@ struct external_constructor<value_t::array>
|
|||||||
}
|
}
|
||||||
|
|
||||||
template < typename BasicJsonType, typename CompatibleArrayType,
|
template < typename BasicJsonType, typename CompatibleArrayType,
|
||||||
enable_if_t < !std::is_same<CompatibleArrayType, typename BasicJsonType::array_t>::value,
|
enable_if_t < !std::is_same<CompatibleArrayType, typename BasicJsonType::array_t>::value
|
||||||
int > = 0 >
|
#if JSON_HAS_RANGES && !defined(__MINGW32__)
|
||||||
|
&& !is_compatible_range_view<CompatibleArrayType>::value
|
||||||
|
#endif
|
||||||
|
, int > = 0 >
|
||||||
static void construct(BasicJsonType& j, const CompatibleArrayType& arr)
|
static void construct(BasicJsonType& j, const CompatibleArrayType& arr)
|
||||||
{
|
{
|
||||||
using std::begin;
|
using std::begin;
|
||||||
@@ -218,6 +221,25 @@ struct external_constructor<value_t::array>
|
|||||||
j.set_parents();
|
j.set_parents();
|
||||||
j.assert_invariant();
|
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<>
|
template<>
|
||||||
@@ -355,19 +377,44 @@ template < typename BasicJsonType, typename CompatibleArrayType,
|
|||||||
!is_compatible_object_type<BasicJsonType, CompatibleArrayType>::value&&
|
!is_compatible_object_type<BasicJsonType, CompatibleArrayType>::value&&
|
||||||
!is_compatible_string_type<BasicJsonType, CompatibleArrayType>::value&&
|
!is_compatible_string_type<BasicJsonType, CompatibleArrayType>::value&&
|
||||||
!std::is_same<typename BasicJsonType::binary_t, CompatibleArrayType>::value&&
|
!std::is_same<typename BasicJsonType::binary_t, CompatibleArrayType>::value&&
|
||||||
!is_basic_json<CompatibleArrayType>::value,
|
!is_compatible_binary_type<BasicJsonType, CompatibleArrayType>::value&&
|
||||||
|
!is_basic_json<CompatibleArrayType>::value
|
||||||
|
#if JSON_HAS_RANGES && !defined(__MINGW32__)
|
||||||
|
&& !is_compatible_range_view<CompatibleArrayType>::value
|
||||||
|
#endif
|
||||||
|
,
|
||||||
int > = 0 >
|
int > = 0 >
|
||||||
inline void to_json(BasicJsonType& j, const CompatibleArrayType& arr)
|
inline void to_json(BasicJsonType& j, const CompatibleArrayType& arr)
|
||||||
{
|
{
|
||||||
external_constructor<value_t::array>::construct(j, 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>
|
template<typename BasicJsonType>
|
||||||
inline void to_json(BasicJsonType& j, const typename BasicJsonType::binary_t& bin)
|
inline void to_json(BasicJsonType& j, const typename BasicJsonType::binary_t& bin)
|
||||||
{
|
{
|
||||||
external_constructor<value_t::binary>::construct(j, bin);
|
external_constructor<value_t::binary>::construct(j, bin);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template < typename BasicJsonType, typename CompatibleArrayType,
|
||||||
|
enable_if_t < is_compatible_binary_type<BasicJsonType, CompatibleArrayType>::value,
|
||||||
|
int > = 0 >
|
||||||
|
inline void to_json(BasicJsonType& j, const CompatibleArrayType& bin)
|
||||||
|
{
|
||||||
|
external_constructor<value_t::binary>::construct(j, typename BasicJsonType::binary_t(bin));
|
||||||
|
}
|
||||||
|
|
||||||
template<typename BasicJsonType, typename T,
|
template<typename BasicJsonType, typename T,
|
||||||
enable_if_t<std::is_convertible<T, BasicJsonType>::value, int> = 0>
|
enable_if_t<std::is_convertible<T, BasicJsonType>::value, int> = 0>
|
||||||
inline void to_json(BasicJsonType& j, const std::valarray<T>& arr)
|
inline void to_json(BasicJsonType& j, const std::valarray<T>& arr)
|
||||||
|
|||||||
@@ -13,11 +13,15 @@
|
|||||||
#include <tuple> // tuple
|
#include <tuple> // tuple
|
||||||
#include <type_traits> // false_type, is_constructible, is_integral, is_same, true_type
|
#include <type_traits> // false_type, is_constructible, is_integral, is_same, true_type
|
||||||
#include <utility> // declval
|
#include <utility> // declval
|
||||||
|
#include <vector> // vector
|
||||||
#if defined(__cpp_lib_byte) && __cpp_lib_byte >= 201603L
|
#if defined(__cpp_lib_byte) && __cpp_lib_byte >= 201603L
|
||||||
#include <cstddef> // byte
|
#include <cstddef> // byte
|
||||||
#endif
|
#endif
|
||||||
#include <nlohmann/detail/iterators/iterator_traits.hpp>
|
#include <nlohmann/detail/iterators/iterator_traits.hpp>
|
||||||
#include <nlohmann/detail/macro_scope.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/begin.hpp>
|
||||||
#include <nlohmann/detail/meta/call_std/end.hpp>
|
#include <nlohmann/detail/meta/call_std/end.hpp>
|
||||||
#include <nlohmann/detail/meta/cpp_future.hpp>
|
#include <nlohmann/detail/meta/cpp_future.hpp>
|
||||||
@@ -450,6 +454,51 @@ struct is_constructible_string_type
|
|||||||
value_type_t, laundered_type >>::value;
|
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>
|
template<typename BasicJsonType, typename CompatibleArrayType, typename = void>
|
||||||
struct is_compatible_array_type_impl : std::false_type {};
|
struct is_compatible_array_type_impl : std::false_type {};
|
||||||
|
|
||||||
@@ -461,13 +510,38 @@ struct is_compatible_array_type_impl <
|
|||||||
is_iterator_traits<iterator_traits<detected_t<iterator_t, CompatibleArrayType>>>::value&&
|
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
|
// special case for types like std::filesystem::path whose iterator's value_type are themselves
|
||||||
// c.f. https://github.com/nlohmann/json/pull/3073
|
// 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 =
|
static constexpr bool value =
|
||||||
is_constructible<BasicJsonType,
|
is_constructible<BasicJsonType,
|
||||||
range_value_t<CompatibleArrayType>>::value;
|
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>
|
template<typename BasicJsonType, typename CompatibleArrayType>
|
||||||
struct is_compatible_array_type
|
struct is_compatible_array_type
|
||||||
: is_compatible_array_type_impl<BasicJsonType, CompatibleArrayType> {};
|
: is_compatible_array_type_impl<BasicJsonType, CompatibleArrayType> {};
|
||||||
@@ -559,6 +633,14 @@ template<typename BasicJsonType, typename CompatibleType>
|
|||||||
struct is_compatible_type
|
struct is_compatible_type
|
||||||
: is_compatible_type_impl<BasicJsonType, CompatibleType> {};
|
: is_compatible_type_impl<BasicJsonType, CompatibleType> {};
|
||||||
|
|
||||||
|
template<typename BasicJsonType, typename CompatibleArrayType>
|
||||||
|
struct is_compatible_binary_type
|
||||||
|
{
|
||||||
|
static constexpr bool value =
|
||||||
|
std::is_same<typename BasicJsonType::binary_t::container_type, CompatibleArrayType>::value &&
|
||||||
|
!std::is_same<typename BasicJsonType::binary_t::container_type, std::vector<std::uint8_t>>::value;
|
||||||
|
};
|
||||||
|
|
||||||
template<typename BasicJsonType, typename CompatibleReferenceType>
|
template<typename BasicJsonType, typename CompatibleReferenceType>
|
||||||
struct is_compatible_reference_type_impl
|
struct is_compatible_reference_type_impl
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -189,6 +189,7 @@
|
|||||||
#include <unordered_map> // unordered_map
|
#include <unordered_map> // unordered_map
|
||||||
#include <utility> // pair, declval
|
#include <utility> // pair, declval
|
||||||
#include <valarray> // valarray
|
#include <valarray> // valarray
|
||||||
|
#include <vector> // vector
|
||||||
|
|
||||||
// #include <nlohmann/detail/exceptions.hpp>
|
// #include <nlohmann/detail/exceptions.hpp>
|
||||||
// __ _____ _____ _____
|
// __ _____ _____ _____
|
||||||
@@ -3592,6 +3593,7 @@ NLOHMANN_JSON_NAMESPACE_END
|
|||||||
#include <tuple> // tuple
|
#include <tuple> // tuple
|
||||||
#include <type_traits> // false_type, is_constructible, is_integral, is_same, true_type
|
#include <type_traits> // false_type, is_constructible, is_integral, is_same, true_type
|
||||||
#include <utility> // declval
|
#include <utility> // declval
|
||||||
|
#include <vector> // vector
|
||||||
#if defined(__cpp_lib_byte) && __cpp_lib_byte >= 201603L
|
#if defined(__cpp_lib_byte) && __cpp_lib_byte >= 201603L
|
||||||
#include <cstddef> // byte
|
#include <cstddef> // byte
|
||||||
#endif
|
#endif
|
||||||
@@ -3663,6 +3665,9 @@ NLOHMANN_JSON_NAMESPACE_END
|
|||||||
|
|
||||||
// #include <nlohmann/detail/macro_scope.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/begin.hpp>
|
||||||
// __ _____ _____ _____
|
// __ _____ _____ _____
|
||||||
// __| | __| | | | JSON for Modern C++
|
// __| | __| | | | JSON for Modern C++
|
||||||
@@ -4212,6 +4217,51 @@ struct is_constructible_string_type
|
|||||||
value_type_t, laundered_type >>::value;
|
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>
|
template<typename BasicJsonType, typename CompatibleArrayType, typename = void>
|
||||||
struct is_compatible_array_type_impl : std::false_type {};
|
struct is_compatible_array_type_impl : std::false_type {};
|
||||||
|
|
||||||
@@ -4223,13 +4273,38 @@ struct is_compatible_array_type_impl <
|
|||||||
is_iterator_traits<iterator_traits<detected_t<iterator_t, CompatibleArrayType>>>::value&&
|
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
|
// special case for types like std::filesystem::path whose iterator's value_type are themselves
|
||||||
// c.f. https://github.com/nlohmann/json/pull/3073
|
// 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 =
|
static constexpr bool value =
|
||||||
is_constructible<BasicJsonType,
|
is_constructible<BasicJsonType,
|
||||||
range_value_t<CompatibleArrayType>>::value;
|
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>
|
template<typename BasicJsonType, typename CompatibleArrayType>
|
||||||
struct is_compatible_array_type
|
struct is_compatible_array_type
|
||||||
: is_compatible_array_type_impl<BasicJsonType, CompatibleArrayType> {};
|
: is_compatible_array_type_impl<BasicJsonType, CompatibleArrayType> {};
|
||||||
@@ -4321,6 +4396,14 @@ template<typename BasicJsonType, typename CompatibleType>
|
|||||||
struct is_compatible_type
|
struct is_compatible_type
|
||||||
: is_compatible_type_impl<BasicJsonType, CompatibleType> {};
|
: is_compatible_type_impl<BasicJsonType, CompatibleType> {};
|
||||||
|
|
||||||
|
template<typename BasicJsonType, typename CompatibleArrayType>
|
||||||
|
struct is_compatible_binary_type
|
||||||
|
{
|
||||||
|
static constexpr bool value =
|
||||||
|
std::is_same<typename BasicJsonType::binary_t::container_type, CompatibleArrayType>::value &&
|
||||||
|
!std::is_same<typename BasicJsonType::binary_t::container_type, std::vector<std::uint8_t>>::value;
|
||||||
|
};
|
||||||
|
|
||||||
template<typename BasicJsonType, typename CompatibleReferenceType>
|
template<typename BasicJsonType, typename CompatibleReferenceType>
|
||||||
struct is_compatible_reference_type_impl
|
struct is_compatible_reference_type_impl
|
||||||
{
|
{
|
||||||
@@ -5464,6 +5547,7 @@ template < typename BasicJsonType, typename ConstructibleArrayType,
|
|||||||
!is_constructible_object_type<BasicJsonType, ConstructibleArrayType>::value&&
|
!is_constructible_object_type<BasicJsonType, ConstructibleArrayType>::value&&
|
||||||
!is_constructible_string_type<BasicJsonType, ConstructibleArrayType>::value&&
|
!is_constructible_string_type<BasicJsonType, ConstructibleArrayType>::value&&
|
||||||
!std::is_same<ConstructibleArrayType, typename BasicJsonType::binary_t>::value&&
|
!std::is_same<ConstructibleArrayType, typename BasicJsonType::binary_t>::value&&
|
||||||
|
!is_compatible_binary_type<BasicJsonType, ConstructibleArrayType>::value&&
|
||||||
!is_basic_json<ConstructibleArrayType>::value,
|
!is_basic_json<ConstructibleArrayType>::value,
|
||||||
int > = 0 >
|
int > = 0 >
|
||||||
auto from_json(const BasicJsonType& j, ConstructibleArrayType& arr)
|
auto from_json(const BasicJsonType& j, ConstructibleArrayType& arr)
|
||||||
@@ -5509,6 +5593,25 @@ inline void from_json(const BasicJsonType& j, typename BasicJsonType::binary_t&
|
|||||||
bin = *j.template get_ptr<const typename BasicJsonType::binary_t*>();
|
bin = *j.template get_ptr<const typename BasicJsonType::binary_t*>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template < typename BasicJsonType, typename CompatibleArrayType,
|
||||||
|
enable_if_t < is_compatible_binary_type<BasicJsonType, CompatibleArrayType>::value,
|
||||||
|
int > = 0 >
|
||||||
|
inline void from_json(const BasicJsonType& j, CompatibleArrayType& bin)
|
||||||
|
{
|
||||||
|
if (j.is_binary())
|
||||||
|
{
|
||||||
|
bin = static_cast<CompatibleArrayType>(*j.template get_ptr<const typename BasicJsonType::binary_t*>());
|
||||||
|
}
|
||||||
|
else if (j.is_array())
|
||||||
|
{
|
||||||
|
from_json_array_impl(j, bin, priority_tag<3> {});
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
JSON_THROW(type_error::create(302, concat("type must be binary or array, but is ", j.type_name()), &j));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
template<typename BasicJsonType, typename ConstructibleObjectType,
|
template<typename BasicJsonType, typename ConstructibleObjectType,
|
||||||
enable_if_t<is_constructible_object_type<BasicJsonType, ConstructibleObjectType>::value, int> = 0>
|
enable_if_t<is_constructible_object_type<BasicJsonType, ConstructibleObjectType>::value, int> = 0>
|
||||||
inline void from_json(const BasicJsonType& j, ConstructibleObjectType& obj)
|
inline void from_json(const BasicJsonType& j, ConstructibleObjectType& obj)
|
||||||
@@ -6205,8 +6308,11 @@ struct external_constructor<value_t::array>
|
|||||||
}
|
}
|
||||||
|
|
||||||
template < typename BasicJsonType, typename CompatibleArrayType,
|
template < typename BasicJsonType, typename CompatibleArrayType,
|
||||||
enable_if_t < !std::is_same<CompatibleArrayType, typename BasicJsonType::array_t>::value,
|
enable_if_t < !std::is_same<CompatibleArrayType, typename BasicJsonType::array_t>::value
|
||||||
int > = 0 >
|
#if JSON_HAS_RANGES && !defined(__MINGW32__)
|
||||||
|
&& !is_compatible_range_view<CompatibleArrayType>::value
|
||||||
|
#endif
|
||||||
|
, int > = 0 >
|
||||||
static void construct(BasicJsonType& j, const CompatibleArrayType& arr)
|
static void construct(BasicJsonType& j, const CompatibleArrayType& arr)
|
||||||
{
|
{
|
||||||
using std::begin;
|
using std::begin;
|
||||||
@@ -6246,6 +6352,25 @@ struct external_constructor<value_t::array>
|
|||||||
j.set_parents();
|
j.set_parents();
|
||||||
j.assert_invariant();
|
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<>
|
template<>
|
||||||
@@ -6383,19 +6508,44 @@ template < typename BasicJsonType, typename CompatibleArrayType,
|
|||||||
!is_compatible_object_type<BasicJsonType, CompatibleArrayType>::value&&
|
!is_compatible_object_type<BasicJsonType, CompatibleArrayType>::value&&
|
||||||
!is_compatible_string_type<BasicJsonType, CompatibleArrayType>::value&&
|
!is_compatible_string_type<BasicJsonType, CompatibleArrayType>::value&&
|
||||||
!std::is_same<typename BasicJsonType::binary_t, CompatibleArrayType>::value&&
|
!std::is_same<typename BasicJsonType::binary_t, CompatibleArrayType>::value&&
|
||||||
!is_basic_json<CompatibleArrayType>::value,
|
!is_compatible_binary_type<BasicJsonType, CompatibleArrayType>::value&&
|
||||||
|
!is_basic_json<CompatibleArrayType>::value
|
||||||
|
#if JSON_HAS_RANGES && !defined(__MINGW32__)
|
||||||
|
&& !is_compatible_range_view<CompatibleArrayType>::value
|
||||||
|
#endif
|
||||||
|
,
|
||||||
int > = 0 >
|
int > = 0 >
|
||||||
inline void to_json(BasicJsonType& j, const CompatibleArrayType& arr)
|
inline void to_json(BasicJsonType& j, const CompatibleArrayType& arr)
|
||||||
{
|
{
|
||||||
external_constructor<value_t::array>::construct(j, 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>
|
template<typename BasicJsonType>
|
||||||
inline void to_json(BasicJsonType& j, const typename BasicJsonType::binary_t& bin)
|
inline void to_json(BasicJsonType& j, const typename BasicJsonType::binary_t& bin)
|
||||||
{
|
{
|
||||||
external_constructor<value_t::binary>::construct(j, bin);
|
external_constructor<value_t::binary>::construct(j, bin);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template < typename BasicJsonType, typename CompatibleArrayType,
|
||||||
|
enable_if_t < is_compatible_binary_type<BasicJsonType, CompatibleArrayType>::value,
|
||||||
|
int > = 0 >
|
||||||
|
inline void to_json(BasicJsonType& j, const CompatibleArrayType& bin)
|
||||||
|
{
|
||||||
|
external_constructor<value_t::binary>::construct(j, typename BasicJsonType::binary_t(bin));
|
||||||
|
}
|
||||||
|
|
||||||
template<typename BasicJsonType, typename T,
|
template<typename BasicJsonType, typename T,
|
||||||
enable_if_t<std::is_convertible<T, BasicJsonType>::value, int> = 0>
|
enable_if_t<std::is_convertible<T, BasicJsonType>::value, int> = 0>
|
||||||
inline void to_json(BasicJsonType& j, const std::valarray<T>& arr)
|
inline void to_json(BasicJsonType& j, const std::valarray<T>& arr)
|
||||||
|
|||||||
@@ -1782,6 +1782,21 @@ TEST_CASE("std::optional")
|
|||||||
"[json.exception.type_error.302] type must be string, but is null", json::type_error&);
|
"[json.exception.type_error.302] type must be string, but is null", json::type_error&);
|
||||||
CHECK_THROWS_WITH_AS(std::optional<int>(j_null),
|
CHECK_THROWS_WITH_AS(std::optional<int>(j_null),
|
||||||
"[json.exception.type_error.302] type must be number, but is null", json::type_error&);
|
"[json.exception.type_error.302] type must be number, but is null", json::type_error&);
|
||||||
|
|
||||||
|
// Assignment goes through the same overload resolution as direct
|
||||||
|
// construction, so it throws for the same reason. This relies on
|
||||||
|
// basic_json's implicit conversion operator, so it only applies
|
||||||
|
// when JSON_USE_IMPLICIT_CONVERSIONS is enabled (the default).
|
||||||
|
#if JSON_USE_IMPLICIT_CONVERSIONS
|
||||||
|
std::optional<std::string> opt_assign;
|
||||||
|
CHECK_THROWS_WITH_AS(opt_assign = j_null,
|
||||||
|
"[json.exception.type_error.302] type must be string, but is null", json::type_error&);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// get_to() is the correct way to obtain std::nullopt from a JSON null.
|
||||||
|
std::optional<std::string> opt_get_to = "placeholder";
|
||||||
|
j_null.get_to(opt_get_to);
|
||||||
|
CHECK(opt_get_to == std::nullopt);
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("string")
|
SECTION("string")
|
||||||
|
|||||||
@@ -1136,6 +1136,40 @@ TEST_CASE("regression tests 2")
|
|||||||
CHECK((decoded == json_4804::array()));
|
CHECK((decoded == json_4804::array()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SECTION("discussion #4209 - custom BinaryType direct assignment and round-tripping")
|
||||||
|
{
|
||||||
|
// Test that assigning a custom BinaryType directly creates a binary value, not an array
|
||||||
|
const std::vector<std::byte> original{std::byte{1}, std::byte{2}, std::byte{3}};
|
||||||
|
const json_4804 j = original;
|
||||||
|
CHECK(j.is_binary());
|
||||||
|
CHECK(!j.is_array());
|
||||||
|
|
||||||
|
// Test round-tripping: extracting the binary value back as the custom container type
|
||||||
|
const auto extracted = j.get<std::vector<std::byte>>();
|
||||||
|
CHECK(extracted == original);
|
||||||
|
|
||||||
|
// Test that the default json alias behavior is unchanged: std::vector<uint8_t> -> array
|
||||||
|
const json default_json = std::vector<std::uint8_t> {1, 2, 3};
|
||||||
|
CHECK(default_json.is_array());
|
||||||
|
CHECK(!default_json.is_binary());
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("discussion #4209 - custom BinaryType extraction from parsed array")
|
||||||
|
{
|
||||||
|
// Test that extracting a custom BinaryType from a parsed JSON array still works
|
||||||
|
// (not just from a binary-typed node)
|
||||||
|
const auto j = json_4804::parse("[1,2,3]");
|
||||||
|
CHECK(j.is_array());
|
||||||
|
CHECK(!j.is_binary());
|
||||||
|
|
||||||
|
// Extracting as custom BinaryType should work from arrays
|
||||||
|
const auto extracted = j.get<std::vector<std::byte>>();
|
||||||
|
CHECK(extracted.size() == 3);
|
||||||
|
CHECK(extracted[0] == std::byte{1});
|
||||||
|
CHECK(extracted[1] == std::byte{2});
|
||||||
|
CHECK(extracted[2] == std::byte{3});
|
||||||
|
}
|
||||||
|
|
||||||
SECTION("issue #5046 - implicit conversion of return json to std::optional no longer implicit")
|
SECTION("issue #5046 - implicit conversion of return json to std::optional no longer implicit")
|
||||||
{
|
{
|
||||||
const json jval{};
|
const json jval{};
|
||||||
@@ -1165,6 +1199,46 @@ TEST_CASE("regression tests 2")
|
|||||||
}
|
}
|
||||||
#endif
|
#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)
|
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)
|
||||||
|
|||||||
@@ -216,15 +216,16 @@ TEST_CASE("Parse with heterogeneous iterator and sentinel types")
|
|||||||
// JSON_HAS_CPP_20 (do not remove; see note at top of file)
|
// JSON_HAS_CPP_20 (do not remove; see note at top of file)
|
||||||
TEST_CASE("Parse with std::counted_iterator and std::default_sentinel_t")
|
TEST_CASE("Parse with std::counted_iterator and std::default_sentinel_t")
|
||||||
{
|
{
|
||||||
|
using iterator_type = std::string::const_iterator;
|
||||||
const std::string json_str = R"({"key":"value","array":[1,2,3]})";
|
const std::string json_str = R"({"key":"value","array":[1,2,3]})";
|
||||||
const auto len = static_cast<std::iter_difference_t<std::string::const_iterator>>(json_str.size());
|
const auto len = static_cast<std::iter_difference_t<iterator_type>>(json_str.size());
|
||||||
|
|
||||||
std::counted_iterator first(json_str.begin(), len);
|
const std::counted_iterator<iterator_type> first(json_str.begin(), len);
|
||||||
const json j = json::parse(first, std::default_sentinel);
|
const json j = json::parse(first, std::default_sentinel);
|
||||||
CHECK(j["key"] == "value");
|
CHECK(j["key"] == "value");
|
||||||
CHECK(j["array"].size() == 3);
|
CHECK(j["array"].size() == 3);
|
||||||
|
|
||||||
std::counted_iterator first2(json_str.begin(), len);
|
const std::counted_iterator<iterator_type> first2(json_str.begin(), len);
|
||||||
CHECK(json::accept(first2, std::default_sentinel));
|
CHECK(json::accept(first2, std::default_sentinel));
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
Reference in New Issue
Block a user