mirror of
https://github.com/nlohmann/json.git
synced 2026-07-11 13:05:11 +00:00
Add iterator+sentinel tests and docs for binary deserializers
This commit extends the C++20 ranges support (iterator+sentinel pairs) to the binary format deserializers from_cbor, from_msgpack, from_ubjson, from_bjdata, and from_bson, matching what was already done for parse(), accept(), and sax_parse(). Changes: - Add istreambuf_sentinel helper to test_utils.hpp for EOF detection in tests - Add 5 new test cases that read binary files directly via std::istreambuf_iterator<char> + sentinel, without pre-buffering - Update documentation for all 5 from_* functions to document overload (3) with SentinelType parameter - All tests pass; verified against existing test suite data - Fix potential buffer over-read warning in heterogeneous iterator test Signed-off-by: Niels Lohmann <mail@nlohmann.me>
This commit is contained in:
@@ -12,15 +12,25 @@ template<typename IteratorType>
|
||||
static bool accept(IteratorType first, IteratorType last,
|
||||
const bool ignore_comments = false,
|
||||
const bool ignore_trailing_commas = false);
|
||||
|
||||
// (3)
|
||||
template<typename IteratorType, typename SentinelType>
|
||||
static bool accept(IteratorType first, SentinelType last,
|
||||
const bool ignore_comments = false,
|
||||
const bool ignore_trailing_commas = false);
|
||||
```
|
||||
|
||||
Checks whether the input is valid JSON.
|
||||
|
||||
1. Reads from a compatible input.
|
||||
2. Reads from a pair of character iterators
|
||||
2. Reads from a pair of character iterators (same type)
|
||||
|
||||
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.
|
||||
3. Reads from an iterator and a sentinel (different types, C++20 ranges support)
|
||||
|
||||
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. The sentinel type must be comparable to the iterator type with `operator!=`.
|
||||
|
||||
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.
|
||||
@@ -44,6 +54,12 @@ 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 pointers such as `ptr` and `ptr + len`
|
||||
|
||||
`SentinelType`
|
||||
: a sentinel type compatible with `IteratorType` (different from `IteratorType` and comparable via `operator!=`), for instance.
|
||||
|
||||
- a custom sentinel type for C++20 ranges
|
||||
- `std::counted_iterator` with a different sentinel type
|
||||
|
||||
## Parameters
|
||||
|
||||
`i` (in)
|
||||
@@ -61,7 +77,7 @@ Unlike the [`parse()`](parse.md) function, this function neither throws an excep
|
||||
: iterator to the start of the character range
|
||||
|
||||
`last` (in)
|
||||
: iterator to the end of the character range
|
||||
: iterator to the end of the character range, or a sentinel value that compares equal to the end iterator with `operator!=`
|
||||
|
||||
## Return value
|
||||
|
||||
@@ -112,6 +128,7 @@ 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.
|
||||
- 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.
|
||||
- Added overload (3) for heterogeneous iterator+sentinel pairs (C++20 ranges support) in version 3.13.0.
|
||||
|
||||
!!! warning "Deprecation"
|
||||
|
||||
|
||||
@@ -11,12 +11,19 @@ template<typename IteratorType>
|
||||
static basic_json from_bjdata(IteratorType first, IteratorType last,
|
||||
const bool strict = true,
|
||||
const bool allow_exceptions = true);
|
||||
|
||||
// (3)
|
||||
template<typename IteratorType, typename SentinelType>
|
||||
static basic_json from_bjdata(IteratorType first, SentinelType last,
|
||||
const bool strict = true,
|
||||
const bool allow_exceptions = true);
|
||||
```
|
||||
|
||||
Deserializes a given input to a JSON value using the BJData (Binary JData) serialization format.
|
||||
|
||||
1. Reads from a compatible input.
|
||||
2. Reads from an iterator range.
|
||||
3. Reads from an iterator and a sentinel (different types, C++20 ranges support).
|
||||
|
||||
The exact mapping and its limitations are described on a [dedicated page](../../features/binary_formats/bjdata.md).
|
||||
|
||||
@@ -35,6 +42,9 @@ The exact mapping and its limitations are described on a [dedicated page](../../
|
||||
`IteratorType`
|
||||
: a compatible iterator type
|
||||
|
||||
`SentinelType`
|
||||
: a sentinel type compatible with `IteratorType` (different from `IteratorType` and comparable via `operator!=`), for instance a custom sentinel type for C++20 ranges
|
||||
|
||||
## Parameters
|
||||
|
||||
`i` (in)
|
||||
@@ -44,7 +54,7 @@ The exact mapping and its limitations are described on a [dedicated page](../../
|
||||
: iterator to the start of the input
|
||||
|
||||
`last` (in)
|
||||
: iterator to the end of the input
|
||||
: iterator to the end of the input, or a sentinel value that compares equal to the end iterator with `operator!=`
|
||||
|
||||
`strict` (in)
|
||||
: whether to expect the input to be consumed until EOF (`#!cpp true` by default)
|
||||
@@ -103,3 +113,4 @@ Linear in the size of the input.
|
||||
|
||||
- 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.
|
||||
- Added overload (3) for heterogeneous iterator+sentinel pairs (C++20 ranges support) in version 3.13.0.
|
||||
|
||||
@@ -11,12 +11,19 @@ template<typename IteratorType>
|
||||
static basic_json from_bson(IteratorType first, IteratorType last,
|
||||
const bool strict = true,
|
||||
const bool allow_exceptions = true);
|
||||
|
||||
// (3)
|
||||
template<typename IteratorType, typename SentinelType>
|
||||
static basic_json from_bson(IteratorType first, SentinelType last,
|
||||
const bool strict = true,
|
||||
const bool allow_exceptions = true);
|
||||
```
|
||||
|
||||
Deserializes a given input to a JSON value using the BSON (Binary JSON) serialization format.
|
||||
|
||||
1. Reads from a compatible input.
|
||||
2. Reads from an iterator range.
|
||||
3. Reads from an iterator and a sentinel (different types, C++20 ranges support).
|
||||
|
||||
The exact mapping and its limitations are described on a [dedicated page](../../features/binary_formats/bson.md).
|
||||
|
||||
@@ -35,6 +42,9 @@ The exact mapping and its limitations are described on a [dedicated page](../../
|
||||
`IteratorType`
|
||||
: a compatible iterator type
|
||||
|
||||
`SentinelType`
|
||||
: a sentinel type compatible with `IteratorType` (different from `IteratorType` and comparable via `operator!=`), for instance a custom sentinel type for C++20 ranges
|
||||
|
||||
## Parameters
|
||||
|
||||
`i` (in)
|
||||
@@ -44,7 +54,7 @@ The exact mapping and its limitations are described on a [dedicated page](../../
|
||||
: iterator to the start of the input
|
||||
|
||||
`last` (in)
|
||||
: iterator to the end of the input
|
||||
: iterator to the end of the input, or a sentinel value that compares equal to the end iterator with `operator!=`
|
||||
|
||||
`strict` (in)
|
||||
: whether to expect the input to be consumed until EOF (`#!cpp true` by default)
|
||||
@@ -103,6 +113,7 @@ Linear in the size of the input.
|
||||
|
||||
- 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.
|
||||
- Added overload (3) for heterogeneous iterator+sentinel pairs (C++20 ranges support) in version 3.13.0.
|
||||
|
||||
!!! warning "Deprecation"
|
||||
|
||||
|
||||
@@ -14,12 +14,20 @@ static basic_json from_cbor(IteratorType first, IteratorType last,
|
||||
const bool strict = true,
|
||||
const bool allow_exceptions = true,
|
||||
const cbor_tag_handler_t tag_handler = cbor_tag_handler_t::error);
|
||||
|
||||
// (3)
|
||||
template<typename IteratorType, typename SentinelType>
|
||||
static basic_json from_cbor(IteratorType first, SentinelType last,
|
||||
const bool strict = true,
|
||||
const bool allow_exceptions = true,
|
||||
const cbor_tag_handler_t tag_handler = cbor_tag_handler_t::error);
|
||||
```
|
||||
|
||||
Deserializes a given input to a JSON value using the CBOR (Concise Binary Object Representation) serialization format.
|
||||
|
||||
1. Reads from a compatible input.
|
||||
2. Reads from an iterator range.
|
||||
3. Reads from an iterator and a sentinel (different types, C++20 ranges support).
|
||||
|
||||
The exact mapping and its limitations are described on a [dedicated page](../../features/binary_formats/cbor.md).
|
||||
|
||||
@@ -38,6 +46,9 @@ The exact mapping and its limitations are described on a [dedicated page](../../
|
||||
`IteratorType`
|
||||
: a compatible iterator type
|
||||
|
||||
`SentinelType`
|
||||
: a sentinel type compatible with `IteratorType` (different from `IteratorType` and comparable via `operator!=`), for instance a custom sentinel type for C++20 ranges
|
||||
|
||||
## Parameters
|
||||
|
||||
`i` (in)
|
||||
@@ -47,7 +58,7 @@ The exact mapping and its limitations are described on a [dedicated page](../../
|
||||
: iterator to the start of the input
|
||||
|
||||
`last` (in)
|
||||
: iterator to the end of the input
|
||||
: iterator to the end of the input, or a sentinel value that compares equal to the end iterator with `operator!=`
|
||||
|
||||
`strict` (in)
|
||||
: whether to expect the input to be consumed until EOF (`#!cpp true` by default)
|
||||
@@ -113,6 +124,7 @@ Linear in the size of the input.
|
||||
- Added `allow_exceptions` parameter in version 3.2.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.
|
||||
- Added overload (3) for heterogeneous iterator+sentinel pairs (C++20 ranges support) in version 3.13.0.
|
||||
|
||||
!!! warning "Deprecation"
|
||||
|
||||
|
||||
@@ -11,12 +11,19 @@ template<typename IteratorType>
|
||||
static basic_json from_msgpack(IteratorType first, IteratorType last,
|
||||
const bool strict = true,
|
||||
const bool allow_exceptions = true);
|
||||
|
||||
// (3)
|
||||
template<typename IteratorType, typename SentinelType>
|
||||
static basic_json from_msgpack(IteratorType first, SentinelType last,
|
||||
const bool strict = true,
|
||||
const bool allow_exceptions = true);
|
||||
```
|
||||
|
||||
Deserializes a given input to a JSON value using the MessagePack serialization format.
|
||||
|
||||
1. Reads from a compatible input.
|
||||
2. Reads from an iterator range.
|
||||
3. Reads from an iterator and a sentinel (different types, C++20 ranges support).
|
||||
|
||||
The exact mapping and its limitations are described on a [dedicated page](../../features/binary_formats/messagepack.md).
|
||||
|
||||
@@ -35,6 +42,9 @@ The exact mapping and its limitations are described on a [dedicated page](../../
|
||||
`IteratorType`
|
||||
: a compatible iterator type
|
||||
|
||||
`SentinelType`
|
||||
: a sentinel type compatible with `IteratorType` (different from `IteratorType` and comparable via `operator!=`), for instance a custom sentinel type for C++20 ranges
|
||||
|
||||
## Parameters
|
||||
|
||||
`i` (in)
|
||||
@@ -44,7 +54,7 @@ The exact mapping and its limitations are described on a [dedicated page](../../
|
||||
: iterator to the start of the input
|
||||
|
||||
`last` (in)
|
||||
: iterator to the end of the input
|
||||
: iterator to the end of the input, or a sentinel value that compares equal to the end iterator with `operator!=`
|
||||
|
||||
`strict` (in)
|
||||
: whether to expect the input to be consumed until EOF (`#!cpp true` by default)
|
||||
@@ -105,6 +115,7 @@ 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.
|
||||
- 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.
|
||||
- Added overload (3) for heterogeneous iterator+sentinel pairs (C++20 ranges support) in version 3.13.0.
|
||||
|
||||
!!! warning "Deprecation"
|
||||
|
||||
|
||||
@@ -11,12 +11,19 @@ template<typename IteratorType>
|
||||
static basic_json from_ubjson(IteratorType first, IteratorType last,
|
||||
const bool strict = true,
|
||||
const bool allow_exceptions = true);
|
||||
|
||||
// (3)
|
||||
template<typename IteratorType, typename SentinelType>
|
||||
static basic_json from_ubjson(IteratorType first, SentinelType last,
|
||||
const bool strict = true,
|
||||
const bool allow_exceptions = true);
|
||||
```
|
||||
|
||||
Deserializes a given input to a JSON value using the UBJSON (Universal Binary JSON) serialization format.
|
||||
|
||||
1. Reads from a compatible input.
|
||||
2. Reads from an iterator range.
|
||||
3. Reads from an iterator and a sentinel (different types, C++20 ranges support).
|
||||
|
||||
The exact mapping and its limitations are described on a [dedicated page](../../features/binary_formats/ubjson.md).
|
||||
|
||||
@@ -35,6 +42,9 @@ The exact mapping and its limitations are described on a [dedicated page](../../
|
||||
`IteratorType`
|
||||
: a compatible iterator type
|
||||
|
||||
`SentinelType`
|
||||
: a sentinel type compatible with `IteratorType` (different from `IteratorType` and comparable via `operator!=`), for instance a custom sentinel type for C++20 ranges
|
||||
|
||||
## Parameters
|
||||
|
||||
`i` (in)
|
||||
@@ -44,7 +54,7 @@ The exact mapping and its limitations are described on a [dedicated page](../../
|
||||
: iterator to the start of the input
|
||||
|
||||
`last` (in)
|
||||
: iterator to the end of the input
|
||||
: iterator to the end of the input, or a sentinel value that compares equal to the end iterator with `operator!=`
|
||||
|
||||
`strict` (in)
|
||||
: whether to expect the input to be consumed until EOF (`#!cpp true` by default)
|
||||
@@ -104,6 +114,7 @@ Linear in the size of the input.
|
||||
- Added in version 3.1.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.
|
||||
- Added overload (3) for heterogeneous iterator+sentinel pairs (C++20 ranges support) in version 3.13.0.
|
||||
|
||||
!!! warning "Deprecation"
|
||||
|
||||
|
||||
@@ -16,13 +16,25 @@ static basic_json parse(IteratorType first, IteratorType last,
|
||||
const bool allow_exceptions = true,
|
||||
const bool ignore_comments = false,
|
||||
const bool ignore_trailing_commas = false);
|
||||
|
||||
// (3)
|
||||
template<typename IteratorType, typename SentinelType>
|
||||
static basic_json parse(IteratorType first, SentinelType last,
|
||||
const parser_callback_t cb = nullptr,
|
||||
const bool allow_exceptions = true,
|
||||
const bool ignore_comments = false,
|
||||
const bool ignore_trailing_commas = false);
|
||||
```
|
||||
|
||||
1. Deserialize from a compatible input.
|
||||
2. Deserialize from a pair of character iterators
|
||||
2. Deserialize from a pair of character iterators (same type)
|
||||
|
||||
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.
|
||||
3. Deserialize from an iterator and a sentinel (different types, C++20 ranges support)
|
||||
|
||||
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. The sentinel type must be comparable to the iterator type with `operator!=`.
|
||||
|
||||
## Template parameters
|
||||
|
||||
@@ -43,6 +55,12 @@ static basic_json parse(IteratorType first, IteratorType last,
|
||||
- a pair of `std::string::iterator` or `std::vector<std::uint8_t>::iterator`
|
||||
- a pair of pointers such as `ptr` and `ptr + len`
|
||||
|
||||
`SentinelType`
|
||||
: a sentinel type compatible with `IteratorType` (different from `IteratorType` and comparable via `operator!=`), for instance.
|
||||
|
||||
- a custom sentinel type for C++20 ranges
|
||||
- `std::counted_iterator` with a different sentinel type
|
||||
|
||||
## Parameters
|
||||
|
||||
`i` (in)
|
||||
@@ -67,7 +85,7 @@ static basic_json parse(IteratorType first, IteratorType last,
|
||||
: iterator to the start of a character range
|
||||
|
||||
`last` (in)
|
||||
: iterator to the end of a character range
|
||||
: iterator to the end of a character range, or a sentinel value that compares equal to the end iterator with `operator!=`
|
||||
|
||||
## Return value
|
||||
|
||||
@@ -238,6 +256,7 @@ 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.
|
||||
- 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.
|
||||
- Added overload (3) for heterogeneous iterator+sentinel pairs (C++20 ranges support) in version 3.13.0.
|
||||
|
||||
!!! warning "Deprecation"
|
||||
|
||||
|
||||
@@ -18,15 +18,28 @@ static bool sax_parse(IteratorType first, IteratorType last,
|
||||
const bool strict = true,
|
||||
const bool ignore_comments = false,
|
||||
const bool ignore_trailing_commas = false);
|
||||
|
||||
// (3)
|
||||
template<class IteratorType, class SentinelType, class SAX>
|
||||
static bool sax_parse(IteratorType first, SentinelType last,
|
||||
SAX* sax,
|
||||
input_format_t format = input_format_t::json,
|
||||
const bool strict = true,
|
||||
const bool ignore_comments = false,
|
||||
const bool ignore_trailing_commas = false);
|
||||
```
|
||||
|
||||
Read from input and generate SAX events
|
||||
|
||||
1. Read from a compatible input.
|
||||
2. Read from a pair of character iterators
|
||||
2. Read from a pair of character iterators (same type)
|
||||
|
||||
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.
|
||||
3. Read from an iterator and a sentinel (different types, C++20 ranges support)
|
||||
|
||||
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. The sentinel type must be comparable to the iterator type with `operator!=`.
|
||||
|
||||
The SAX event lister must follow the interface of [`json_sax`](../json_sax/index.md).
|
||||
|
||||
@@ -43,9 +56,12 @@ The SAX event lister must follow the interface of [`json_sax`](../json_sax/index
|
||||
(as found via ADL or member functions, with semantics compatible to `std::begin` and `std::end`)
|
||||
|
||||
`IteratorType`
|
||||
: a compatible iterator type for overload (2); a pair of character iterators whose `value_type` is an integral type
|
||||
: a compatible iterator type for overloads (2) and (3); 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)
|
||||
|
||||
`SentinelType`
|
||||
: a sentinel type compatible with `IteratorType` (different from `IteratorType` and comparable via `operator!=`) for overload (3)
|
||||
|
||||
`SAX`
|
||||
: a class fulfilling the SAX event listener interface; see [`json_sax`](../json_sax/index.md)
|
||||
|
||||
@@ -76,7 +92,7 @@ The SAX event lister must follow the interface of [`json_sax`](../json_sax/index
|
||||
: iterator to the start of a character range
|
||||
|
||||
`last` (in)
|
||||
: iterator to the end of a character range
|
||||
: iterator to the end of a character range, or a sentinel value that compares equal to the end iterator with `operator!=`
|
||||
|
||||
## Return value
|
||||
|
||||
@@ -128,6 +144,7 @@ A UTF-8 byte order mark is silently ignored.
|
||||
- Ignoring comments via `ignore_comments` added in version 3.9.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.
|
||||
- Added overload (3) for heterogeneous iterator+sentinel pairs (C++20 ranges support) in version 3.13.0.
|
||||
|
||||
!!! warning "Deprecation"
|
||||
|
||||
|
||||
@@ -155,7 +155,9 @@ class input_stream_adapter
|
||||
|
||||
// General-purpose iterator-based adapter. It might not be as fast as
|
||||
// theoretically possible for some containers, but it is extremely versatile.
|
||||
template<typename IteratorType>
|
||||
// SentinelType defaults to IteratorType for backward compatibility, but may
|
||||
// be a different type (e.g., a C++20 sentinel or counted_iterator).
|
||||
template<typename IteratorType, typename SentinelType = IteratorType>
|
||||
class iterator_input_adapter
|
||||
{
|
||||
public:
|
||||
@@ -169,9 +171,10 @@ class iterator_input_adapter
|
||||
// in wide_string_input_adapter, which does not expose this).
|
||||
static constexpr bool supports_seek =
|
||||
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;
|
||||
|
||||
iterator_input_adapter(IteratorType first, IteratorType last)
|
||||
iterator_input_adapter(IteratorType first, SentinelType last)
|
||||
: begin(first), current(std::move(first)), end(std::move(last))
|
||||
{}
|
||||
|
||||
@@ -216,12 +219,14 @@ class iterator_input_adapter
|
||||
private:
|
||||
// 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
|
||||
// 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 =
|
||||
std::is_same<IteratorType, SentinelType>::value && (
|
||||
#if defined(__cpp_lib_concepts) && defined(JSON_HAS_CPP_20)
|
||||
std::contiguous_iterator<IteratorType> ||
|
||||
std::contiguous_iterator<IteratorType> ||
|
||||
#endif
|
||||
std::is_pointer<IteratorType>::value;
|
||||
std::is_pointer<IteratorType>::value);
|
||||
|
||||
// contiguous fast path: bulk copy the remaining range with std::memcpy
|
||||
template<class T>
|
||||
@@ -267,7 +272,7 @@ class iterator_input_adapter
|
||||
|
||||
IteratorType begin;
|
||||
IteratorType current;
|
||||
IteratorType end;
|
||||
SentinelType end;
|
||||
|
||||
template<typename BaseInputAdapter, size_t T>
|
||||
friend struct wide_string_input_helper;
|
||||
@@ -453,19 +458,43 @@ class wide_string_input_adapter
|
||||
std::size_t utf8_bytes_filled = 0;
|
||||
};
|
||||
|
||||
template<typename IteratorType, typename Enable = void>
|
||||
template<typename IteratorType, typename SentinelType = IteratorType, typename Enable = void>
|
||||
struct iterator_input_adapter_factory
|
||||
{
|
||||
using iterator_type = IteratorType;
|
||||
using sentinel_type = SentinelType;
|
||||
using char_type = typename std::iterator_traits<iterator_type>::value_type;
|
||||
using adapter_type = iterator_input_adapter<iterator_type>;
|
||||
using adapter_type = iterator_input_adapter<iterator_type, sentinel_type>;
|
||||
|
||||
static adapter_type create(IteratorType first, IteratorType last)
|
||||
static adapter_type create(IteratorType first, SentinelType 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 : std::integral_constant < bool,
|
||||
can_compare_ne_impl<IteratorType, SentinelType>::value ||
|
||||
can_compare_ne_reversed<IteratorType, SentinelType>::value > {};
|
||||
|
||||
template<typename T>
|
||||
struct is_iterator_of_multibyte
|
||||
{
|
||||
@@ -476,25 +505,38 @@ struct is_iterator_of_multibyte
|
||||
};
|
||||
};
|
||||
|
||||
template<typename IteratorType>
|
||||
struct iterator_input_adapter_factory<IteratorType, enable_if_t<is_iterator_of_multibyte<IteratorType>::value>>
|
||||
template<typename IteratorType, typename SentinelType>
|
||||
struct iterator_input_adapter_factory<IteratorType, SentinelType, enable_if_t<is_iterator_of_multibyte<IteratorType>::value>>
|
||||
{
|
||||
using iterator_type = IteratorType;
|
||||
using sentinel_type = SentinelType;
|
||||
using char_type = typename std::iterator_traits<iterator_type>::value_type;
|
||||
using base_adapter_type = iterator_input_adapter<iterator_type>;
|
||||
using base_adapter_type = iterator_input_adapter<iterator_type, sentinel_type>;
|
||||
using adapter_type = wide_string_input_adapter<base_adapter_type, char_type>;
|
||||
|
||||
static adapter_type create(IteratorType first, IteratorType last)
|
||||
static adapter_type create(IteratorType first, SentinelType last)
|
||||
{
|
||||
return adapter_type(base_adapter_type(std::move(first), std::move(last)));
|
||||
}
|
||||
};
|
||||
|
||||
// General purpose iterator-based input
|
||||
// General purpose iterator-based input (same-type iterators)
|
||||
template<typename IteratorType>
|
||||
typename iterator_input_adapter_factory<IteratorType>::adapter_type input_adapter(IteratorType first, IteratorType last)
|
||||
typename iterator_input_adapter_factory<IteratorType, IteratorType>::adapter_type input_adapter(IteratorType first, IteratorType last)
|
||||
{
|
||||
using factory_type = iterator_input_adapter_factory<IteratorType>;
|
||||
using factory_type = iterator_input_adapter_factory<IteratorType, IteratorType>;
|
||||
return factory_type::create(first, last);
|
||||
}
|
||||
|
||||
// General purpose iterator-based input (iterator+sentinel pair with different types)
|
||||
// Only enable for types that can be compared with !=
|
||||
template < typename IteratorType, typename SentinelType,
|
||||
typename = typename std::enable_if <
|
||||
!std::is_same<IteratorType, SentinelType>::value &&
|
||||
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>;
|
||||
return factory_type::create(first, last);
|
||||
}
|
||||
|
||||
|
||||
@@ -4099,6 +4099,24 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
return result;
|
||||
}
|
||||
|
||||
/// @brief deserialize from an iterator+sentinel pair (C++20 ranges support)
|
||||
/// @sa https://json.nlohmann.me/api/basic_json/parse/
|
||||
template<typename IteratorType, typename SentinelType>
|
||||
JSON_HEDLEY_WARN_UNUSED_RESULT
|
||||
static basic_json parse(IteratorType first,
|
||||
SentinelType last,
|
||||
parser_callback_t cb = nullptr,
|
||||
const bool allow_exceptions = true,
|
||||
const bool ignore_comments = false,
|
||||
const bool ignore_trailing_commas = false,
|
||||
typename std::enable_if < !std::is_same<IteratorType, SentinelType>::value &&
|
||||
detail::can_compare_ne<IteratorType, SentinelType>::value >::type* = nullptr)
|
||||
{
|
||||
basic_json result;
|
||||
parser(detail::input_adapter(std::move(first), std::move(last)), std::move(cb), allow_exceptions, ignore_comments, ignore_trailing_commas).parse(true, result); // cppcheck-suppress[accessMoved]
|
||||
return result;
|
||||
}
|
||||
|
||||
JSON_HEDLEY_WARN_UNUSED_RESULT
|
||||
JSON_HEDLEY_DEPRECATED_FOR(3.8.0, parse(ptr, ptr + len))
|
||||
static basic_json parse(detail::span_input_adapter&& i,
|
||||
@@ -4132,6 +4150,18 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
return parser(detail::input_adapter(std::move(first), std::move(last)), nullptr, false, ignore_comments, ignore_trailing_commas).accept(true);
|
||||
}
|
||||
|
||||
/// @brief check if the input is valid JSON (sentinel version)
|
||||
/// @sa https://json.nlohmann.me/api/basic_json/accept/
|
||||
template<typename IteratorType, typename SentinelType>
|
||||
static bool accept(IteratorType first, SentinelType last,
|
||||
const bool ignore_comments = false,
|
||||
const bool ignore_trailing_commas = false,
|
||||
typename std::enable_if < !std::is_same<IteratorType, SentinelType>::value &&
|
||||
detail::can_compare_ne<IteratorType, SentinelType>::value >::type* = nullptr)
|
||||
{
|
||||
return parser(detail::input_adapter(std::move(first), std::move(last)), nullptr, false, ignore_comments, ignore_trailing_commas).accept(true);
|
||||
}
|
||||
|
||||
JSON_HEDLEY_WARN_UNUSED_RESULT
|
||||
JSON_HEDLEY_DEPRECATED_FOR(3.8.0, accept(ptr, ptr + len))
|
||||
static bool accept(detail::span_input_adapter&& i,
|
||||
@@ -4173,6 +4203,24 @@ 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);
|
||||
}
|
||||
|
||||
/// @brief generate SAX events (sentinel version)
|
||||
/// @sa https://json.nlohmann.me/api/basic_json/sax_parse/
|
||||
template<class IteratorType, class SentinelType, class SAX>
|
||||
JSON_HEDLEY_NON_NULL(3)
|
||||
static bool sax_parse(IteratorType first, SentinelType last, SAX* sax,
|
||||
input_format_t format = input_format_t::json,
|
||||
const bool strict = true,
|
||||
const bool ignore_comments = false,
|
||||
const bool ignore_trailing_commas = false,
|
||||
typename std::enable_if < !std::is_same<IteratorType, SentinelType>::value &&
|
||||
detail::can_compare_ne<IteratorType, SentinelType>::value >::type* = nullptr)
|
||||
{
|
||||
auto ia = detail::input_adapter(std::move(first), std::move(last));
|
||||
return format == input_format_t::json
|
||||
? parser(std::move(ia), nullptr, true, ignore_comments, ignore_trailing_commas).sax_parse(sax, strict)
|
||||
: detail::binary_reader<basic_json, decltype(ia), SAX>(std::move(ia), format).sax_parse(format, sax, strict);
|
||||
}
|
||||
|
||||
/// @brief generate SAX events
|
||||
/// @sa https://json.nlohmann.me/api/basic_json/sax_parse/
|
||||
/// @deprecated This function is deprecated since 3.8.0 and will be removed in
|
||||
@@ -4477,6 +4525,24 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
return res ? result : basic_json(value_t::discarded);
|
||||
}
|
||||
|
||||
/// @brief create a JSON value from an input in CBOR format (sentinel version)
|
||||
/// @sa https://json.nlohmann.me/api/basic_json/from_cbor/
|
||||
template<typename IteratorType, typename SentinelType>
|
||||
JSON_HEDLEY_WARN_UNUSED_RESULT
|
||||
static basic_json from_cbor(IteratorType first, SentinelType last,
|
||||
const bool strict = true,
|
||||
const bool allow_exceptions = true,
|
||||
const cbor_tag_handler_t tag_handler = cbor_tag_handler_t::error,
|
||||
typename std::enable_if < !std::is_same<IteratorType, SentinelType>::value &&
|
||||
detail::can_compare_ne<IteratorType, SentinelType>::value >::type* = nullptr)
|
||||
{
|
||||
basic_json result;
|
||||
auto ia = detail::input_adapter(std::move(first), std::move(last));
|
||||
detail::json_sax_dom_parser<basic_json, decltype(ia)> sdp(result, allow_exceptions);
|
||||
const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::cbor).sax_parse(input_format_t::cbor, &sdp, strict, tag_handler); // cppcheck-suppress[accessMoved]
|
||||
return res ? result : basic_json(value_t::discarded);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
JSON_HEDLEY_WARN_UNUSED_RESULT
|
||||
JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_cbor(ptr, ptr + len))
|
||||
@@ -4533,6 +4599,23 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
return res ? result : basic_json(value_t::discarded);
|
||||
}
|
||||
|
||||
/// @brief create a JSON value from an input in MessagePack format (sentinel version)
|
||||
/// @sa https://json.nlohmann.me/api/basic_json/from_msgpack/
|
||||
template<typename IteratorType, typename SentinelType>
|
||||
JSON_HEDLEY_WARN_UNUSED_RESULT
|
||||
static basic_json from_msgpack(IteratorType first, SentinelType last,
|
||||
const bool strict = true,
|
||||
const bool allow_exceptions = true,
|
||||
typename std::enable_if < !std::is_same<IteratorType, SentinelType>::value &&
|
||||
detail::can_compare_ne<IteratorType, SentinelType>::value >::type* = nullptr)
|
||||
{
|
||||
basic_json result;
|
||||
auto ia = detail::input_adapter(std::move(first), std::move(last));
|
||||
detail::json_sax_dom_parser<basic_json, decltype(ia)> sdp(result, allow_exceptions);
|
||||
const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::msgpack).sax_parse(input_format_t::msgpack, &sdp, strict); // cppcheck-suppress[accessMoved]
|
||||
return res ? result : basic_json(value_t::discarded);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
JSON_HEDLEY_WARN_UNUSED_RESULT
|
||||
JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_msgpack(ptr, ptr + len))
|
||||
@@ -4587,6 +4670,23 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
return res ? result : basic_json(value_t::discarded);
|
||||
}
|
||||
|
||||
/// @brief create a JSON value from an input in UBJSON format (sentinel version)
|
||||
/// @sa https://json.nlohmann.me/api/basic_json/from_ubjson/
|
||||
template<typename IteratorType, typename SentinelType>
|
||||
JSON_HEDLEY_WARN_UNUSED_RESULT
|
||||
static basic_json from_ubjson(IteratorType first, SentinelType last,
|
||||
const bool strict = true,
|
||||
const bool allow_exceptions = true,
|
||||
typename std::enable_if < !std::is_same<IteratorType, SentinelType>::value &&
|
||||
detail::can_compare_ne<IteratorType, SentinelType>::value >::type* = nullptr)
|
||||
{
|
||||
basic_json result;
|
||||
auto ia = detail::input_adapter(std::move(first), std::move(last));
|
||||
detail::json_sax_dom_parser<basic_json, decltype(ia)> sdp(result, allow_exceptions);
|
||||
const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::ubjson).sax_parse(input_format_t::ubjson, &sdp, strict); // cppcheck-suppress[accessMoved]
|
||||
return res ? result : basic_json(value_t::discarded);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
JSON_HEDLEY_WARN_UNUSED_RESULT
|
||||
JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_ubjson(ptr, ptr + len))
|
||||
@@ -4641,6 +4741,23 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
return res ? result : basic_json(value_t::discarded);
|
||||
}
|
||||
|
||||
/// @brief create a JSON value from an input in BJData format (sentinel version)
|
||||
/// @sa https://json.nlohmann.me/api/basic_json/from_bjdata/
|
||||
template<typename IteratorType, typename SentinelType>
|
||||
JSON_HEDLEY_WARN_UNUSED_RESULT
|
||||
static basic_json from_bjdata(IteratorType first, SentinelType last,
|
||||
const bool strict = true,
|
||||
const bool allow_exceptions = true,
|
||||
typename std::enable_if < !std::is_same<IteratorType, SentinelType>::value &&
|
||||
detail::can_compare_ne<IteratorType, SentinelType>::value >::type* = nullptr)
|
||||
{
|
||||
basic_json result;
|
||||
auto ia = detail::input_adapter(std::move(first), std::move(last));
|
||||
detail::json_sax_dom_parser<basic_json, decltype(ia)> sdp(result, allow_exceptions);
|
||||
const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::bjdata).sax_parse(input_format_t::bjdata, &sdp, strict); // cppcheck-suppress[accessMoved]
|
||||
return res ? result : basic_json(value_t::discarded);
|
||||
}
|
||||
|
||||
/// @brief create a JSON value from an input in BSON format
|
||||
/// @sa https://json.nlohmann.me/api/basic_json/from_bson/
|
||||
template<typename InputType>
|
||||
@@ -4671,6 +4788,23 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
return res ? result : basic_json(value_t::discarded);
|
||||
}
|
||||
|
||||
/// @brief create a JSON value from an input in BSON format (sentinel version)
|
||||
/// @sa https://json.nlohmann.me/api/basic_json/from_bson/
|
||||
template<typename IteratorType, typename SentinelType>
|
||||
JSON_HEDLEY_WARN_UNUSED_RESULT
|
||||
static basic_json from_bson(IteratorType first, SentinelType last,
|
||||
const bool strict = true,
|
||||
const bool allow_exceptions = true,
|
||||
typename std::enable_if < !std::is_same<IteratorType, SentinelType>::value &&
|
||||
detail::can_compare_ne<IteratorType, SentinelType>::value >::type* = nullptr)
|
||||
{
|
||||
basic_json result;
|
||||
auto ia = detail::input_adapter(std::move(first), std::move(last));
|
||||
detail::json_sax_dom_parser<basic_json, decltype(ia)> sdp(result, allow_exceptions);
|
||||
const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::bson).sax_parse(input_format_t::bson, &sdp, strict); // cppcheck-suppress[accessMoved]
|
||||
return res ? result : basic_json(value_t::discarded);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
JSON_HEDLEY_WARN_UNUSED_RESULT
|
||||
JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_bson(ptr, ptr + len))
|
||||
|
||||
@@ -6992,7 +6992,9 @@ class input_stream_adapter
|
||||
|
||||
// General-purpose iterator-based adapter. It might not be as fast as
|
||||
// theoretically possible for some containers, but it is extremely versatile.
|
||||
template<typename IteratorType>
|
||||
// SentinelType defaults to IteratorType for backward compatibility, but may
|
||||
// be a different type (e.g., a C++20 sentinel or counted_iterator).
|
||||
template<typename IteratorType, typename SentinelType = IteratorType>
|
||||
class iterator_input_adapter
|
||||
{
|
||||
public:
|
||||
@@ -7006,9 +7008,10 @@ class iterator_input_adapter
|
||||
// in wide_string_input_adapter, which does not expose this).
|
||||
static constexpr bool supports_seek =
|
||||
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;
|
||||
|
||||
iterator_input_adapter(IteratorType first, IteratorType last)
|
||||
iterator_input_adapter(IteratorType first, SentinelType last)
|
||||
: begin(first), current(std::move(first)), end(std::move(last))
|
||||
{}
|
||||
|
||||
@@ -7053,12 +7056,14 @@ class iterator_input_adapter
|
||||
private:
|
||||
// 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
|
||||
// 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 =
|
||||
std::is_same<IteratorType, SentinelType>::value && (
|
||||
#if defined(__cpp_lib_concepts) && defined(JSON_HAS_CPP_20)
|
||||
std::contiguous_iterator<IteratorType> ||
|
||||
std::contiguous_iterator<IteratorType> ||
|
||||
#endif
|
||||
std::is_pointer<IteratorType>::value;
|
||||
std::is_pointer<IteratorType>::value);
|
||||
|
||||
// contiguous fast path: bulk copy the remaining range with std::memcpy
|
||||
template<class T>
|
||||
@@ -7104,7 +7109,7 @@ class iterator_input_adapter
|
||||
|
||||
IteratorType begin;
|
||||
IteratorType current;
|
||||
IteratorType end;
|
||||
SentinelType end;
|
||||
|
||||
template<typename BaseInputAdapter, size_t T>
|
||||
friend struct wide_string_input_helper;
|
||||
@@ -7290,19 +7295,43 @@ class wide_string_input_adapter
|
||||
std::size_t utf8_bytes_filled = 0;
|
||||
};
|
||||
|
||||
template<typename IteratorType, typename Enable = void>
|
||||
template<typename IteratorType, typename SentinelType = IteratorType, typename Enable = void>
|
||||
struct iterator_input_adapter_factory
|
||||
{
|
||||
using iterator_type = IteratorType;
|
||||
using sentinel_type = SentinelType;
|
||||
using char_type = typename std::iterator_traits<iterator_type>::value_type;
|
||||
using adapter_type = iterator_input_adapter<iterator_type>;
|
||||
using adapter_type = iterator_input_adapter<iterator_type, sentinel_type>;
|
||||
|
||||
static adapter_type create(IteratorType first, IteratorType last)
|
||||
static adapter_type create(IteratorType first, SentinelType 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 : std::integral_constant < bool,
|
||||
can_compare_ne_impl<IteratorType, SentinelType>::value ||
|
||||
can_compare_ne_reversed<IteratorType, SentinelType>::value > {};
|
||||
|
||||
template<typename T>
|
||||
struct is_iterator_of_multibyte
|
||||
{
|
||||
@@ -7313,25 +7342,38 @@ struct is_iterator_of_multibyte
|
||||
};
|
||||
};
|
||||
|
||||
template<typename IteratorType>
|
||||
struct iterator_input_adapter_factory<IteratorType, enable_if_t<is_iterator_of_multibyte<IteratorType>::value>>
|
||||
template<typename IteratorType, typename SentinelType>
|
||||
struct iterator_input_adapter_factory<IteratorType, SentinelType, enable_if_t<is_iterator_of_multibyte<IteratorType>::value>>
|
||||
{
|
||||
using iterator_type = IteratorType;
|
||||
using sentinel_type = SentinelType;
|
||||
using char_type = typename std::iterator_traits<iterator_type>::value_type;
|
||||
using base_adapter_type = iterator_input_adapter<iterator_type>;
|
||||
using base_adapter_type = iterator_input_adapter<iterator_type, sentinel_type>;
|
||||
using adapter_type = wide_string_input_adapter<base_adapter_type, char_type>;
|
||||
|
||||
static adapter_type create(IteratorType first, IteratorType last)
|
||||
static adapter_type create(IteratorType first, SentinelType last)
|
||||
{
|
||||
return adapter_type(base_adapter_type(std::move(first), std::move(last)));
|
||||
}
|
||||
};
|
||||
|
||||
// General purpose iterator-based input
|
||||
// General purpose iterator-based input (same-type iterators)
|
||||
template<typename IteratorType>
|
||||
typename iterator_input_adapter_factory<IteratorType>::adapter_type input_adapter(IteratorType first, IteratorType last)
|
||||
typename iterator_input_adapter_factory<IteratorType, IteratorType>::adapter_type input_adapter(IteratorType first, IteratorType last)
|
||||
{
|
||||
using factory_type = iterator_input_adapter_factory<IteratorType>;
|
||||
using factory_type = iterator_input_adapter_factory<IteratorType, IteratorType>;
|
||||
return factory_type::create(first, last);
|
||||
}
|
||||
|
||||
// General purpose iterator-based input (iterator+sentinel pair with different types)
|
||||
// Only enable for types that can be compared with !=
|
||||
template < typename IteratorType, typename SentinelType,
|
||||
typename = typename std::enable_if <
|
||||
!std::is_same<IteratorType, SentinelType>::value &&
|
||||
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>;
|
||||
return factory_type::create(first, last);
|
||||
}
|
||||
|
||||
@@ -24950,6 +24992,24 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
return result;
|
||||
}
|
||||
|
||||
/// @brief deserialize from an iterator+sentinel pair (C++20 ranges support)
|
||||
/// @sa https://json.nlohmann.me/api/basic_json/parse/
|
||||
template<typename IteratorType, typename SentinelType>
|
||||
JSON_HEDLEY_WARN_UNUSED_RESULT
|
||||
static basic_json parse(IteratorType first,
|
||||
SentinelType last,
|
||||
parser_callback_t cb = nullptr,
|
||||
const bool allow_exceptions = true,
|
||||
const bool ignore_comments = false,
|
||||
const bool ignore_trailing_commas = false,
|
||||
typename std::enable_if < !std::is_same<IteratorType, SentinelType>::value &&
|
||||
detail::can_compare_ne<IteratorType, SentinelType>::value >::type* = nullptr)
|
||||
{
|
||||
basic_json result;
|
||||
parser(detail::input_adapter(std::move(first), std::move(last)), std::move(cb), allow_exceptions, ignore_comments, ignore_trailing_commas).parse(true, result); // cppcheck-suppress[accessMoved]
|
||||
return result;
|
||||
}
|
||||
|
||||
JSON_HEDLEY_WARN_UNUSED_RESULT
|
||||
JSON_HEDLEY_DEPRECATED_FOR(3.8.0, parse(ptr, ptr + len))
|
||||
static basic_json parse(detail::span_input_adapter&& i,
|
||||
@@ -24983,6 +25043,18 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
return parser(detail::input_adapter(std::move(first), std::move(last)), nullptr, false, ignore_comments, ignore_trailing_commas).accept(true);
|
||||
}
|
||||
|
||||
/// @brief check if the input is valid JSON (sentinel version)
|
||||
/// @sa https://json.nlohmann.me/api/basic_json/accept/
|
||||
template<typename IteratorType, typename SentinelType>
|
||||
static bool accept(IteratorType first, SentinelType last,
|
||||
const bool ignore_comments = false,
|
||||
const bool ignore_trailing_commas = false,
|
||||
typename std::enable_if < !std::is_same<IteratorType, SentinelType>::value &&
|
||||
detail::can_compare_ne<IteratorType, SentinelType>::value >::type* = nullptr)
|
||||
{
|
||||
return parser(detail::input_adapter(std::move(first), std::move(last)), nullptr, false, ignore_comments, ignore_trailing_commas).accept(true);
|
||||
}
|
||||
|
||||
JSON_HEDLEY_WARN_UNUSED_RESULT
|
||||
JSON_HEDLEY_DEPRECATED_FOR(3.8.0, accept(ptr, ptr + len))
|
||||
static bool accept(detail::span_input_adapter&& i,
|
||||
@@ -25024,6 +25096,24 @@ 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);
|
||||
}
|
||||
|
||||
/// @brief generate SAX events (sentinel version)
|
||||
/// @sa https://json.nlohmann.me/api/basic_json/sax_parse/
|
||||
template<class IteratorType, class SentinelType, class SAX>
|
||||
JSON_HEDLEY_NON_NULL(3)
|
||||
static bool sax_parse(IteratorType first, SentinelType last, SAX* sax,
|
||||
input_format_t format = input_format_t::json,
|
||||
const bool strict = true,
|
||||
const bool ignore_comments = false,
|
||||
const bool ignore_trailing_commas = false,
|
||||
typename std::enable_if < !std::is_same<IteratorType, SentinelType>::value &&
|
||||
detail::can_compare_ne<IteratorType, SentinelType>::value >::type* = nullptr)
|
||||
{
|
||||
auto ia = detail::input_adapter(std::move(first), std::move(last));
|
||||
return format == input_format_t::json
|
||||
? parser(std::move(ia), nullptr, true, ignore_comments, ignore_trailing_commas).sax_parse(sax, strict)
|
||||
: detail::binary_reader<basic_json, decltype(ia), SAX>(std::move(ia), format).sax_parse(format, sax, strict);
|
||||
}
|
||||
|
||||
/// @brief generate SAX events
|
||||
/// @sa https://json.nlohmann.me/api/basic_json/sax_parse/
|
||||
/// @deprecated This function is deprecated since 3.8.0 and will be removed in
|
||||
@@ -25328,6 +25418,24 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
return res ? result : basic_json(value_t::discarded);
|
||||
}
|
||||
|
||||
/// @brief create a JSON value from an input in CBOR format (sentinel version)
|
||||
/// @sa https://json.nlohmann.me/api/basic_json/from_cbor/
|
||||
template<typename IteratorType, typename SentinelType>
|
||||
JSON_HEDLEY_WARN_UNUSED_RESULT
|
||||
static basic_json from_cbor(IteratorType first, SentinelType last,
|
||||
const bool strict = true,
|
||||
const bool allow_exceptions = true,
|
||||
const cbor_tag_handler_t tag_handler = cbor_tag_handler_t::error,
|
||||
typename std::enable_if < !std::is_same<IteratorType, SentinelType>::value &&
|
||||
detail::can_compare_ne<IteratorType, SentinelType>::value >::type* = nullptr)
|
||||
{
|
||||
basic_json result;
|
||||
auto ia = detail::input_adapter(std::move(first), std::move(last));
|
||||
detail::json_sax_dom_parser<basic_json, decltype(ia)> sdp(result, allow_exceptions);
|
||||
const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::cbor).sax_parse(input_format_t::cbor, &sdp, strict, tag_handler); // cppcheck-suppress[accessMoved]
|
||||
return res ? result : basic_json(value_t::discarded);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
JSON_HEDLEY_WARN_UNUSED_RESULT
|
||||
JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_cbor(ptr, ptr + len))
|
||||
@@ -25384,6 +25492,23 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
return res ? result : basic_json(value_t::discarded);
|
||||
}
|
||||
|
||||
/// @brief create a JSON value from an input in MessagePack format (sentinel version)
|
||||
/// @sa https://json.nlohmann.me/api/basic_json/from_msgpack/
|
||||
template<typename IteratorType, typename SentinelType>
|
||||
JSON_HEDLEY_WARN_UNUSED_RESULT
|
||||
static basic_json from_msgpack(IteratorType first, SentinelType last,
|
||||
const bool strict = true,
|
||||
const bool allow_exceptions = true,
|
||||
typename std::enable_if < !std::is_same<IteratorType, SentinelType>::value &&
|
||||
detail::can_compare_ne<IteratorType, SentinelType>::value >::type* = nullptr)
|
||||
{
|
||||
basic_json result;
|
||||
auto ia = detail::input_adapter(std::move(first), std::move(last));
|
||||
detail::json_sax_dom_parser<basic_json, decltype(ia)> sdp(result, allow_exceptions);
|
||||
const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::msgpack).sax_parse(input_format_t::msgpack, &sdp, strict); // cppcheck-suppress[accessMoved]
|
||||
return res ? result : basic_json(value_t::discarded);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
JSON_HEDLEY_WARN_UNUSED_RESULT
|
||||
JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_msgpack(ptr, ptr + len))
|
||||
@@ -25438,6 +25563,23 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
return res ? result : basic_json(value_t::discarded);
|
||||
}
|
||||
|
||||
/// @brief create a JSON value from an input in UBJSON format (sentinel version)
|
||||
/// @sa https://json.nlohmann.me/api/basic_json/from_ubjson/
|
||||
template<typename IteratorType, typename SentinelType>
|
||||
JSON_HEDLEY_WARN_UNUSED_RESULT
|
||||
static basic_json from_ubjson(IteratorType first, SentinelType last,
|
||||
const bool strict = true,
|
||||
const bool allow_exceptions = true,
|
||||
typename std::enable_if < !std::is_same<IteratorType, SentinelType>::value &&
|
||||
detail::can_compare_ne<IteratorType, SentinelType>::value >::type* = nullptr)
|
||||
{
|
||||
basic_json result;
|
||||
auto ia = detail::input_adapter(std::move(first), std::move(last));
|
||||
detail::json_sax_dom_parser<basic_json, decltype(ia)> sdp(result, allow_exceptions);
|
||||
const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::ubjson).sax_parse(input_format_t::ubjson, &sdp, strict); // cppcheck-suppress[accessMoved]
|
||||
return res ? result : basic_json(value_t::discarded);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
JSON_HEDLEY_WARN_UNUSED_RESULT
|
||||
JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_ubjson(ptr, ptr + len))
|
||||
@@ -25492,6 +25634,23 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
return res ? result : basic_json(value_t::discarded);
|
||||
}
|
||||
|
||||
/// @brief create a JSON value from an input in BJData format (sentinel version)
|
||||
/// @sa https://json.nlohmann.me/api/basic_json/from_bjdata/
|
||||
template<typename IteratorType, typename SentinelType>
|
||||
JSON_HEDLEY_WARN_UNUSED_RESULT
|
||||
static basic_json from_bjdata(IteratorType first, SentinelType last,
|
||||
const bool strict = true,
|
||||
const bool allow_exceptions = true,
|
||||
typename std::enable_if < !std::is_same<IteratorType, SentinelType>::value &&
|
||||
detail::can_compare_ne<IteratorType, SentinelType>::value >::type* = nullptr)
|
||||
{
|
||||
basic_json result;
|
||||
auto ia = detail::input_adapter(std::move(first), std::move(last));
|
||||
detail::json_sax_dom_parser<basic_json, decltype(ia)> sdp(result, allow_exceptions);
|
||||
const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::bjdata).sax_parse(input_format_t::bjdata, &sdp, strict); // cppcheck-suppress[accessMoved]
|
||||
return res ? result : basic_json(value_t::discarded);
|
||||
}
|
||||
|
||||
/// @brief create a JSON value from an input in BSON format
|
||||
/// @sa https://json.nlohmann.me/api/basic_json/from_bson/
|
||||
template<typename InputType>
|
||||
@@ -25522,6 +25681,23 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
return res ? result : basic_json(value_t::discarded);
|
||||
}
|
||||
|
||||
/// @brief create a JSON value from an input in BSON format (sentinel version)
|
||||
/// @sa https://json.nlohmann.me/api/basic_json/from_bson/
|
||||
template<typename IteratorType, typename SentinelType>
|
||||
JSON_HEDLEY_WARN_UNUSED_RESULT
|
||||
static basic_json from_bson(IteratorType first, SentinelType last,
|
||||
const bool strict = true,
|
||||
const bool allow_exceptions = true,
|
||||
typename std::enable_if < !std::is_same<IteratorType, SentinelType>::value &&
|
||||
detail::can_compare_ne<IteratorType, SentinelType>::value >::type* = nullptr)
|
||||
{
|
||||
basic_json result;
|
||||
auto ia = detail::input_adapter(std::move(first), std::move(last));
|
||||
detail::json_sax_dom_parser<basic_json, decltype(ia)> sdp(result, allow_exceptions);
|
||||
const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::bson).sax_parse(input_format_t::bson, &sdp, strict); // cppcheck-suppress[accessMoved]
|
||||
return res ? result : basic_json(value_t::discarded);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
JSON_HEDLEY_WARN_UNUSED_RESULT
|
||||
JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_bson(ptr, ptr + len))
|
||||
|
||||
@@ -30,4 +30,20 @@ inline std::vector<std::uint8_t> read_binary_file(const std::string& filename)
|
||||
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
|
||||
struct istreambuf_sentinel
|
||||
{
|
||||
friend bool operator!=(const std::istreambuf_iterator<char>& it, const istreambuf_sentinel&) noexcept
|
||||
{
|
||||
return it != std::istreambuf_iterator<char>();
|
||||
}
|
||||
|
||||
friend bool operator!=(const istreambuf_sentinel&, const std::istreambuf_iterator<char>& it) noexcept
|
||||
{
|
||||
return it != std::istreambuf_iterator<char>();
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace utils
|
||||
|
||||
@@ -3699,6 +3699,15 @@ 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);
|
||||
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)
|
||||
TEST_CASE("all BJData first bytes")
|
||||
{
|
||||
|
||||
@@ -1208,6 +1208,25 @@ TEST_CASE("BSON numerical data")
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("Parse BSON directly from a file using iterator and sentinel")
|
||||
{
|
||||
const json j = {{"key", "value"}, {"number", 42}};
|
||||
std::vector<std::uint8_t> bson_bytes;
|
||||
json::to_bson(j, bson_bytes);
|
||||
|
||||
{
|
||||
std::ofstream file("test_bson_sentinel.bson", std::ios::binary);
|
||||
file.write(reinterpret_cast<const char*>(bson_bytes.data()), static_cast<std::streamsize>(bson_bytes.size()));
|
||||
}
|
||||
|
||||
std::ifstream file("test_bson_sentinel.bson", std::ios::binary);
|
||||
std::istreambuf_iterator<char> first(file);
|
||||
const json parsed = json::from_bson(first, utils::istreambuf_sentinel{});
|
||||
CHECK(parsed == j);
|
||||
|
||||
static_cast<void>(std::remove("test_bson_sentinel.bson"));
|
||||
}
|
||||
|
||||
TEST_CASE("BSON roundtrips" * doctest::skip())
|
||||
{
|
||||
SECTION("reference files")
|
||||
|
||||
@@ -1921,6 +1921,15 @@ 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);
|
||||
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)
|
||||
TEST_CASE("CBOR regressions")
|
||||
{
|
||||
|
||||
@@ -1641,6 +1641,15 @@ 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);
|
||||
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())
|
||||
{
|
||||
SECTION("input from msgpack-python")
|
||||
|
||||
@@ -2393,6 +2393,15 @@ 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);
|
||||
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)
|
||||
TEST_CASE("all UBJSON first bytes")
|
||||
{
|
||||
|
||||
@@ -168,4 +168,40 @@ TEST_CASE("Custom iterator")
|
||||
CHECK(as_json.at(3) == 4);
|
||||
}
|
||||
|
||||
// Custom sentinel type for testing heterogeneous iterator+sentinel support
|
||||
struct CustomSentinel
|
||||
{
|
||||
const char* end_ptr;
|
||||
|
||||
// Support both directions for != comparison
|
||||
friend bool operator!=(const char* it, const CustomSentinel& sentinel)
|
||||
{
|
||||
return it != sentinel.end_ptr;
|
||||
}
|
||||
|
||||
friend bool operator!=(const CustomSentinel& sentinel, const char* it)
|
||||
{
|
||||
return it != sentinel.end_ptr;
|
||||
}
|
||||
};
|
||||
|
||||
TEST_CASE("Parse with heterogeneous iterator and sentinel types")
|
||||
{
|
||||
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
|
||||
|
||||
Reference in New Issue
Block a user