mirror of
https://github.com/nlohmann/json.git
synced 2026-07-12 05:25:09 +00:00
Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 0e03ecee10 | |||
| d23806a327 | |||
| fa9741f0ce | |||
| da95d1184e | |||
| 146e5e0bc7 | |||
| 2269656bc6 |
@@ -49,7 +49,7 @@ Unlike the [`parse()`](parse.md) function, this function neither throws an excep
|
|||||||
: defaults to `IteratorType`; may be a different type comparable to `IteratorType` via `operator!=`, for instance.
|
: defaults to `IteratorType`; may be a different type comparable to `IteratorType` via `operator!=`, for instance.
|
||||||
|
|
||||||
- a custom sentinel type for C++20 ranges
|
- a custom sentinel type for C++20 ranges
|
||||||
- `std::counted_iterator` with a different sentinel type
|
- `std::default_sentinel_t`, when `IteratorType` is `std::counted_iterator`
|
||||||
|
|
||||||
## Parameters
|
## Parameters
|
||||||
|
|
||||||
|
|||||||
@@ -51,38 +51,6 @@ 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
|
||||||
|
|||||||
@@ -36,8 +36,10 @@ The exact mapping and its limitations are described on a [dedicated page](../../
|
|||||||
: a compatible iterator type
|
: a compatible iterator type
|
||||||
|
|
||||||
`SentinelType`
|
`SentinelType`
|
||||||
: defaults to `IteratorType`; may be a different type comparable to `IteratorType` via `operator!=`, for instance a
|
: defaults to `IteratorType`; may be a different type comparable to `IteratorType` via `operator!=`, for instance.
|
||||||
custom sentinel type for C++20 ranges
|
|
||||||
|
- a custom sentinel type for C++20 ranges
|
||||||
|
- `std::default_sentinel_t`, when `IteratorType` is `std::counted_iterator`
|
||||||
|
|
||||||
## Parameters
|
## Parameters
|
||||||
|
|
||||||
|
|||||||
@@ -36,8 +36,10 @@ The exact mapping and its limitations are described on a [dedicated page](../../
|
|||||||
: a compatible iterator type
|
: a compatible iterator type
|
||||||
|
|
||||||
`SentinelType`
|
`SentinelType`
|
||||||
: defaults to `IteratorType`; may be a different type comparable to `IteratorType` via `operator!=`, for instance a
|
: defaults to `IteratorType`; may be a different type comparable to `IteratorType` via `operator!=`, for instance.
|
||||||
custom sentinel type for C++20 ranges
|
|
||||||
|
- a custom sentinel type for C++20 ranges
|
||||||
|
- `std::default_sentinel_t`, when `IteratorType` is `std::counted_iterator`
|
||||||
|
|
||||||
## Parameters
|
## Parameters
|
||||||
|
|
||||||
|
|||||||
@@ -39,8 +39,10 @@ The exact mapping and its limitations are described on a [dedicated page](../../
|
|||||||
: a compatible iterator type
|
: a compatible iterator type
|
||||||
|
|
||||||
`SentinelType`
|
`SentinelType`
|
||||||
: defaults to `IteratorType`; may be a different type comparable to `IteratorType` via `operator!=`, for instance a
|
: defaults to `IteratorType`; may be a different type comparable to `IteratorType` via `operator!=`, for instance.
|
||||||
custom sentinel type for C++20 ranges
|
|
||||||
|
- a custom sentinel type for C++20 ranges
|
||||||
|
- `std::default_sentinel_t`, when `IteratorType` is `std::counted_iterator`
|
||||||
|
|
||||||
## Parameters
|
## Parameters
|
||||||
|
|
||||||
|
|||||||
@@ -36,8 +36,10 @@ The exact mapping and its limitations are described on a [dedicated page](../../
|
|||||||
: a compatible iterator type
|
: a compatible iterator type
|
||||||
|
|
||||||
`SentinelType`
|
`SentinelType`
|
||||||
: defaults to `IteratorType`; may be a different type comparable to `IteratorType` via `operator!=`, for instance a
|
: defaults to `IteratorType`; may be a different type comparable to `IteratorType` via `operator!=`, for instance.
|
||||||
custom sentinel type for C++20 ranges
|
|
||||||
|
- a custom sentinel type for C++20 ranges
|
||||||
|
- `std::default_sentinel_t`, when `IteratorType` is `std::counted_iterator`
|
||||||
|
|
||||||
## Parameters
|
## Parameters
|
||||||
|
|
||||||
|
|||||||
@@ -36,8 +36,10 @@ The exact mapping and its limitations are described on a [dedicated page](../../
|
|||||||
: a compatible iterator type
|
: a compatible iterator type
|
||||||
|
|
||||||
`SentinelType`
|
`SentinelType`
|
||||||
: defaults to `IteratorType`; may be a different type comparable to `IteratorType` via `operator!=`, for instance a
|
: defaults to `IteratorType`; may be a different type comparable to `IteratorType` via `operator!=`, for instance.
|
||||||
custom sentinel type for C++20 ranges
|
|
||||||
|
- a custom sentinel type for C++20 ranges
|
||||||
|
- `std::default_sentinel_t`, when `IteratorType` is `std::counted_iterator`
|
||||||
|
|
||||||
## Parameters
|
## Parameters
|
||||||
|
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ static basic_json parse(IteratorType first, SentinelType last,
|
|||||||
: defaults to `IteratorType`; may be a different type comparable to `IteratorType` via `operator!=`, for instance.
|
: defaults to `IteratorType`; may be a different type comparable to `IteratorType` via `operator!=`, for instance.
|
||||||
|
|
||||||
- a custom sentinel type for C++20 ranges
|
- a custom sentinel type for C++20 ranges
|
||||||
- `std::counted_iterator` with a different sentinel type
|
- `std::default_sentinel_t`, when `IteratorType` is `std::counted_iterator`
|
||||||
|
|
||||||
## Parameters
|
## Parameters
|
||||||
|
|
||||||
|
|||||||
@@ -48,7 +48,10 @@ The SAX event lister must follow the interface of [`json_sax`](../json_sax/index
|
|||||||
with a size of 1, 2, or 4 bytes (interpreted respectively as UTF-8, UTF-16, and UTF-32)
|
with a size of 1, 2, or 4 bytes (interpreted respectively as UTF-8, UTF-16, and UTF-32)
|
||||||
|
|
||||||
`SentinelType`
|
`SentinelType`
|
||||||
: defaults to `IteratorType`; may be a different type comparable to `IteratorType` via `operator!=`, for overload (2)
|
: defaults to `IteratorType`; may be a different type comparable to `IteratorType` via `operator!=`, for overload (2), for instance.
|
||||||
|
|
||||||
|
- a custom sentinel type for C++20 ranges
|
||||||
|
- `std::default_sentinel_t`, when `IteratorType` is `std::counted_iterator`
|
||||||
|
|
||||||
`SAX`
|
`SAX`
|
||||||
: a class fulfilling the SAX event listener interface; see [`json_sax`](../json_sax/index.md)
|
: a class fulfilling the SAX event listener interface; see [`json_sax`](../json_sax/index.md)
|
||||||
|
|||||||
@@ -38,8 +38,7 @@ 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. Note this only applies when building the
|
which defines `JSON_DIAGNOSTICS` accordingly.
|
||||||
library from source — see the pre-installed-package caveat on that page.
|
|
||||||
|
|
||||||
## Examples
|
## Examples
|
||||||
|
|
||||||
|
|||||||
@@ -47,28 +47,6 @@ 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:
|
||||||
@@ -158,20 +136,6 @@ 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,31 +135,6 @@ 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,7 +19,6 @@
|
|||||||
#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>
|
||||||
@@ -333,7 +332,6 @@ 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)
|
||||||
@@ -379,25 +377,6 @@ 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,11 +177,8 @@ 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,
|
||||||
#if JSON_HAS_RANGES && !defined(__MINGW32__)
|
int > = 0 >
|
||||||
&& !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;
|
||||||
@@ -221,25 +218,6 @@ 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<>
|
||||||
@@ -377,44 +355,19 @@ 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_compatible_binary_type<BasicJsonType, 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 >
|
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)
|
||||||
|
|||||||
@@ -220,20 +220,29 @@ class iterator_input_adapter
|
|||||||
// whether IteratorType refers to a contiguous range and therefore supports
|
// whether IteratorType refers to a contiguous range and therefore supports
|
||||||
// a std::memcpy fast path (pointers always do; in C++20 we can also detect
|
// a std::memcpy fast path (pointers always do; in C++20 we can also detect
|
||||||
// library iterators such as those of std::vector and std::string).
|
// library iterators such as those of std::vector and std::string).
|
||||||
// The fast path also requires SentinelType == IteratorType so std::distance works.
|
// Computing the available element count needs either same-type iterators
|
||||||
|
// (plain std::distance) or, in C++20, a sized sentinel (std::ranges::distance),
|
||||||
|
// e.g. std::counted_iterator paired with std::default_sentinel_t.
|
||||||
static constexpr bool iterator_is_contiguous =
|
static constexpr bool iterator_is_contiguous =
|
||||||
std::is_same<IteratorType, SentinelType>::value && (
|
|
||||||
#if defined(__cpp_lib_concepts) && defined(JSON_HAS_CPP_20)
|
#if defined(__cpp_lib_concepts) && defined(JSON_HAS_CPP_20)
|
||||||
std::contiguous_iterator<IteratorType> ||
|
(std::is_same<IteratorType, SentinelType>::value || std::sized_sentinel_for<SentinelType, IteratorType>)
|
||||||
|
&& (std::contiguous_iterator<IteratorType> || std::is_pointer<IteratorType>::value);
|
||||||
|
#else
|
||||||
|
std::is_same<IteratorType, SentinelType>::value && std::is_pointer<IteratorType>::value;
|
||||||
#endif
|
#endif
|
||||||
std::is_pointer<IteratorType>::value);
|
|
||||||
|
|
||||||
// contiguous fast path: bulk copy the remaining range with std::memcpy
|
// contiguous fast path: bulk copy the remaining range with std::memcpy
|
||||||
template<class T>
|
template<class T>
|
||||||
std::size_t get_elements_impl(T* dest, std::size_t count, std::true_type /*contiguous*/)
|
std::size_t get_elements_impl(T* dest, std::size_t count, std::true_type /*contiguous*/)
|
||||||
{
|
{
|
||||||
const std::size_t wanted = count * sizeof(T);
|
const std::size_t wanted = count * sizeof(T);
|
||||||
|
#if defined(__cpp_lib_concepts) && defined(JSON_HAS_CPP_20)
|
||||||
|
// std::ranges::distance also supports sized sentinels of a different
|
||||||
|
// type (e.g. std::counted_iterator + std::default_sentinel_t)
|
||||||
|
const std::size_t available = static_cast<std::size_t>(std::ranges::distance(current, end)) * sizeof(char_type);
|
||||||
|
#else
|
||||||
const std::size_t available = static_cast<std::size_t>(std::distance(current, end)) * sizeof(char_type);
|
const std::size_t available = static_cast<std::size_t>(std::distance(current, end)) * sizeof(char_type);
|
||||||
|
#endif
|
||||||
const std::size_t copied = (std::min)(wanted, available);
|
const std::size_t copied = (std::min)(wanted, available);
|
||||||
if (JSON_HEDLEY_LIKELY(copied != 0))
|
if (JSON_HEDLEY_LIKELY(copied != 0))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -13,15 +13,11 @@
|
|||||||
#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>
|
||||||
@@ -454,51 +450,6 @@ 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 {};
|
||||||
|
|
||||||
@@ -510,38 +461,13 @@ 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> {};
|
||||||
@@ -633,14 +559,6 @@ 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,7 +189,6 @@
|
|||||||
#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>
|
||||||
// __ _____ _____ _____
|
// __ _____ _____ _____
|
||||||
@@ -3593,7 +3592,6 @@ 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
|
||||||
@@ -3665,9 +3663,6 @@ 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++
|
||||||
@@ -4217,51 +4212,6 @@ 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 {};
|
||||||
|
|
||||||
@@ -4273,38 +4223,13 @@ 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> {};
|
||||||
@@ -4396,14 +4321,6 @@ 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
|
||||||
{
|
{
|
||||||
@@ -5547,7 +5464,6 @@ 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)
|
||||||
@@ -5593,25 +5509,6 @@ 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)
|
||||||
@@ -6308,11 +6205,8 @@ 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,
|
||||||
#if JSON_HAS_RANGES && !defined(__MINGW32__)
|
int > = 0 >
|
||||||
&& !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;
|
||||||
@@ -6352,25 +6246,6 @@ 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<>
|
||||||
@@ -6508,44 +6383,19 @@ 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_compatible_binary_type<BasicJsonType, 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 >
|
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)
|
||||||
@@ -7207,20 +7057,29 @@ class iterator_input_adapter
|
|||||||
// whether IteratorType refers to a contiguous range and therefore supports
|
// whether IteratorType refers to a contiguous range and therefore supports
|
||||||
// a std::memcpy fast path (pointers always do; in C++20 we can also detect
|
// a std::memcpy fast path (pointers always do; in C++20 we can also detect
|
||||||
// library iterators such as those of std::vector and std::string).
|
// library iterators such as those of std::vector and std::string).
|
||||||
// The fast path also requires SentinelType == IteratorType so std::distance works.
|
// Computing the available element count needs either same-type iterators
|
||||||
|
// (plain std::distance) or, in C++20, a sized sentinel (std::ranges::distance),
|
||||||
|
// e.g. std::counted_iterator paired with std::default_sentinel_t.
|
||||||
static constexpr bool iterator_is_contiguous =
|
static constexpr bool iterator_is_contiguous =
|
||||||
std::is_same<IteratorType, SentinelType>::value && (
|
|
||||||
#if defined(__cpp_lib_concepts) && defined(JSON_HAS_CPP_20)
|
#if defined(__cpp_lib_concepts) && defined(JSON_HAS_CPP_20)
|
||||||
std::contiguous_iterator<IteratorType> ||
|
(std::is_same<IteratorType, SentinelType>::value || std::sized_sentinel_for<SentinelType, IteratorType>)
|
||||||
|
&& (std::contiguous_iterator<IteratorType> || std::is_pointer<IteratorType>::value);
|
||||||
|
#else
|
||||||
|
std::is_same<IteratorType, SentinelType>::value && std::is_pointer<IteratorType>::value;
|
||||||
#endif
|
#endif
|
||||||
std::is_pointer<IteratorType>::value);
|
|
||||||
|
|
||||||
// contiguous fast path: bulk copy the remaining range with std::memcpy
|
// contiguous fast path: bulk copy the remaining range with std::memcpy
|
||||||
template<class T>
|
template<class T>
|
||||||
std::size_t get_elements_impl(T* dest, std::size_t count, std::true_type /*contiguous*/)
|
std::size_t get_elements_impl(T* dest, std::size_t count, std::true_type /*contiguous*/)
|
||||||
{
|
{
|
||||||
const std::size_t wanted = count * sizeof(T);
|
const std::size_t wanted = count * sizeof(T);
|
||||||
|
#if defined(__cpp_lib_concepts) && defined(JSON_HAS_CPP_20)
|
||||||
|
// std::ranges::distance also supports sized sentinels of a different
|
||||||
|
// type (e.g. std::counted_iterator + std::default_sentinel_t)
|
||||||
|
const std::size_t available = static_cast<std::size_t>(std::ranges::distance(current, end)) * sizeof(char_type);
|
||||||
|
#else
|
||||||
const std::size_t available = static_cast<std::size_t>(std::distance(current, end)) * sizeof(char_type);
|
const std::size_t available = static_cast<std::size_t>(std::distance(current, end)) * sizeof(char_type);
|
||||||
|
#endif
|
||||||
const std::size_t copied = (std::min)(wanted, available);
|
const std::size_t copied = (std::min)(wanted, available);
|
||||||
if (JSON_HEDLEY_LIKELY(copied != 0))
|
if (JSON_HEDLEY_LIKELY(copied != 0))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1136,40 +1136,6 @@ 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{};
|
||||||
@@ -1199,46 +1165,6 @@ 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)
|
||||||
|
|||||||
@@ -6,6 +6,13 @@
|
|||||||
// SPDX-FileCopyrightText: 2013-2026 Niels Lohmann <https://nlohmann.me>
|
// SPDX-FileCopyrightText: 2013-2026 Niels Lohmann <https://nlohmann.me>
|
||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
// cmake/test.cmake selects the C++ standard versions with which to build a
|
||||||
|
// unit test based on the presence of JSON_HAS_CPP_<VERSION> macros.
|
||||||
|
// When using macros that are only defined for particular versions of the standard
|
||||||
|
// (e.g., JSON_HAS_FILESYSTEM for C++17 and up), please mention the corresponding
|
||||||
|
// version macro in a comment close by, like this:
|
||||||
|
// JSON_HAS_CPP_<VERSION> (do not remove; see note at top of file)
|
||||||
|
|
||||||
#include "doctest_compatibility.h"
|
#include "doctest_compatibility.h"
|
||||||
|
|
||||||
#include <nlohmann/json.hpp>
|
#include <nlohmann/json.hpp>
|
||||||
@@ -13,6 +20,10 @@ using nlohmann::json;
|
|||||||
|
|
||||||
#include <list>
|
#include <list>
|
||||||
|
|
||||||
|
#if defined(__cpp_lib_concepts) && defined(JSON_HAS_CPP_20)
|
||||||
|
#include <iterator>
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
TEST_CASE("Use arbitrary stdlib container")
|
TEST_CASE("Use arbitrary stdlib container")
|
||||||
@@ -201,4 +212,21 @@ TEST_CASE("Parse with heterogeneous iterator and sentinel types")
|
|||||||
CHECK(j2.at(0) == 1);
|
CHECK(j2.at(0) == 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(__cpp_lib_concepts) && defined(JSON_HAS_CPP_20)
|
||||||
|
// 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")
|
||||||
|
{
|
||||||
|
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());
|
||||||
|
|
||||||
|
std::counted_iterator first(json_str.begin(), len);
|
||||||
|
const json j = json::parse(first, std::default_sentinel);
|
||||||
|
CHECK(j["key"] == "value");
|
||||||
|
CHECK(j["array"].size() == 3);
|
||||||
|
|
||||||
|
std::counted_iterator first2(json_str.begin(), len);
|
||||||
|
CHECK(json::accept(first2, std::default_sentinel));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|||||||
Reference in New Issue
Block a user