Compare commits

..

2 Commits

Author SHA1 Message Date
Niels Lohmann 97dc6bed50 Guard optional assignment test behind JSON_USE_IMPLICIT_CONVERSIONS
opt_assign = j_null relies on basic_json's implicit conversion
operator to satisfy std::optional's assignment operator template
(which requires is_assignable, not just is_constructible). With
implicit conversions disabled the operator is explicit, so the
assignment doesn't compile at all rather than throwing at runtime.
Fixes the ci_test_noimplicitconversions failure on #5269.

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
2026-07-11 23:42:29 +02:00
Niels Lohmann 0e535ba3bc Extend std::optional null regression coverage (assignment, get_to)
Adds two cases to the existing null-handling regression test for
std::optional<T>: assignment (opt = json_null) throws for the same
reason as direct construction, and get_to() correctly yields
std::nullopt. Prompted by a review comment on #5246 asking for a
fuller regression matrix; construction and get<optional<T>>() were
already covered by #5247.

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
2026-07-11 18:49:11 +02:00
27 changed files with 133 additions and 573 deletions
+5 -13
View File
@@ -8,8 +8,8 @@ static bool accept(InputType&& i,
const bool ignore_trailing_commas = false); const bool ignore_trailing_commas = false);
// (2) // (2)
template<typename IteratorType, typename SentinelType = IteratorType> template<typename IteratorType>
static bool accept(IteratorType first, SentinelType last, static bool accept(IteratorType first, IteratorType last,
const bool ignore_comments = false, const bool ignore_comments = false,
const bool ignore_trailing_commas = false); const bool ignore_trailing_commas = false);
``` ```
@@ -17,11 +17,10 @@ static bool accept(IteratorType first, SentinelType last,
Checks whether the input is valid JSON. Checks whether the input is valid JSON.
1. Reads from a compatible input. 1. Reads from a compatible input.
2. Reads from a pair of character iterators, or an iterator and a sentinel of a different type (C++20 ranges support) 2. Reads from a pair of character iterators
The value_type of the iterator must be an integral type with a size of 1, 2, or 4 bytes, which will be interpreted The value_type of the iterator must be an integral type with a size of 1, 2, or 4 bytes, which will be interpreted
respectively as UTF-8, UTF-16, and UTF-32. If `SentinelType` differs from `IteratorType`, it must be comparable to respectively as UTF-8, UTF-16, and UTF-32.
the iterator type with `operator!=`.
Unlike the [`parse()`](parse.md) function, this function neither throws an exception in case of invalid JSON input Unlike the [`parse()`](parse.md) function, this function neither throws an exception in case of invalid JSON input
(i.e., a parse error) nor creates diagnostic information. (i.e., a parse error) nor creates diagnostic information.
@@ -45,12 +44,6 @@ Unlike the [`parse()`](parse.md) function, this function neither throws an excep
- a pair of `std::string::iterator` or `std::vector<std::uint8_t>::iterator` - a pair of `std::string::iterator` or `std::vector<std::uint8_t>::iterator`
- a pair of pointers such as `ptr` and `ptr + len` - a pair of pointers such as `ptr` and `ptr + len`
`SentinelType`
: defaults to `IteratorType`; may be a different type comparable to `IteratorType` via `operator!=`, for instance.
- a custom sentinel type for C++20 ranges
- `std::counted_iterator` with a different sentinel type
## Parameters ## Parameters
`i` (in) `i` (in)
@@ -68,7 +61,7 @@ Unlike the [`parse()`](parse.md) function, this function neither throws an excep
: iterator to the start of the character range : iterator to the start of the character range
`last` (in) `last` (in)
: iterator to the end of the character range, or a sentinel value that compares equal to the end iterator with `operator!=` : iterator to the end of the character range
## Return value ## Return value
@@ -119,7 +112,6 @@ A UTF-8 byte order mark is silently ignored.
- Changed [runtime assertion](../../features/assertions.md) in case of `FILE*` null pointers to exception in version 3.12.0. - Changed [runtime assertion](../../features/assertions.md) in case of `FILE*` null pointers to exception in version 3.12.0.
- Added `ignore_trailing_commas` in version 3.13.0. - Added `ignore_trailing_commas` in version 3.13.0.
- Extended container support (1) to include types with lvalue-only ADL `begin`/`end` (matching `std::begin`/`std::end` semantics) in version 3.13.0. - Extended container support (1) to include types with lvalue-only ADL `begin`/`end` (matching `std::begin`/`std::end` semantics) in version 3.13.0.
- Extended overload (2) to accept heterogeneous iterator+sentinel pairs (C++20 ranges support) in version 3.13.0.
!!! warning "Deprecation" !!! warning "Deprecation"
@@ -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
@@ -7,8 +7,8 @@ static basic_json from_bjdata(InputType&& i,
const bool strict = true, const bool strict = true,
const bool allow_exceptions = true); const bool allow_exceptions = true);
// (2) // (2)
template<typename IteratorType, typename SentinelType = IteratorType> template<typename IteratorType>
static basic_json from_bjdata(IteratorType first, SentinelType last, static basic_json from_bjdata(IteratorType first, IteratorType last,
const bool strict = true, const bool strict = true,
const bool allow_exceptions = true); const bool allow_exceptions = true);
``` ```
@@ -16,7 +16,7 @@ static basic_json from_bjdata(IteratorType first, SentinelType last,
Deserializes a given input to a JSON value using the BJData (Binary JData) serialization format. Deserializes a given input to a JSON value using the BJData (Binary JData) serialization format.
1. Reads from a compatible input. 1. Reads from a compatible input.
2. Reads from an iterator range, or an iterator and a sentinel of a different type (C++20 ranges support). 2. Reads from an iterator range.
The exact mapping and its limitations are described on a [dedicated page](../../features/binary_formats/bjdata.md). The exact mapping and its limitations are described on a [dedicated page](../../features/binary_formats/bjdata.md).
@@ -35,10 +35,6 @@ The exact mapping and its limitations are described on a [dedicated page](../../
`IteratorType` `IteratorType`
: a compatible iterator type : a compatible iterator type
`SentinelType`
: defaults to `IteratorType`; may be a different type comparable to `IteratorType` via `operator!=`, for instance a
custom sentinel type for C++20 ranges
## Parameters ## Parameters
`i` (in) `i` (in)
@@ -48,7 +44,7 @@ The exact mapping and its limitations are described on a [dedicated page](../../
: iterator to the start of the input : iterator to the start of the input
`last` (in) `last` (in)
: iterator to the end of the input, or a sentinel value that compares equal to the end iterator with `operator!=` : iterator to the end of the input
`strict` (in) `strict` (in)
: whether to expect the input to be consumed until EOF (`#!cpp true` by default) : whether to expect the input to be consumed until EOF (`#!cpp true` by default)
@@ -107,4 +103,3 @@ Linear in the size of the input.
- Added in version 3.11.0. - Added in version 3.11.0.
- Extended container support (1) to include types with lvalue-only ADL `begin`/`end` (matching `std::begin`/`std::end` semantics) in version 3.13.0. - Extended container support (1) to include types with lvalue-only ADL `begin`/`end` (matching `std::begin`/`std::end` semantics) in version 3.13.0.
- Extended overload (2) to accept heterogeneous iterator+sentinel pairs (C++20 ranges support) in version 3.13.0.
+4 -9
View File
@@ -7,8 +7,8 @@ static basic_json from_bson(InputType&& i,
const bool strict = true, const bool strict = true,
const bool allow_exceptions = true); const bool allow_exceptions = true);
// (2) // (2)
template<typename IteratorType, typename SentinelType = IteratorType> template<typename IteratorType>
static basic_json from_bson(IteratorType first, SentinelType last, static basic_json from_bson(IteratorType first, IteratorType last,
const bool strict = true, const bool strict = true,
const bool allow_exceptions = true); const bool allow_exceptions = true);
``` ```
@@ -16,7 +16,7 @@ static basic_json from_bson(IteratorType first, SentinelType last,
Deserializes a given input to a JSON value using the BSON (Binary JSON) serialization format. Deserializes a given input to a JSON value using the BSON (Binary JSON) serialization format.
1. Reads from a compatible input. 1. Reads from a compatible input.
2. Reads from an iterator range, or an iterator and a sentinel of a different type (C++20 ranges support). 2. Reads from an iterator range.
The exact mapping and its limitations are described on a [dedicated page](../../features/binary_formats/bson.md). The exact mapping and its limitations are described on a [dedicated page](../../features/binary_formats/bson.md).
@@ -35,10 +35,6 @@ The exact mapping and its limitations are described on a [dedicated page](../../
`IteratorType` `IteratorType`
: a compatible iterator type : a compatible iterator type
`SentinelType`
: defaults to `IteratorType`; may be a different type comparable to `IteratorType` via `operator!=`, for instance a
custom sentinel type for C++20 ranges
## Parameters ## Parameters
`i` (in) `i` (in)
@@ -48,7 +44,7 @@ The exact mapping and its limitations are described on a [dedicated page](../../
: iterator to the start of the input : iterator to the start of the input
`last` (in) `last` (in)
: iterator to the end of the input, or a sentinel value that compares equal to the end iterator with `operator!=` : iterator to the end of the input
`strict` (in) `strict` (in)
: whether to expect the input to be consumed until EOF (`#!cpp true` by default) : whether to expect the input to be consumed until EOF (`#!cpp true` by default)
@@ -107,7 +103,6 @@ Linear in the size of the input.
- Added in version 3.4.0. - Added in version 3.4.0.
- Extended container support (1) to include types with lvalue-only ADL `begin`/`end` (matching `std::begin`/`std::end` semantics) in version 3.13.0. - Extended container support (1) to include types with lvalue-only ADL `begin`/`end` (matching `std::begin`/`std::end` semantics) in version 3.13.0.
- Extended overload (2) to accept heterogeneous iterator+sentinel pairs (C++20 ranges support) in version 3.13.0.
!!! warning "Deprecation" !!! warning "Deprecation"
+4 -9
View File
@@ -9,8 +9,8 @@ static basic_json from_cbor(InputType&& i,
const cbor_tag_handler_t tag_handler = cbor_tag_handler_t::error); const cbor_tag_handler_t tag_handler = cbor_tag_handler_t::error);
// (2) // (2)
template<typename IteratorType, typename SentinelType = IteratorType> template<typename IteratorType>
static basic_json from_cbor(IteratorType first, SentinelType last, static basic_json from_cbor(IteratorType first, IteratorType last,
const bool strict = true, const bool strict = true,
const bool allow_exceptions = true, const bool allow_exceptions = true,
const cbor_tag_handler_t tag_handler = cbor_tag_handler_t::error); const cbor_tag_handler_t tag_handler = cbor_tag_handler_t::error);
@@ -19,7 +19,7 @@ static basic_json from_cbor(IteratorType first, SentinelType last,
Deserializes a given input to a JSON value using the CBOR (Concise Binary Object Representation) serialization format. Deserializes a given input to a JSON value using the CBOR (Concise Binary Object Representation) serialization format.
1. Reads from a compatible input. 1. Reads from a compatible input.
2. Reads from an iterator range, or an iterator and a sentinel of a different type (C++20 ranges support). 2. Reads from an iterator range.
The exact mapping and its limitations are described on a [dedicated page](../../features/binary_formats/cbor.md). The exact mapping and its limitations are described on a [dedicated page](../../features/binary_formats/cbor.md).
@@ -38,10 +38,6 @@ The exact mapping and its limitations are described on a [dedicated page](../../
`IteratorType` `IteratorType`
: a compatible iterator type : a compatible iterator type
`SentinelType`
: defaults to `IteratorType`; may be a different type comparable to `IteratorType` via `operator!=`, for instance a
custom sentinel type for C++20 ranges
## Parameters ## Parameters
`i` (in) `i` (in)
@@ -51,7 +47,7 @@ The exact mapping and its limitations are described on a [dedicated page](../../
: iterator to the start of the input : iterator to the start of the input
`last` (in) `last` (in)
: iterator to the end of the input, or a sentinel value that compares equal to the end iterator with `operator!=` : iterator to the end of the input
`strict` (in) `strict` (in)
: whether to expect the input to be consumed until EOF (`#!cpp true` by default) : whether to expect the input to be consumed until EOF (`#!cpp true` by default)
@@ -117,7 +113,6 @@ Linear in the size of the input.
- Added `allow_exceptions` parameter in version 3.2.0. - Added `allow_exceptions` parameter in version 3.2.0.
- Added `tag_handler` parameter in version 3.9.0. - Added `tag_handler` parameter in version 3.9.0.
- Extended container support (1) to include types with lvalue-only ADL `begin`/`end` (matching `std::begin`/`std::end` semantics) in version 3.13.0. - Extended container support (1) to include types with lvalue-only ADL `begin`/`end` (matching `std::begin`/`std::end` semantics) in version 3.13.0.
- Extended overload (2) to accept heterogeneous iterator+sentinel pairs (C++20 ranges support) in version 3.13.0.
!!! warning "Deprecation" !!! warning "Deprecation"
@@ -7,8 +7,8 @@ static basic_json from_msgpack(InputType&& i,
const bool strict = true, const bool strict = true,
const bool allow_exceptions = true); const bool allow_exceptions = true);
// (2) // (2)
template<typename IteratorType, typename SentinelType = IteratorType> template<typename IteratorType>
static basic_json from_msgpack(IteratorType first, SentinelType last, static basic_json from_msgpack(IteratorType first, IteratorType last,
const bool strict = true, const bool strict = true,
const bool allow_exceptions = true); const bool allow_exceptions = true);
``` ```
@@ -16,7 +16,7 @@ static basic_json from_msgpack(IteratorType first, SentinelType last,
Deserializes a given input to a JSON value using the MessagePack serialization format. Deserializes a given input to a JSON value using the MessagePack serialization format.
1. Reads from a compatible input. 1. Reads from a compatible input.
2. Reads from an iterator range, or an iterator and a sentinel of a different type (C++20 ranges support). 2. Reads from an iterator range.
The exact mapping and its limitations are described on a [dedicated page](../../features/binary_formats/messagepack.md). The exact mapping and its limitations are described on a [dedicated page](../../features/binary_formats/messagepack.md).
@@ -35,10 +35,6 @@ The exact mapping and its limitations are described on a [dedicated page](../../
`IteratorType` `IteratorType`
: a compatible iterator type : a compatible iterator type
`SentinelType`
: defaults to `IteratorType`; may be a different type comparable to `IteratorType` via `operator!=`, for instance a
custom sentinel type for C++20 ranges
## Parameters ## Parameters
`i` (in) `i` (in)
@@ -48,7 +44,7 @@ The exact mapping and its limitations are described on a [dedicated page](../../
: iterator to the start of the input : iterator to the start of the input
`last` (in) `last` (in)
: iterator to the end of the input, or a sentinel value that compares equal to the end iterator with `operator!=` : iterator to the end of the input
`strict` (in) `strict` (in)
: whether to expect the input to be consumed until EOF (`#!cpp true` by default) : whether to expect the input to be consumed until EOF (`#!cpp true` by default)
@@ -109,7 +105,6 @@ Linear in the size of the input.
- Changed to consume input adapters, removed `start_index` parameter, and added `strict` parameter in version 3.0.0. - Changed to consume input adapters, removed `start_index` parameter, and added `strict` parameter in version 3.0.0.
- Added `allow_exceptions` parameter in version 3.2.0. - Added `allow_exceptions` parameter in version 3.2.0.
- Extended container support (1) to include types with lvalue-only ADL `begin`/`end` (matching `std::begin`/`std::end` semantics) in version 3.13.0. - Extended container support (1) to include types with lvalue-only ADL `begin`/`end` (matching `std::begin`/`std::end` semantics) in version 3.13.0.
- Extended overload (2) to accept heterogeneous iterator+sentinel pairs (C++20 ranges support) in version 3.13.0.
!!! warning "Deprecation" !!! warning "Deprecation"
@@ -7,8 +7,8 @@ static basic_json from_ubjson(InputType&& i,
const bool strict = true, const bool strict = true,
const bool allow_exceptions = true); const bool allow_exceptions = true);
// (2) // (2)
template<typename IteratorType, typename SentinelType = IteratorType> template<typename IteratorType>
static basic_json from_ubjson(IteratorType first, SentinelType last, static basic_json from_ubjson(IteratorType first, IteratorType last,
const bool strict = true, const bool strict = true,
const bool allow_exceptions = true); const bool allow_exceptions = true);
``` ```
@@ -16,7 +16,7 @@ static basic_json from_ubjson(IteratorType first, SentinelType last,
Deserializes a given input to a JSON value using the UBJSON (Universal Binary JSON) serialization format. Deserializes a given input to a JSON value using the UBJSON (Universal Binary JSON) serialization format.
1. Reads from a compatible input. 1. Reads from a compatible input.
2. Reads from an iterator range, or an iterator and a sentinel of a different type (C++20 ranges support). 2. Reads from an iterator range.
The exact mapping and its limitations are described on a [dedicated page](../../features/binary_formats/ubjson.md). The exact mapping and its limitations are described on a [dedicated page](../../features/binary_formats/ubjson.md).
@@ -35,10 +35,6 @@ The exact mapping and its limitations are described on a [dedicated page](../../
`IteratorType` `IteratorType`
: a compatible iterator type : a compatible iterator type
`SentinelType`
: defaults to `IteratorType`; may be a different type comparable to `IteratorType` via `operator!=`, for instance a
custom sentinel type for C++20 ranges
## Parameters ## Parameters
`i` (in) `i` (in)
@@ -48,7 +44,7 @@ The exact mapping and its limitations are described on a [dedicated page](../../
: iterator to the start of the input : iterator to the start of the input
`last` (in) `last` (in)
: iterator to the end of the input, or a sentinel value that compares equal to the end iterator with `operator!=` : iterator to the end of the input
`strict` (in) `strict` (in)
: whether to expect the input to be consumed until EOF (`#!cpp true` by default) : whether to expect the input to be consumed until EOF (`#!cpp true` by default)
@@ -108,7 +104,6 @@ Linear in the size of the input.
- Added in version 3.1.0. - Added in version 3.1.0.
- Added `allow_exceptions` parameter in version 3.2.0. - Added `allow_exceptions` parameter in version 3.2.0.
- Extended container support (1) to include types with lvalue-only ADL `begin`/`end` (matching `std::begin`/`std::end` semantics) in version 3.13.0. - Extended container support (1) to include types with lvalue-only ADL `begin`/`end` (matching `std::begin`/`std::end` semantics) in version 3.13.0.
- Extended overload (2) to accept heterogeneous iterator+sentinel pairs (C++20 ranges support) in version 3.13.0.
!!! warning "Deprecation" !!! warning "Deprecation"
+5 -13
View File
@@ -10,8 +10,8 @@ static basic_json parse(InputType&& i,
const bool ignore_trailing_commas = false); const bool ignore_trailing_commas = false);
// (2) // (2)
template<typename IteratorType, typename SentinelType = IteratorType> template<typename IteratorType>
static basic_json parse(IteratorType first, SentinelType last, static basic_json parse(IteratorType first, IteratorType last,
const parser_callback_t cb = nullptr, const parser_callback_t cb = nullptr,
const bool allow_exceptions = true, const bool allow_exceptions = true,
const bool ignore_comments = false, const bool ignore_comments = false,
@@ -19,11 +19,10 @@ static basic_json parse(IteratorType first, SentinelType last,
``` ```
1. Deserialize from a compatible input. 1. Deserialize from a compatible input.
2. Deserialize from a pair of character iterators, or an iterator and a sentinel of a different type (C++20 ranges support) 2. Deserialize from a pair of character iterators
The `value_type` of the iterator must be an integral type with size of 1, 2, or 4 bytes, which will be interpreted The `value_type` of the iterator must be an integral type with size of 1, 2, or 4 bytes, which will be interpreted
respectively as UTF-8, UTF-16, and UTF-32. If `SentinelType` differs from `IteratorType`, it must be comparable to respectively as UTF-8, UTF-16, and UTF-32.
the iterator type with `operator!=`.
## Template parameters ## Template parameters
@@ -44,12 +43,6 @@ static basic_json parse(IteratorType first, SentinelType last,
- a pair of `std::string::iterator` or `std::vector<std::uint8_t>::iterator` - a pair of `std::string::iterator` or `std::vector<std::uint8_t>::iterator`
- a pair of pointers such as `ptr` and `ptr + len` - a pair of pointers such as `ptr` and `ptr + len`
`SentinelType`
: defaults to `IteratorType`; may be a different type comparable to `IteratorType` via `operator!=`, for instance.
- a custom sentinel type for C++20 ranges
- `std::counted_iterator` with a different sentinel type
## Parameters ## Parameters
`i` (in) `i` (in)
@@ -74,7 +67,7 @@ static basic_json parse(IteratorType first, SentinelType last,
: iterator to the start of a character range : iterator to the start of a character range
`last` (in) `last` (in)
: iterator to the end of a character range, or a sentinel value that compares equal to the end iterator with `operator!=` : iterator to the end of a character range
## Return value ## Return value
@@ -245,7 +238,6 @@ Invalid Unicode escapes and unpaired surrogates in the input are reported as
- Changed [runtime assertion](../../features/assertions.md) in case of `FILE*` null pointers to exception in version 3.12.0. - Changed [runtime assertion](../../features/assertions.md) in case of `FILE*` null pointers to exception in version 3.12.0.
- Added `ignore_trailing_commas` in version 3.13.0. - Added `ignore_trailing_commas` in version 3.13.0.
- Extended container support (1) to include types with lvalue-only ADL `begin`/`end` (matching `std::begin`/`std::end` semantics) in version 3.13.0. - Extended container support (1) to include types with lvalue-only ADL `begin`/`end` (matching `std::begin`/`std::end` semantics) in version 3.13.0.
- Extended overload (2) to accept heterogeneous iterator+sentinel pairs (C++20 ranges support) in version 3.13.0.
!!! warning "Deprecation" !!! warning "Deprecation"
+5 -10
View File
@@ -11,8 +11,8 @@ static bool sax_parse(InputType&& i,
const bool ignore_trailing_commas = false); const bool ignore_trailing_commas = false);
// (2) // (2)
template<class IteratorType, class SAX, class SentinelType = IteratorType> template<class IteratorType, class SAX>
static bool sax_parse(IteratorType first, SentinelType last, static bool sax_parse(IteratorType first, IteratorType last,
SAX* sax, SAX* sax,
input_format_t format = input_format_t::json, input_format_t format = input_format_t::json,
const bool strict = true, const bool strict = true,
@@ -23,11 +23,10 @@ static bool sax_parse(IteratorType first, SentinelType last,
Read from input and generate SAX events Read from input and generate SAX events
1. Read from a compatible input. 1. Read from a compatible input.
2. Read from a pair of character iterators, or an iterator and a sentinel of a different type (C++20 ranges support) 2. Read from a pair of character iterators
The value_type of the iterator must be an integral type with a size of 1, 2, or 4 bytes, which will be interpreted The value_type of the iterator must be an integral type with a size of 1, 2, or 4 bytes, which will be interpreted
respectively as UTF-8, UTF-16, and UTF-32. If `SentinelType` differs from `IteratorType`, it must be comparable to respectively as UTF-8, UTF-16, and UTF-32.
the iterator type with `operator!=`.
The SAX event lister must follow the interface of [`json_sax`](../json_sax/index.md). The SAX event lister must follow the interface of [`json_sax`](../json_sax/index.md).
@@ -47,9 +46,6 @@ The SAX event lister must follow the interface of [`json_sax`](../json_sax/index
: a compatible iterator type for overload (2); a pair of character iterators whose `value_type` is an integral type : a compatible iterator type for overload (2); a pair of character iterators whose `value_type` is an integral type
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`
: defaults to `IteratorType`; may be a different type comparable to `IteratorType` via `operator!=`, for overload (2)
`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)
@@ -80,7 +76,7 @@ The SAX event lister must follow the interface of [`json_sax`](../json_sax/index
: iterator to the start of a character range : iterator to the start of a character range
`last` (in) `last` (in)
: iterator to the end of a character range, or a sentinel value that compares equal to the end iterator with `operator!=` : iterator to the end of a character range
## Return value ## Return value
@@ -132,7 +128,6 @@ A UTF-8 byte order mark is silently ignored.
- Ignoring comments via `ignore_comments` added in version 3.9.0. - Ignoring comments via `ignore_comments` added in version 3.9.0.
- Added `ignore_trailing_commas` in version 3.13.0. - Added `ignore_trailing_commas` in version 3.13.0.
- Extended container support (1) to include types with lvalue-only ADL `begin`/`end` (matching `std::begin`/`std::end` semantics) in version 3.13.0. - Extended container support (1) to include types with lvalue-only ADL `begin`/`end` (matching `std::begin`/`std::end` semantics) in version 3.13.0.
- Extended overload (2) to accept heterogeneous iterator+sentinel pairs (C++20 ranges support) in version 3.13.0.
!!! warning "Deprecation" !!! warning "Deprecation"
@@ -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
-36
View File
@@ -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
-25
View File
@@ -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)
@@ -377,7 +377,6 @@ 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__) #if JSON_HAS_RANGES && !defined(__MINGW32__)
&& !is_compatible_range_view<CompatibleArrayType>::value && !is_compatible_range_view<CompatibleArrayType>::value
@@ -407,14 +406,6 @@ inline void to_json(BasicJsonType& j, const typename BasicJsonType::binary_t& bi
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)
@@ -155,9 +155,7 @@ class input_stream_adapter
// General-purpose iterator-based adapter. It might not be as fast as // General-purpose iterator-based adapter. It might not be as fast as
// theoretically possible for some containers, but it is extremely versatile. // theoretically possible for some containers, but it is extremely versatile.
// SentinelType defaults to IteratorType for backward compatibility, but may template<typename IteratorType>
// be a different type (e.g., a C++20 sentinel or counted_iterator).
template<typename IteratorType, typename SentinelType = IteratorType>
class iterator_input_adapter class iterator_input_adapter
{ {
public: public:
@@ -171,10 +169,9 @@ class iterator_input_adapter
// in wide_string_input_adapter, which does not expose this). // in wide_string_input_adapter, which does not expose this).
static constexpr bool supports_seek = static constexpr bool supports_seek =
std::is_same<typename std::iterator_traits<IteratorType>::iterator_category, std::random_access_iterator_tag>::value std::is_same<typename std::iterator_traits<IteratorType>::iterator_category, std::random_access_iterator_tag>::value
&& std::is_same<IteratorType, SentinelType>::value
&& sizeof(char_type) == 1; && sizeof(char_type) == 1;
iterator_input_adapter(IteratorType first, SentinelType last) iterator_input_adapter(IteratorType first, IteratorType last)
: begin(first), current(std::move(first)), end(std::move(last)) : begin(first), current(std::move(first)), end(std::move(last))
{} {}
@@ -219,14 +216,12 @@ class iterator_input_adapter
private: private:
// 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.
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::contiguous_iterator<IteratorType> ||
#endif #endif
std::is_pointer<IteratorType>::value); 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>
@@ -272,7 +267,7 @@ class iterator_input_adapter
IteratorType begin; IteratorType begin;
IteratorType current; IteratorType current;
SentinelType end; IteratorType end;
template<typename BaseInputAdapter, size_t T> template<typename BaseInputAdapter, size_t T>
friend struct wide_string_input_helper; friend struct wide_string_input_helper;
@@ -458,54 +453,19 @@ class wide_string_input_adapter
std::size_t utf8_bytes_filled = 0; std::size_t utf8_bytes_filled = 0;
}; };
template<typename IteratorType, typename SentinelType = IteratorType, typename Enable = void> template<typename IteratorType, typename Enable = void>
struct iterator_input_adapter_factory struct iterator_input_adapter_factory
{ {
using iterator_type = IteratorType; using iterator_type = IteratorType;
using sentinel_type = SentinelType;
using char_type = typename std::iterator_traits<iterator_type>::value_type; using char_type = typename std::iterator_traits<iterator_type>::value_type;
using adapter_type = iterator_input_adapter<iterator_type, sentinel_type>; using adapter_type = iterator_input_adapter<iterator_type>;
static adapter_type create(IteratorType first, SentinelType last) static adapter_type create(IteratorType first, IteratorType last)
{ {
return adapter_type(std::move(first), std::move(last)); return adapter_type(std::move(first), std::move(last));
} }
}; };
// Detection: whether IteratorType and SentinelType can be compared with !=
template<typename IteratorType, typename SentinelType, typename = void>
struct can_compare_ne_impl : std::false_type {};
template<typename IteratorType, typename SentinelType>
struct can_compare_ne_impl < IteratorType, SentinelType,
void_t < decltype(std::declval<IteratorType>() != std::declval<SentinelType>()) >>
: std::true_type {};
// Workaround for reversed operator order
template<typename IteratorType, typename SentinelType, typename = void>
struct can_compare_ne_reversed : std::false_type {};
template<typename IteratorType, typename SentinelType>
struct can_compare_ne_reversed < IteratorType, SentinelType,
void_t < decltype(std::declval<SentinelType>() != std::declval<IteratorType>()) >>
: std::true_type {};
template<typename IteratorType, typename SentinelType>
struct can_compare_ne_either_order : std::integral_constant < bool,
can_compare_ne_impl<IteratorType, SentinelType>::value ||
can_compare_ne_reversed<IteratorType, SentinelType>::value > {};
// std::nullptr_t is excluded explicitly: a literal `nullptr` passed as a
// trailing default argument (e.g. parse(s, nullptr, ...)) must never be
// mistaken for a sentinel, and some compilers (e.g. GCC 4.8) unreliably
// SFINAE the `operator!=` detection above for std::nullptr_t against
// container/string types, which would otherwise make such calls ambiguous
// with the compatible-input overload.
template<typename IteratorType, typename SentinelType>
struct can_compare_ne : std::integral_constant < bool,
!std::is_same<SentinelType, std::nullptr_t>::value &&
can_compare_ne_either_order<IteratorType, SentinelType>::value > {};
template<typename T> template<typename T>
struct is_iterator_of_multibyte struct is_iterator_of_multibyte
{ {
@@ -516,31 +476,25 @@ struct is_iterator_of_multibyte
}; };
}; };
template<typename IteratorType, typename SentinelType> template<typename IteratorType>
struct iterator_input_adapter_factory<IteratorType, SentinelType, enable_if_t<is_iterator_of_multibyte<IteratorType>::value>> struct iterator_input_adapter_factory<IteratorType, enable_if_t<is_iterator_of_multibyte<IteratorType>::value>>
{ {
using iterator_type = IteratorType; using iterator_type = IteratorType;
using sentinel_type = SentinelType;
using char_type = typename std::iterator_traits<iterator_type>::value_type; using char_type = typename std::iterator_traits<iterator_type>::value_type;
using base_adapter_type = iterator_input_adapter<iterator_type, sentinel_type>; using base_adapter_type = iterator_input_adapter<iterator_type>;
using adapter_type = wide_string_input_adapter<base_adapter_type, char_type>; using adapter_type = wide_string_input_adapter<base_adapter_type, char_type>;
static adapter_type create(IteratorType first, SentinelType last) static adapter_type create(IteratorType first, IteratorType last)
{ {
return adapter_type(base_adapter_type(std::move(first), std::move(last))); return adapter_type(base_adapter_type(std::move(first), std::move(last)));
} }
}; };
// General purpose iterator-based input (iterator+sentinel pair; SentinelType // General purpose iterator-based input
// defaults to IteratorType for the common same-type case, but may differ for template<typename IteratorType>
// C++20 ranges-style iterator+sentinel pairs). Only enable for types that can typename iterator_input_adapter_factory<IteratorType>::adapter_type input_adapter(IteratorType first, IteratorType last)
// be compared with !=.
template < typename IteratorType, typename SentinelType = IteratorType,
typename = typename std::enable_if <
can_compare_ne<IteratorType, SentinelType>::value >::type >
typename iterator_input_adapter_factory<IteratorType, SentinelType>::adapter_type input_adapter(IteratorType first, SentinelType last)
{ {
using factory_type = iterator_input_adapter_factory<IteratorType, SentinelType>; using factory_type = iterator_input_adapter_factory<IteratorType>;
return factory_type::create(first, last); return factory_type::create(first, last);
} }
@@ -13,7 +13,6 @@
#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
@@ -633,14 +632,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
{ {
+24 -32
View File
@@ -4083,13 +4083,12 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
return result; return result;
} }
/// @brief deserialize from a pair of character iterators (or an iterator+sentinel pair, C++20 ranges support) /// @brief deserialize from a pair of character iterators
/// @sa https://json.nlohmann.me/api/basic_json/parse/ /// @sa https://json.nlohmann.me/api/basic_json/parse/
template<typename IteratorType, typename SentinelType = IteratorType, template<typename IteratorType>
detail::enable_if_t<detail::can_compare_ne<IteratorType, SentinelType>::value, int> = 0>
JSON_HEDLEY_WARN_UNUSED_RESULT JSON_HEDLEY_WARN_UNUSED_RESULT
static basic_json parse(IteratorType first, static basic_json parse(IteratorType first,
SentinelType last, IteratorType last,
parser_callback_t cb = nullptr, parser_callback_t cb = nullptr,
const bool allow_exceptions = true, const bool allow_exceptions = true,
const bool ignore_comments = false, const bool ignore_comments = false,
@@ -4123,11 +4122,10 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
return parser(detail::input_adapter(std::forward<InputType>(i)), nullptr, false, ignore_comments, ignore_trailing_commas).accept(true); return parser(detail::input_adapter(std::forward<InputType>(i)), nullptr, false, ignore_comments, ignore_trailing_commas).accept(true);
} }
/// @brief check if the input is valid JSON (iterator pair, or iterator+sentinel pair for C++20 ranges support) /// @brief check if the input is valid JSON
/// @sa https://json.nlohmann.me/api/basic_json/accept/ /// @sa https://json.nlohmann.me/api/basic_json/accept/
template<typename IteratorType, typename SentinelType = IteratorType, template<typename IteratorType>
detail::enable_if_t<detail::can_compare_ne<IteratorType, SentinelType>::value, int> = 0> static bool accept(IteratorType first, IteratorType last,
static bool accept(IteratorType first, SentinelType last,
const bool ignore_comments = false, const bool ignore_comments = false,
const bool ignore_trailing_commas = false) const bool ignore_trailing_commas = false)
{ {
@@ -4159,12 +4157,11 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
: detail::binary_reader<basic_json, decltype(ia), SAX>(std::move(ia), format).sax_parse(format, sax, strict); : detail::binary_reader<basic_json, decltype(ia), SAX>(std::move(ia), format).sax_parse(format, sax, strict);
} }
/// @brief generate SAX events (iterator pair, or iterator+sentinel pair for C++20 ranges support) /// @brief generate SAX events
/// @sa https://json.nlohmann.me/api/basic_json/sax_parse/ /// @sa https://json.nlohmann.me/api/basic_json/sax_parse/
template<class IteratorType, class SAX, class SentinelType = IteratorType, template<class IteratorType, class SAX>
detail::enable_if_t<detail::can_compare_ne<IteratorType, SentinelType>::value, int> = 0>
JSON_HEDLEY_NON_NULL(3) JSON_HEDLEY_NON_NULL(3)
static bool sax_parse(IteratorType first, SentinelType last, SAX* sax, static bool sax_parse(IteratorType first, IteratorType last, SAX* sax,
input_format_t format = input_format_t::json, input_format_t format = input_format_t::json,
const bool strict = true, const bool strict = true,
const bool ignore_comments = false, const bool ignore_comments = false,
@@ -4464,12 +4461,11 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
return res ? result : basic_json(value_t::discarded); return res ? result : basic_json(value_t::discarded);
} }
/// @brief create a JSON value from an input in CBOR format (iterator pair, or iterator+sentinel pair for C++20 ranges support) /// @brief create a JSON value from an input in CBOR format
/// @sa https://json.nlohmann.me/api/basic_json/from_cbor/ /// @sa https://json.nlohmann.me/api/basic_json/from_cbor/
template<typename IteratorType, typename SentinelType = IteratorType, template<typename IteratorType>
detail::enable_if_t<detail::can_compare_ne<IteratorType, SentinelType>::value, int> = 0>
JSON_HEDLEY_WARN_UNUSED_RESULT JSON_HEDLEY_WARN_UNUSED_RESULT
static basic_json from_cbor(IteratorType first, SentinelType last, static basic_json from_cbor(IteratorType first, IteratorType last,
const bool strict = true, const bool strict = true,
const bool allow_exceptions = true, const bool allow_exceptions = true,
const cbor_tag_handler_t tag_handler = cbor_tag_handler_t::error) const cbor_tag_handler_t tag_handler = cbor_tag_handler_t::error)
@@ -4522,12 +4518,11 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
return res ? result : basic_json(value_t::discarded); return res ? result : basic_json(value_t::discarded);
} }
/// @brief create a JSON value from an input in MessagePack format (iterator pair, or iterator+sentinel pair for C++20 ranges support) /// @brief create a JSON value from an input in MessagePack format
/// @sa https://json.nlohmann.me/api/basic_json/from_msgpack/ /// @sa https://json.nlohmann.me/api/basic_json/from_msgpack/
template<typename IteratorType, typename SentinelType = IteratorType, template<typename IteratorType>
detail::enable_if_t<detail::can_compare_ne<IteratorType, SentinelType>::value, int> = 0>
JSON_HEDLEY_WARN_UNUSED_RESULT JSON_HEDLEY_WARN_UNUSED_RESULT
static basic_json from_msgpack(IteratorType first, SentinelType last, static basic_json from_msgpack(IteratorType first, IteratorType last,
const bool strict = true, const bool strict = true,
const bool allow_exceptions = true) const bool allow_exceptions = true)
{ {
@@ -4577,12 +4572,11 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
return res ? result : basic_json(value_t::discarded); return res ? result : basic_json(value_t::discarded);
} }
/// @brief create a JSON value from an input in UBJSON format (iterator pair, or iterator+sentinel pair for C++20 ranges support) /// @brief create a JSON value from an input in UBJSON format
/// @sa https://json.nlohmann.me/api/basic_json/from_ubjson/ /// @sa https://json.nlohmann.me/api/basic_json/from_ubjson/
template<typename IteratorType, typename SentinelType = IteratorType, template<typename IteratorType>
detail::enable_if_t<detail::can_compare_ne<IteratorType, SentinelType>::value, int> = 0>
JSON_HEDLEY_WARN_UNUSED_RESULT JSON_HEDLEY_WARN_UNUSED_RESULT
static basic_json from_ubjson(IteratorType first, SentinelType last, static basic_json from_ubjson(IteratorType first, IteratorType last,
const bool strict = true, const bool strict = true,
const bool allow_exceptions = true) const bool allow_exceptions = true)
{ {
@@ -4632,12 +4626,11 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
return res ? result : basic_json(value_t::discarded); return res ? result : basic_json(value_t::discarded);
} }
/// @brief create a JSON value from an input in BJData format (iterator pair, or iterator+sentinel pair for C++20 ranges support) /// @brief create a JSON value from an input in BJData format
/// @sa https://json.nlohmann.me/api/basic_json/from_bjdata/ /// @sa https://json.nlohmann.me/api/basic_json/from_bjdata/
template<typename IteratorType, typename SentinelType = IteratorType, template<typename IteratorType>
detail::enable_if_t<detail::can_compare_ne<IteratorType, SentinelType>::value, int> = 0>
JSON_HEDLEY_WARN_UNUSED_RESULT JSON_HEDLEY_WARN_UNUSED_RESULT
static basic_json from_bjdata(IteratorType first, SentinelType last, static basic_json from_bjdata(IteratorType first, IteratorType last,
const bool strict = true, const bool strict = true,
const bool allow_exceptions = true) const bool allow_exceptions = true)
{ {
@@ -4663,12 +4656,11 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
return res ? result : basic_json(value_t::discarded); return res ? result : basic_json(value_t::discarded);
} }
/// @brief create a JSON value from an input in BSON format (iterator pair, or iterator+sentinel pair for C++20 ranges support) /// @brief create a JSON value from an input in BSON format
/// @sa https://json.nlohmann.me/api/basic_json/from_bson/ /// @sa https://json.nlohmann.me/api/basic_json/from_bson/
template<typename IteratorType, typename SentinelType = IteratorType, template<typename IteratorType>
detail::enable_if_t<detail::can_compare_ne<IteratorType, SentinelType>::value, int> = 0>
JSON_HEDLEY_WARN_UNUSED_RESULT JSON_HEDLEY_WARN_UNUSED_RESULT
static basic_json from_bson(IteratorType first, SentinelType last, static basic_json from_bson(IteratorType first, IteratorType last,
const bool strict = true, const bool strict = true,
const bool allow_exceptions = true) const bool allow_exceptions = true)
{ {
+41 -134
View File
@@ -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
@@ -4396,14 +4394,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 +5537,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 +5582,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)
@@ -6508,7 +6478,6 @@ 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__) #if JSON_HAS_RANGES && !defined(__MINGW32__)
&& !is_compatible_range_view<CompatibleArrayType>::value && !is_compatible_range_view<CompatibleArrayType>::value
@@ -6538,14 +6507,6 @@ inline void to_json(BasicJsonType& j, const typename BasicJsonType::binary_t& bi
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)
@@ -7142,9 +7103,7 @@ class input_stream_adapter
// General-purpose iterator-based adapter. It might not be as fast as // General-purpose iterator-based adapter. It might not be as fast as
// theoretically possible for some containers, but it is extremely versatile. // theoretically possible for some containers, but it is extremely versatile.
// SentinelType defaults to IteratorType for backward compatibility, but may template<typename IteratorType>
// be a different type (e.g., a C++20 sentinel or counted_iterator).
template<typename IteratorType, typename SentinelType = IteratorType>
class iterator_input_adapter class iterator_input_adapter
{ {
public: public:
@@ -7158,10 +7117,9 @@ class iterator_input_adapter
// in wide_string_input_adapter, which does not expose this). // in wide_string_input_adapter, which does not expose this).
static constexpr bool supports_seek = static constexpr bool supports_seek =
std::is_same<typename std::iterator_traits<IteratorType>::iterator_category, std::random_access_iterator_tag>::value std::is_same<typename std::iterator_traits<IteratorType>::iterator_category, std::random_access_iterator_tag>::value
&& std::is_same<IteratorType, SentinelType>::value
&& sizeof(char_type) == 1; && sizeof(char_type) == 1;
iterator_input_adapter(IteratorType first, SentinelType last) iterator_input_adapter(IteratorType first, IteratorType last)
: begin(first), current(std::move(first)), end(std::move(last)) : begin(first), current(std::move(first)), end(std::move(last))
{} {}
@@ -7206,14 +7164,12 @@ class iterator_input_adapter
private: private:
// 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.
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::contiguous_iterator<IteratorType> ||
#endif #endif
std::is_pointer<IteratorType>::value); 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>
@@ -7259,7 +7215,7 @@ class iterator_input_adapter
IteratorType begin; IteratorType begin;
IteratorType current; IteratorType current;
SentinelType end; IteratorType end;
template<typename BaseInputAdapter, size_t T> template<typename BaseInputAdapter, size_t T>
friend struct wide_string_input_helper; friend struct wide_string_input_helper;
@@ -7445,54 +7401,19 @@ class wide_string_input_adapter
std::size_t utf8_bytes_filled = 0; std::size_t utf8_bytes_filled = 0;
}; };
template<typename IteratorType, typename SentinelType = IteratorType, typename Enable = void> template<typename IteratorType, typename Enable = void>
struct iterator_input_adapter_factory struct iterator_input_adapter_factory
{ {
using iterator_type = IteratorType; using iterator_type = IteratorType;
using sentinel_type = SentinelType;
using char_type = typename std::iterator_traits<iterator_type>::value_type; using char_type = typename std::iterator_traits<iterator_type>::value_type;
using adapter_type = iterator_input_adapter<iterator_type, sentinel_type>; using adapter_type = iterator_input_adapter<iterator_type>;
static adapter_type create(IteratorType first, SentinelType last) static adapter_type create(IteratorType first, IteratorType last)
{ {
return adapter_type(std::move(first), std::move(last)); return adapter_type(std::move(first), std::move(last));
} }
}; };
// Detection: whether IteratorType and SentinelType can be compared with !=
template<typename IteratorType, typename SentinelType, typename = void>
struct can_compare_ne_impl : std::false_type {};
template<typename IteratorType, typename SentinelType>
struct can_compare_ne_impl < IteratorType, SentinelType,
void_t < decltype(std::declval<IteratorType>() != std::declval<SentinelType>()) >>
: std::true_type {};
// Workaround for reversed operator order
template<typename IteratorType, typename SentinelType, typename = void>
struct can_compare_ne_reversed : std::false_type {};
template<typename IteratorType, typename SentinelType>
struct can_compare_ne_reversed < IteratorType, SentinelType,
void_t < decltype(std::declval<SentinelType>() != std::declval<IteratorType>()) >>
: std::true_type {};
template<typename IteratorType, typename SentinelType>
struct can_compare_ne_either_order : std::integral_constant < bool,
can_compare_ne_impl<IteratorType, SentinelType>::value ||
can_compare_ne_reversed<IteratorType, SentinelType>::value > {};
// std::nullptr_t is excluded explicitly: a literal `nullptr` passed as a
// trailing default argument (e.g. parse(s, nullptr, ...)) must never be
// mistaken for a sentinel, and some compilers (e.g. GCC 4.8) unreliably
// SFINAE the `operator!=` detection above for std::nullptr_t against
// container/string types, which would otherwise make such calls ambiguous
// with the compatible-input overload.
template<typename IteratorType, typename SentinelType>
struct can_compare_ne : std::integral_constant < bool,
!std::is_same<SentinelType, std::nullptr_t>::value &&
can_compare_ne_either_order<IteratorType, SentinelType>::value > {};
template<typename T> template<typename T>
struct is_iterator_of_multibyte struct is_iterator_of_multibyte
{ {
@@ -7503,31 +7424,25 @@ struct is_iterator_of_multibyte
}; };
}; };
template<typename IteratorType, typename SentinelType> template<typename IteratorType>
struct iterator_input_adapter_factory<IteratorType, SentinelType, enable_if_t<is_iterator_of_multibyte<IteratorType>::value>> struct iterator_input_adapter_factory<IteratorType, enable_if_t<is_iterator_of_multibyte<IteratorType>::value>>
{ {
using iterator_type = IteratorType; using iterator_type = IteratorType;
using sentinel_type = SentinelType;
using char_type = typename std::iterator_traits<iterator_type>::value_type; using char_type = typename std::iterator_traits<iterator_type>::value_type;
using base_adapter_type = iterator_input_adapter<iterator_type, sentinel_type>; using base_adapter_type = iterator_input_adapter<iterator_type>;
using adapter_type = wide_string_input_adapter<base_adapter_type, char_type>; using adapter_type = wide_string_input_adapter<base_adapter_type, char_type>;
static adapter_type create(IteratorType first, SentinelType last) static adapter_type create(IteratorType first, IteratorType last)
{ {
return adapter_type(base_adapter_type(std::move(first), std::move(last))); return adapter_type(base_adapter_type(std::move(first), std::move(last)));
} }
}; };
// General purpose iterator-based input (iterator+sentinel pair; SentinelType // General purpose iterator-based input
// defaults to IteratorType for the common same-type case, but may differ for template<typename IteratorType>
// C++20 ranges-style iterator+sentinel pairs). Only enable for types that can typename iterator_input_adapter_factory<IteratorType>::adapter_type input_adapter(IteratorType first, IteratorType last)
// be compared with !=.
template < typename IteratorType, typename SentinelType = IteratorType,
typename = typename std::enable_if <
can_compare_ne<IteratorType, SentinelType>::value >::type >
typename iterator_input_adapter_factory<IteratorType, SentinelType>::adapter_type input_adapter(IteratorType first, SentinelType last)
{ {
using factory_type = iterator_input_adapter_factory<IteratorType, SentinelType>; using factory_type = iterator_input_adapter_factory<IteratorType>;
return factory_type::create(first, last); return factory_type::create(first, last);
} }
@@ -25130,13 +25045,12 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
return result; return result;
} }
/// @brief deserialize from a pair of character iterators (or an iterator+sentinel pair, C++20 ranges support) /// @brief deserialize from a pair of character iterators
/// @sa https://json.nlohmann.me/api/basic_json/parse/ /// @sa https://json.nlohmann.me/api/basic_json/parse/
template<typename IteratorType, typename SentinelType = IteratorType, template<typename IteratorType>
detail::enable_if_t<detail::can_compare_ne<IteratorType, SentinelType>::value, int> = 0>
JSON_HEDLEY_WARN_UNUSED_RESULT JSON_HEDLEY_WARN_UNUSED_RESULT
static basic_json parse(IteratorType first, static basic_json parse(IteratorType first,
SentinelType last, IteratorType last,
parser_callback_t cb = nullptr, parser_callback_t cb = nullptr,
const bool allow_exceptions = true, const bool allow_exceptions = true,
const bool ignore_comments = false, const bool ignore_comments = false,
@@ -25170,11 +25084,10 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
return parser(detail::input_adapter(std::forward<InputType>(i)), nullptr, false, ignore_comments, ignore_trailing_commas).accept(true); return parser(detail::input_adapter(std::forward<InputType>(i)), nullptr, false, ignore_comments, ignore_trailing_commas).accept(true);
} }
/// @brief check if the input is valid JSON (iterator pair, or iterator+sentinel pair for C++20 ranges support) /// @brief check if the input is valid JSON
/// @sa https://json.nlohmann.me/api/basic_json/accept/ /// @sa https://json.nlohmann.me/api/basic_json/accept/
template<typename IteratorType, typename SentinelType = IteratorType, template<typename IteratorType>
detail::enable_if_t<detail::can_compare_ne<IteratorType, SentinelType>::value, int> = 0> static bool accept(IteratorType first, IteratorType last,
static bool accept(IteratorType first, SentinelType last,
const bool ignore_comments = false, const bool ignore_comments = false,
const bool ignore_trailing_commas = false) const bool ignore_trailing_commas = false)
{ {
@@ -25206,12 +25119,11 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
: detail::binary_reader<basic_json, decltype(ia), SAX>(std::move(ia), format).sax_parse(format, sax, strict); : detail::binary_reader<basic_json, decltype(ia), SAX>(std::move(ia), format).sax_parse(format, sax, strict);
} }
/// @brief generate SAX events (iterator pair, or iterator+sentinel pair for C++20 ranges support) /// @brief generate SAX events
/// @sa https://json.nlohmann.me/api/basic_json/sax_parse/ /// @sa https://json.nlohmann.me/api/basic_json/sax_parse/
template<class IteratorType, class SAX, class SentinelType = IteratorType, template<class IteratorType, class SAX>
detail::enable_if_t<detail::can_compare_ne<IteratorType, SentinelType>::value, int> = 0>
JSON_HEDLEY_NON_NULL(3) JSON_HEDLEY_NON_NULL(3)
static bool sax_parse(IteratorType first, SentinelType last, SAX* sax, static bool sax_parse(IteratorType first, IteratorType last, SAX* sax,
input_format_t format = input_format_t::json, input_format_t format = input_format_t::json,
const bool strict = true, const bool strict = true,
const bool ignore_comments = false, const bool ignore_comments = false,
@@ -25511,12 +25423,11 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
return res ? result : basic_json(value_t::discarded); return res ? result : basic_json(value_t::discarded);
} }
/// @brief create a JSON value from an input in CBOR format (iterator pair, or iterator+sentinel pair for C++20 ranges support) /// @brief create a JSON value from an input in CBOR format
/// @sa https://json.nlohmann.me/api/basic_json/from_cbor/ /// @sa https://json.nlohmann.me/api/basic_json/from_cbor/
template<typename IteratorType, typename SentinelType = IteratorType, template<typename IteratorType>
detail::enable_if_t<detail::can_compare_ne<IteratorType, SentinelType>::value, int> = 0>
JSON_HEDLEY_WARN_UNUSED_RESULT JSON_HEDLEY_WARN_UNUSED_RESULT
static basic_json from_cbor(IteratorType first, SentinelType last, static basic_json from_cbor(IteratorType first, IteratorType last,
const bool strict = true, const bool strict = true,
const bool allow_exceptions = true, const bool allow_exceptions = true,
const cbor_tag_handler_t tag_handler = cbor_tag_handler_t::error) const cbor_tag_handler_t tag_handler = cbor_tag_handler_t::error)
@@ -25569,12 +25480,11 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
return res ? result : basic_json(value_t::discarded); return res ? result : basic_json(value_t::discarded);
} }
/// @brief create a JSON value from an input in MessagePack format (iterator pair, or iterator+sentinel pair for C++20 ranges support) /// @brief create a JSON value from an input in MessagePack format
/// @sa https://json.nlohmann.me/api/basic_json/from_msgpack/ /// @sa https://json.nlohmann.me/api/basic_json/from_msgpack/
template<typename IteratorType, typename SentinelType = IteratorType, template<typename IteratorType>
detail::enable_if_t<detail::can_compare_ne<IteratorType, SentinelType>::value, int> = 0>
JSON_HEDLEY_WARN_UNUSED_RESULT JSON_HEDLEY_WARN_UNUSED_RESULT
static basic_json from_msgpack(IteratorType first, SentinelType last, static basic_json from_msgpack(IteratorType first, IteratorType last,
const bool strict = true, const bool strict = true,
const bool allow_exceptions = true) const bool allow_exceptions = true)
{ {
@@ -25624,12 +25534,11 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
return res ? result : basic_json(value_t::discarded); return res ? result : basic_json(value_t::discarded);
} }
/// @brief create a JSON value from an input in UBJSON format (iterator pair, or iterator+sentinel pair for C++20 ranges support) /// @brief create a JSON value from an input in UBJSON format
/// @sa https://json.nlohmann.me/api/basic_json/from_ubjson/ /// @sa https://json.nlohmann.me/api/basic_json/from_ubjson/
template<typename IteratorType, typename SentinelType = IteratorType, template<typename IteratorType>
detail::enable_if_t<detail::can_compare_ne<IteratorType, SentinelType>::value, int> = 0>
JSON_HEDLEY_WARN_UNUSED_RESULT JSON_HEDLEY_WARN_UNUSED_RESULT
static basic_json from_ubjson(IteratorType first, SentinelType last, static basic_json from_ubjson(IteratorType first, IteratorType last,
const bool strict = true, const bool strict = true,
const bool allow_exceptions = true) const bool allow_exceptions = true)
{ {
@@ -25679,12 +25588,11 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
return res ? result : basic_json(value_t::discarded); return res ? result : basic_json(value_t::discarded);
} }
/// @brief create a JSON value from an input in BJData format (iterator pair, or iterator+sentinel pair for C++20 ranges support) /// @brief create a JSON value from an input in BJData format
/// @sa https://json.nlohmann.me/api/basic_json/from_bjdata/ /// @sa https://json.nlohmann.me/api/basic_json/from_bjdata/
template<typename IteratorType, typename SentinelType = IteratorType, template<typename IteratorType>
detail::enable_if_t<detail::can_compare_ne<IteratorType, SentinelType>::value, int> = 0>
JSON_HEDLEY_WARN_UNUSED_RESULT JSON_HEDLEY_WARN_UNUSED_RESULT
static basic_json from_bjdata(IteratorType first, SentinelType last, static basic_json from_bjdata(IteratorType first, IteratorType last,
const bool strict = true, const bool strict = true,
const bool allow_exceptions = true) const bool allow_exceptions = true)
{ {
@@ -25710,12 +25618,11 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
return res ? result : basic_json(value_t::discarded); return res ? result : basic_json(value_t::discarded);
} }
/// @brief create a JSON value from an input in BSON format (iterator pair, or iterator+sentinel pair for C++20 ranges support) /// @brief create a JSON value from an input in BSON format
/// @sa https://json.nlohmann.me/api/basic_json/from_bson/ /// @sa https://json.nlohmann.me/api/basic_json/from_bson/
template<typename IteratorType, typename SentinelType = IteratorType, template<typename IteratorType>
detail::enable_if_t<detail::can_compare_ne<IteratorType, SentinelType>::value, int> = 0>
JSON_HEDLEY_WARN_UNUSED_RESULT JSON_HEDLEY_WARN_UNUSED_RESULT
static basic_json from_bson(IteratorType first, SentinelType last, static basic_json from_bson(IteratorType first, IteratorType last,
const bool strict = true, const bool strict = true,
const bool allow_exceptions = true) const bool allow_exceptions = true)
{ {
-13
View File
@@ -30,17 +30,4 @@ inline std::vector<std::uint8_t> read_binary_file(const std::string& filename)
return byte_vector; return byte_vector;
} }
// sentinel for istreambuf_iterator; compares != true until EOF is reached
// lets tests read a file directly via the new iterator+sentinel overloads
// instead of buffering the whole file into a vector first.
// Only the iterator-first direction (it != sentinel) is ever evaluated by
// the library's parse loop, so no reversed-order overload is needed.
struct istreambuf_sentinel
{
friend bool operator!=(const std::istreambuf_iterator<char>& it, const istreambuf_sentinel& /*unused*/) noexcept
{
return it != std::istreambuf_iterator<char>();
}
};
} // namespace utils } // namespace utils
-9
View File
@@ -3699,15 +3699,6 @@ TEST_CASE("Universal Binary JSON Specification Examples 1")
} }
} }
TEST_CASE("Parse BJData directly from a file using iterator and sentinel")
{
std::string const filename = TEST_DATA_DIRECTORY "/json_testsuite/sample.json.bjdata";
std::ifstream file(filename, std::ios::binary);
const std::istreambuf_iterator<char> first(file);
const json parsed = json::from_bjdata(first, utils::istreambuf_sentinel{});
CHECK((parsed.is_object() || parsed.is_array()));
}
#if !defined(JSON_NOEXCEPTION) #if !defined(JSON_NOEXCEPTION)
TEST_CASE("all BJData first bytes") TEST_CASE("all BJData first bytes")
{ {
-13
View File
@@ -1208,19 +1208,6 @@ TEST_CASE("BSON numerical data")
} }
} }
TEST_CASE("Parse BSON directly from a file using iterator and sentinel")
{
std::string const filename = TEST_DATA_DIRECTORY "/json.org/1.json";
std::ifstream f_json(filename);
const json expected = json::parse(f_json);
std::ifstream file(filename + ".bson", std::ios::binary);
const std::istreambuf_iterator<char> first(file);
const json parsed = json::from_bson(first, utils::istreambuf_sentinel{});
CHECK(parsed == expected);
}
TEST_CASE("BSON roundtrips" * doctest::skip()) TEST_CASE("BSON roundtrips" * doctest::skip())
{ {
SECTION("reference files") SECTION("reference files")
-9
View File
@@ -1921,15 +1921,6 @@ TEST_CASE("single CBOR roundtrip")
} }
} }
TEST_CASE("Parse CBOR directly from a file using iterator and sentinel")
{
std::string const filename = TEST_DATA_DIRECTORY "/json_testsuite/sample.json.cbor";
std::ifstream file(filename, std::ios::binary);
const std::istreambuf_iterator<char> first(file);
const json parsed = json::from_cbor(first, utils::istreambuf_sentinel{});
CHECK((parsed.is_object() || parsed.is_array()));
}
#if !defined(JSON_NOEXCEPTION) #if !defined(JSON_NOEXCEPTION)
TEST_CASE("CBOR regressions") TEST_CASE("CBOR regressions")
{ {
+15
View File
@@ -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")
-9
View File
@@ -1641,15 +1641,6 @@ TEST_CASE("single MessagePack roundtrip")
} }
} }
TEST_CASE("Parse MessagePack directly from a file using iterator and sentinel")
{
std::string const filename = TEST_DATA_DIRECTORY "/json_testsuite/sample.json.msgpack";
std::ifstream file(filename, std::ios::binary);
const std::istreambuf_iterator<char> first(file);
const json parsed = json::from_msgpack(first, utils::istreambuf_sentinel{});
CHECK((parsed.is_object() || parsed.is_array()));
}
TEST_CASE("MessagePack roundtrips" * doctest::skip()) TEST_CASE("MessagePack roundtrips" * doctest::skip())
{ {
SECTION("input from msgpack-python") SECTION("input from msgpack-python")
-34
View File
@@ -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{};
-9
View File
@@ -2393,15 +2393,6 @@ TEST_CASE("Universal Binary JSON Specification Examples 1")
} }
} }
TEST_CASE("Parse UBJSON directly from a file using iterator and sentinel")
{
std::string const filename = TEST_DATA_DIRECTORY "/json_testsuite/sample.json.ubjson";
std::ifstream file(filename, std::ios::binary);
const std::istreambuf_iterator<char> first(file);
const json parsed = json::from_ubjson(first, utils::istreambuf_sentinel{});
CHECK((parsed.is_object() || parsed.is_array()));
}
#if !defined(JSON_NOEXCEPTION) #if !defined(JSON_NOEXCEPTION)
TEST_CASE("all UBJSON first bytes") TEST_CASE("all UBJSON first bytes")
{ {
-33
View File
@@ -168,37 +168,4 @@ TEST_CASE("Custom iterator")
CHECK(as_json.at(3) == 4); CHECK(as_json.at(3) == 4);
} }
// Custom sentinel type for testing heterogeneous iterator+sentinel support
struct CustomSentinel
{
const char* end_ptr;
// only the iterator-first direction (it != sentinel) is ever evaluated by
// the library's parse loop; a reversed-order overload would go unused and
// trip -Wunneeded-internal-declaration under -Weverything
friend bool operator!=(const char* it, const CustomSentinel& sentinel)
{
return it != sentinel.end_ptr;
}
};
TEST_CASE("Parse with heterogeneous iterator and sentinel types")
{
const std::string json_str = R"({"key":"value"})";
const char* end_ptr = json_str.data() + json_str.size();
// Parse using pointer and sentinel (different types)
json j = json::parse(json_str.data(), CustomSentinel{end_ptr});
CHECK(j["key"] == "value");
// Accept using pointer and sentinel
CHECK(json::accept(json_str.data(), CustomSentinel{end_ptr}));
// Test that the same-type case still works
std::string raw_data = R"([1,2,3])";
std::list<char> data(raw_data.begin(), raw_data.end());
json j2 = json::parse(data.begin(), data.end());
CHECK(j2.at(0) == 1);
}
} // namespace } // namespace