mirror of
https://github.com/nlohmann/json.git
synced 2026-10-27 00:08:55 +00:00
Compare commits
3
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d2e05c8b45 | ||
|
|
d1566fe9e8 | ||
|
|
3351a8795b |
No files matched your search
@@ -163,9 +163,9 @@ jobs:
|
||||
python3 $GENERATOR --list-tags
|
||||
TAG_COUNT=$(python3 $GENERATOR --list-tags | wc -l)
|
||||
|
||||
python3 $GENERATOR --abi-tags diag,_dp,_ns --abi-tags _diag --output $RUNNER_TEMP/abi_tags.natvis
|
||||
grep -q '<!-- Namespace nlohmann::json_abi_diag_dp_ns -->' $RUNNER_TEMP/abi_tags.natvis
|
||||
grep -q '<!-- Namespace nlohmann::json_abi_diag_dp_ns_v[0-9_]* -->' $RUNNER_TEMP/abi_tags.natvis
|
||||
python3 $GENERATOR --abi-tags diag,_dp,_vns --abi-tags _diag --output $RUNNER_TEMP/abi_tags.natvis
|
||||
grep -q '<!-- Namespace nlohmann::json_abi_diag_dp_vns -->' $RUNNER_TEMP/abi_tags.natvis
|
||||
grep -q '<!-- Namespace nlohmann::json_abi_diag_dp_vns_v[0-9_]* -->' $RUNNER_TEMP/abi_tags.natvis
|
||||
test $(grep -c '<!-- Namespace ' $RUNNER_TEMP/abi_tags.natvis) -eq $(( $(grep -c '<!-- Namespace ' nlohmann_json.natvis) + 2 ))
|
||||
|
||||
python3 $GENERATOR --all --output $RUNNER_TEMP/all.natvis
|
||||
|
||||
@@ -90,7 +90,6 @@ cc_library(
|
||||
"include/nlohmann/detail/view/simd.hpp",
|
||||
"include/nlohmann/detail/view/string_ref.hpp",
|
||||
"include/nlohmann/detail/view/value.hpp",
|
||||
"include/nlohmann/detail/view/view_mode.hpp",
|
||||
"include/nlohmann/json.hpp",
|
||||
"include/nlohmann/json_fwd.hpp",
|
||||
"include/nlohmann/json_literals.hpp",
|
||||
|
||||
@@ -309,7 +309,7 @@ The "Check amalgamation" workflow fails if the file is out of date.
|
||||
|
||||
The file covers the namespace variants with up to two ABI tags. A Natvis file for other configurations can be
|
||||
generated with the `--abi-tags` or `--all` options, for example
|
||||
`make natvis NATVIS_ARGS="--abi-tags _diag,_dp,_ns --output my_nlohmann_json.natvis"`; see
|
||||
`make natvis NATVIS_ARGS="--abi-tags _diag,_dp,_vns --output my_nlohmann_json.natvis"`; see
|
||||
[`tools/generate_natvis`](tools/generate_natvis/README.md). With MSVC, CMake adds the file to the `nlohmann_json`
|
||||
target and installs it.
|
||||
|
||||
|
||||
@@ -120,7 +120,7 @@ $(AMALGAMATED_VIEW_FILE): $(SRCS)
|
||||
tools/amalgamate/amalgamate.py -c tools/amalgamate/config_json_view.json -s . --verbose=yes
|
||||
|
||||
NATVIS_VENV=tools/generate_natvis/venv
|
||||
# extra options for generate_natvis.py, e.g. NATVIS_ARGS="--abi-tags _diag,_dp,_ns --output my.natvis"
|
||||
# extra options for generate_natvis.py, e.g. NATVIS_ARGS="--abi-tags _diag,_dp,_vns --output my.natvis"
|
||||
NATVIS_ARGS=
|
||||
|
||||
# regenerate nlohmann_json.natvis from the ABI tags and version in include/nlohmann/detail/abi_macros.hpp
|
||||
|
||||
@@ -90,7 +90,8 @@ Strong exception safety: if an exception occurs, the original value stays intact
|
||||
1. Constant.
|
||||
2. Logarithmic in the size of the container.
|
||||
3. Logarithmic in the size of the container.
|
||||
4. Logarithmic in the size of the container.
|
||||
4. Linear in the number of reference tokens of `ptr`; for each of them, logarithmic in the size of the object, or
|
||||
constant for an array.
|
||||
|
||||
## Notes
|
||||
|
||||
|
||||
@@ -90,9 +90,8 @@ type `#!cpp binary_t*` must be dereferenced.
|
||||
|
||||
- MessagePack
|
||||
- If a subtype is given and the binary array contains exactly 1, 2, 4, 8, or 16 elements, the fixext family (fixext1,
|
||||
fixext2, fixext4, fixext8, fixext16) is used. For other sizes, the ext family (ext8, ext16, ext32) is used. The
|
||||
subtype is then written as the signed 8-bit ext type: subtypes 128 to 255 map to the negative (reserved) ext
|
||||
types, and on reading the ext type is exposed as an unsigned subtype from 0 to 255.
|
||||
fixext2, fixext4, fixext8) is used. For other sizes, the ext family (ext8, ext16, ext32) is used. The subtype is
|
||||
then added as a signed 8-bit integer.
|
||||
- If no subtype is given, the bin family (bin8, bin16, bin32) is used.
|
||||
|
||||
- BSON
|
||||
|
||||
@@ -1,48 +0,0 @@
|
||||
# <small>nlohmann::basic_json::</small>bjdata_version_t
|
||||
|
||||
```cpp
|
||||
enum class bjdata_version_t
|
||||
{
|
||||
draft2,
|
||||
draft3
|
||||
};
|
||||
```
|
||||
|
||||
This enumeration is used in [`to_bjdata`](to_bjdata.md) to choose the version of the BJData specification to write:
|
||||
|
||||
draft2
|
||||
: BJData Draft 2 (the default). Binary values are written as arrays of `U` integers, and ND-arrays with
|
||||
`"_ArrayType_": "byte"` are written as regular objects, since the `B` marker is not part of Draft 2.
|
||||
|
||||
draft3
|
||||
: BJData Draft 3. Binary values are written as `B` elements: as an optimized binary array (`[$B#`) if both `use_size`
|
||||
and `use_type` are set, and as an array of `B`-prefixed elements otherwise. ND-arrays with
|
||||
`"_ArrayType_": "byte"` are written as packed arrays (`[$B#[...]`).
|
||||
|
||||
Only the writer is affected by the version. [`from_bjdata`](from_bjdata.md) reads the markers of both drafts.
|
||||
|
||||
## Examples
|
||||
|
||||
??? example
|
||||
|
||||
The example below shows how the different values of the `bjdata_version_t` influence the serialization of a binary
|
||||
value with [`to_bjdata`](to_bjdata.md).
|
||||
|
||||
```cpp
|
||||
--8<-- "examples/bjdata_version_t.cpp"
|
||||
```
|
||||
|
||||
Output:
|
||||
|
||||
```json
|
||||
--8<-- "examples/bjdata_version_t.output"
|
||||
```
|
||||
|
||||
## See also
|
||||
|
||||
- [to_bjdata](to_bjdata.md) serializes a JSON value to BJData
|
||||
- [BJData](../../features/binary_formats/bjdata.md) - the article on the BJData format
|
||||
|
||||
## Version history
|
||||
|
||||
- Added in version 3.12.0.
|
||||
@@ -15,13 +15,11 @@ error
|
||||
: report a parse error in case of a tag (the `from_cbor` overloads throw a `parse_error` exception by default)
|
||||
|
||||
ignore
|
||||
: ignore tags (also in front of a text string map key)
|
||||
: ignore tags
|
||||
|
||||
store
|
||||
: store tagged byte strings (for bytes 0xd8..0xdb) as binary values with the tag as subtype; other tagged values are
|
||||
read as if the tag were ignored. If several tags precede a byte string, only the tag directly in front of it is
|
||||
stored, and only when it has the form 0xd8..0xdb (a tag 0..23 written as 0xc0..0xd7 is skipped). Tags in front of a
|
||||
text string map key are skipped.
|
||||
read as if the tag were ignored. If several tags precede a byte string, only the innermost one is stored.
|
||||
|
||||
## Examples
|
||||
|
||||
|
||||
@@ -82,11 +82,8 @@ Strong guarantee: if an exception is thrown, there are no changes in the JSON va
|
||||
- Throws [parse_error.112](../../home/exceptions.md#jsonexceptionparse_error112) if a parse error occurs
|
||||
- Throws [parse_error.113](../../home/exceptions.md#jsonexceptionparse_error113) if a string could not be parsed
|
||||
successfully, or if a string value or object key is not valid UTF-8 and `error_handler` is `strict`
|
||||
- Throws [parse_error.115](../../home/exceptions.md#jsonexceptionparse_error115) if the text of a high-precision
|
||||
number (`H`) is not a valid number
|
||||
- Throws [out_of_range.408](../../home/exceptions.md#jsonexceptionout_of_range408) if the size of an optimized container
|
||||
cannot be represented by `std::size_t` or exceeds the container's `max_size()`, or if the product of the dimensions of
|
||||
an n-dimensional array overflows
|
||||
or n-dimensional array cannot be represented by `std::size_t`
|
||||
|
||||
## Complexity
|
||||
|
||||
|
||||
@@ -74,11 +74,6 @@ Strong guarantee: if an exception is thrown, there are no changes in the JSON va
|
||||
- Throws [parse_error.112](../../home/exceptions.md#jsonexceptionparse_error112) if a parse error occurs, for instance
|
||||
an invalid byte, a string that is not valid UTF-8, or an object key that is not a string
|
||||
|
||||
The UTF-8 validity of strings is always checked, independent of
|
||||
[`JSON_STRICT_BINARY_UTF8`](../macros/json_strict_binary_utf8.md), because the end of a BON8 string is determined from
|
||||
its encoding. Duplicate object keys are accepted; the last value wins (see
|
||||
[BON8](../../features/binary_formats/bon8.md)).
|
||||
|
||||
## Complexity
|
||||
|
||||
Linear in the size of the input.
|
||||
|
||||
@@ -80,8 +80,7 @@ Strong guarantee: if an exception is thrown, there are no changes in the JSON va
|
||||
- Throws [`parse_error.110`](../../home/exceptions.md#jsonexceptionparse_error110) if the given input ends prematurely or
|
||||
the end of the input was not reached when `strict` was set to true
|
||||
- Throws [`parse_error.112`](../../home/exceptions.md#jsonexceptionparse_error112) if a parse error occurs (e.g., an
|
||||
invalid string or byte array length, an invalid inner length of a binary value with subtype `0x02`, or a document size
|
||||
that does not match the content; `strict` does not affect the document size checks)
|
||||
invalid string or byte array length)
|
||||
- Throws [`parse_error.114`](../../home/exceptions.md#jsonexceptionparse_error114) if an unsupported BSON record type is
|
||||
encountered
|
||||
- Throws [`parse_error.113`](../../home/exceptions.md#jsonexceptionparse_error113) if a string value or object key is
|
||||
|
||||
@@ -32,10 +32,8 @@ The exact mapping and its limitations are described on a [dedicated page](../../
|
||||
|
||||
- an `std::istream` object
|
||||
- a `FILE` pointer
|
||||
- a C-style array of characters (its terminating NUL is read as trailing data: `parse_error.110` unless `strict` is
|
||||
`false`)
|
||||
- a pointer to a null-terminated string of single byte characters (read up to the first 0x00 byte, which is a valid
|
||||
CBOR byte)
|
||||
- a C-style array of characters
|
||||
- a pointer to a null-terminated string of single byte characters
|
||||
- a container `obj` for which `begin(obj)` and `end(obj)` produce a valid pair of iterators
|
||||
(as found via ADL or member functions, with semantics compatible to `std::begin` and `std::end`)
|
||||
|
||||
@@ -91,14 +89,8 @@ Strong guarantee: if an exception is thrown, there are no changes in the JSON va
|
||||
- Throws [parse_error.112](../../home/exceptions.md#jsonexceptionparse_error112) if unsupported features from CBOR were
|
||||
used in the given input or if the input is not valid CBOR
|
||||
- Throws [parse_error.113](../../home/exceptions.md#jsonexceptionparse_error113) if a map key is not a string (keys of
|
||||
other types are not supported, as JSON object keys are always strings), if the head of a string or byte string is
|
||||
malformed (including a chunk of the wrong type or an indefinite-length string nested inside an indefinite-length
|
||||
string), or if a string value or object key (or one chunk of an indefinite-length string) is not valid UTF-8 and
|
||||
`error_handler` is `strict`
|
||||
- Throws [out_of_range.408](../../home/exceptions.md#jsonexceptionout_of_range408) if an array or map announces
|
||||
a length that `std::size_t` cannot hold, or that equals `std::size_t(-1)` (for example `9B FF FF FF FF FF FF FF FF`)
|
||||
- Throws [out_of_range.406](../../home/exceptions.md#jsonexceptionout_of_range406) if a floating-point number does not
|
||||
fit into `number_float_t`
|
||||
other types are not supported, as JSON object keys are always strings), or if a string value or object key is not
|
||||
valid UTF-8 and `error_handler` is `strict`
|
||||
|
||||
## Complexity
|
||||
|
||||
|
||||
@@ -79,18 +79,11 @@ Strong guarantee: if an exception is thrown, there are no changes in the JSON va
|
||||
|
||||
- Throws [parse_error.110](../../home/exceptions.md#jsonexceptionparse_error110) if the given input ends prematurely or
|
||||
the end of the file was not reached when `strict` was set to true
|
||||
- Throws [parse_error.112](../../home/exceptions.md#jsonexceptionparse_error112) if an invalid type marker is read
|
||||
(including a type marker after `$` of an optimized container, even if its count is 0), or if `$` is not followed by `#`
|
||||
- Throws [parse_error.112](../../home/exceptions.md#jsonexceptionparse_error112) if a parse error occurs
|
||||
- Throws [parse_error.113](../../home/exceptions.md#jsonexceptionparse_error113) if a string could not be parsed
|
||||
successfully (negative or non-integer length, `C` followed by a byte above 0x7F), if the count of an optimized
|
||||
container is negative, or if a string value or object key is not valid UTF-8 and `error_handler` is `strict`
|
||||
- Throws [parse_error.115](../../home/exceptions.md#jsonexceptionparse_error115) if the text of a high-precision number
|
||||
(`H`) is not a valid JSON number
|
||||
- Throws [out_of_range.406](../../home/exceptions.md#jsonexceptionout_of_range406) if a high-precision number, or a
|
||||
float64 when `number_float_t` is `float`, does not fit into `number_float_t`
|
||||
- Throws [out_of_range.408](../../home/exceptions.md#jsonexceptionout_of_range408) if the count of an optimized
|
||||
container exceeds the capacity of the container (or of `std::size_t`), or if an optimized array of `Z`, `T`, or `F` has
|
||||
more than 1,048,576 elements
|
||||
successfully, or if a string value or object key is not valid UTF-8 and `error_handler` is `strict`
|
||||
- Throws [out_of_range.408](../../home/exceptions.md#jsonexceptionout_of_range408) if the size of an optimized container
|
||||
or n-dimensional array cannot be represented by `std::size_t`
|
||||
|
||||
## Complexity
|
||||
|
||||
|
||||
@@ -121,7 +121,6 @@ The class satisfies the following concept requirements:
|
||||
- [**json_pointer**](../json_pointer/index.md) - JSON Pointer implementation
|
||||
- [**json_serializer**](json_serializer.md) - type of the serializer to for conversions from/to JSON
|
||||
- [**error_handler_t**](error_handler_t.md) - type to choose behavior on decoding errors
|
||||
- [**bjdata_version_t**](bjdata_version_t.md) - type to choose the BJData version to write
|
||||
- [**cbor_tag_handler_t**](cbor_tag_handler_t.md) - type to choose how to handle CBOR tags
|
||||
- **initializer_list_t** - type for initializer lists of `basic_json` values
|
||||
- [**input_format_t**](input_format_t.md) - type to choose the format to parse
|
||||
|
||||
@@ -92,12 +92,20 @@ Strong exception safety: if an exception occurs, the original value stays intact
|
||||
For the **const** version, an object key or array index in `ptr` that does not exist is not reported by an
|
||||
exception, but is undefined behavior (see the notes below). Use [`at`](at.md) for checked access.
|
||||
|
||||
If the **non-const** version throws, the value is left unchanged: values it created for earlier reference tokens
|
||||
of `ptr` are removed again. This also holds for exceptions such as `#!cpp std::bad_alloc` or
|
||||
`#!cpp std::length_error` thrown while padding an array up to a very large index. With custom
|
||||
[template parameters](../../features/types/template_parameters.md), this requires that `erase()` of the object and
|
||||
array types and the move operations of the custom base class do not throw.
|
||||
|
||||
## Complexity
|
||||
|
||||
1. Constant if `idx` is in the range of the array. Otherwise, linear in `idx - size()`.
|
||||
2. Logarithmic in the size of the container.
|
||||
3. Logarithmic in the size of the container.
|
||||
4. Logarithmic in the size of the container.
|
||||
4. Linear in the number of reference tokens of `ptr`; for each of them, logarithmic in the size of the object, or
|
||||
constant for an array. When the non-const version pads an array with `#!json null` values, it is additionally
|
||||
linear in `idx - size()` for that array.
|
||||
|
||||
## Notes
|
||||
|
||||
@@ -145,6 +153,14 @@ Strong exception safety: if an exception occurs, the original value stays intact
|
||||
specified by the JSON Pointer RFC; it is this library's own, intentional disambiguation rule. See also
|
||||
[JSON Pointer](../../features/json_pointer.md).
|
||||
|
||||
!!! warning "Large array indices"
|
||||
|
||||
As the array is filled up with `#!json null` values to the given index, the memory used grows with the index
|
||||
and not with the size of the pointer: on a 64-bit platform, the index `10000000` allocates about 160 MB.
|
||||
The library does not limit the index, so check the array indices of a JSON pointer from untrusted input
|
||||
before using it with the non-const version. See
|
||||
[Parsing untrusted input](../../features/parsing/untrusted_input.md#json-pointers-and-flattened-keys).
|
||||
|
||||
!!! warning "Deprecation"
|
||||
|
||||
Overload (4) also accepts a [`json_pointer`](../json_pointer/index.md) whose template argument is a `basic_json`
|
||||
@@ -294,4 +310,6 @@ Strong exception safety: if an exception occurs, the original value stays intact
|
||||
4. Added in version 2.0.0. A missing array index in the const version is guarded by a runtime assertion since
|
||||
version 3.13.0. Throws [`parse_error.109`](../../home/exceptions.md#jsonexceptionparse_error109) instead of
|
||||
[`out_of_range.404`](../../home/exceptions.md#jsonexceptionout_of_range404) for a one-character array index that is not
|
||||
a digit (e.g., `/x`) in version 3.13.0, as it already did for longer ones.
|
||||
a digit (e.g., `/x`) in version 3.13.0, as it already did for longer ones. Fixed in version 3.13.0 to leave the value
|
||||
unchanged if the non-const version throws (strong exception safety, as documented); before, values created for earlier
|
||||
reference tokens of `ptr` were kept.
|
||||
@@ -43,8 +43,7 @@ The exact mapping and its limitations are described on a [dedicated page](../../
|
||||
`#!cpp false` by default.
|
||||
|
||||
`version` (in)
|
||||
: which version of BJData to use, see [`bjdata_version_t`](bjdata_version_t.md) and the note on "Binary values" on
|
||||
[BJData](../../features/binary_formats/bjdata.md);
|
||||
: which version of BJData to use (see note on "Binary values" on [BJData](../../features/binary_formats/bjdata.md));
|
||||
optional, `#!cpp bjdata_version_t::draft2` by default.
|
||||
|
||||
`error_handler` (in)
|
||||
@@ -65,9 +64,7 @@ Strong guarantee: if an exception is thrown, there are no changes in the JSON va
|
||||
## Exceptions
|
||||
|
||||
- Throws [`other_error.502`](../../home/exceptions.md#jsonexceptionother_error502) if `use_type` is true and `use_size`
|
||||
is false, and `j` contains a non-empty array or object, or a non-empty binary value (with
|
||||
`version = bjdata_version_t::draft3`, any binary value, including an empty one).
|
||||
Scalars, empty arrays, and empty objects do not throw.
|
||||
is false, and `j` contains a non-empty array, object, or binary value.
|
||||
- Throws [type_error.316](../../home/exceptions.md#jsonexceptiontype_error316) if a string or object key in `j` is
|
||||
not valid UTF-8 and `error_handler` is `strict` (the default only if
|
||||
[`JSON_STRICT_BINARY_UTF8`](../macros/json_strict_binary_utf8.md) is enabled)
|
||||
|
||||
@@ -13,7 +13,7 @@ static void to_bson(const basic_json& j, detail::output_adapter<char> o,
|
||||
```
|
||||
|
||||
BSON (Binary JSON) is a binary format in which zero or more ordered key/value pairs are stored as a single entity (a
|
||||
so-called document). The members of an object are written in the order in which iteration visits them.
|
||||
so-called document).
|
||||
|
||||
1. Returns a byte vector containing the BSON serialization.
|
||||
2. Writes the BSON serialization to an output adapter.
|
||||
|
||||
@@ -42,8 +42,7 @@ The exact mapping and its limitations are described on a [dedicated page](../../
|
||||
|
||||
## Exception safety
|
||||
|
||||
Strong guarantee: if an exception is thrown, there are no changes in the JSON value. Bytes that were already written to
|
||||
the output adapter are not taken back.
|
||||
Strong guarantee: if an exception is thrown, there are no changes in the JSON value.
|
||||
|
||||
## Exceptions
|
||||
|
||||
|
||||
@@ -53,7 +53,7 @@ Strong guarantee: if an exception is thrown, there are no changes in the JSON va
|
||||
value, array, or object exceeds 4294967295, the maximum MessagePack can store; example:
|
||||
`"MessagePack length 4294967296 exceeds maximum of 4294967295"`
|
||||
- Throws [`out_of_range.415`](../../home/exceptions.md#jsonexceptionout_of_range415) if the subtype of a binary value
|
||||
exceeds 255, the largest value the library can store in the one-byte MessagePack ext type; example:
|
||||
exceeds 255, the maximum of the MessagePack ext type; example:
|
||||
`"subtype 70000 is too large for the MessagePack ext type (max 255)"`
|
||||
- Throws [type_error.316](../../home/exceptions.md#jsonexceptiontype_error316) if a string or object key in `j` is
|
||||
not valid UTF-8 and `error_handler` is `strict`
|
||||
|
||||
@@ -12,7 +12,7 @@ void erase(view_type array, I idx);
|
||||
std::size_t erase(const json_pointer& ptr);
|
||||
```
|
||||
|
||||
Only an **editable** document (`#!cpp view_mode::editable`, e.g. [`json_editable_document`](../json_editable_document.md))
|
||||
Only an **editable** document (`#!cpp Editable == true`, e.g. [`json_editable_document`](../json_editable_document.md))
|
||||
has `erase`; calling it on a read-only `basic_json_document` fails to compile (`#!cpp static_assert`).
|
||||
|
||||
1. Removes every member of `object` whose key is `key` (see [Notes](#notes) on duplicate keys) and returns how many
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<small>Defined in header `<nlohmann/json_view.hpp>`</small>
|
||||
|
||||
```cpp
|
||||
template<typename BasicJsonType, view_mode Mode = view_mode::read_only>
|
||||
template<typename BasicJsonType, bool Editable = false>
|
||||
class basic_json_document;
|
||||
```
|
||||
|
||||
@@ -20,9 +20,9 @@ is move-only: a copy would duplicate the whole index, the decoded-string buffer,
|
||||
enough in every use we know of. The index, the decoded strings, and the owned text live in one heap block that the
|
||||
document holds through a `#!cpp std::unique_ptr`; this is also why views survive a move of the document.
|
||||
|
||||
With `#!cpp Mode == view_mode::editable`, the document also offers [`set`](set.md), [`push_back`](push_back.md),
|
||||
With `#!cpp Editable == true`, the document also offers [`set`](set.md), [`push_back`](push_back.md),
|
||||
[`insert`](insert.md), and [`erase`](erase.md) to change values in place, see [Edits](#edits) below. The source text
|
||||
itself is never written; a read-only document (`#!cpp view_mode::read_only`, the default) does not carry any of the
|
||||
itself is never written; a read-only document (`#!cpp Editable == false`, the default) does not carry any of the
|
||||
bookkeeping edits need, and calling any of them on one fails to compile (`#!cpp static_assert`).
|
||||
|
||||
## Template parameters
|
||||
@@ -32,10 +32,9 @@ bookkeeping edits need, and calling any of them on one fails to compile (`#!cpp
|
||||
[`ordered_json`](../ordered_json.md). Only 64-bit `number_integer_t`/`number_unsigned_t` types are supported; this
|
||||
is checked with a `static_assert`.
|
||||
|
||||
`Mode`
|
||||
: a [`view_mode`](../view_mode.md): `#!cpp view_mode::editable` if the document supports [`set`](set.md),
|
||||
[`push_back`](push_back.md), [`insert`](insert.md), and [`erase`](erase.md) (optional, `#!cpp view_mode::read_only`
|
||||
by default). See [Edits](#edits) below.
|
||||
`Editable`
|
||||
: whether the document supports [`set`](set.md), [`push_back`](push_back.md), [`insert`](insert.md), and
|
||||
[`erase`](erase.md) (optional, `#!cpp false` by default). See [Edits](#edits) below.
|
||||
|
||||
## Specializations
|
||||
|
||||
@@ -48,7 +47,7 @@ bookkeeping edits need, and calling any of them on one fails to compile (`#!cpp
|
||||
|
||||
## Member types
|
||||
|
||||
- **view_type** - the type of view returned by [`root()`](root.md) (`#!cpp basic_json_view<BasicJsonType, Mode>`)
|
||||
- **view_type** - the type of view returned by [`root()`](root.md) (`#!cpp basic_json_view<BasicJsonType, Editable>`)
|
||||
- **value_t** - the JSON type enumeration, see [`basic_json::value_t`](../basic_json/value_t.md)
|
||||
- **image_check** - how [`load()`](load.md) validates an image (`full`, `bounds`, `none`), see [`image_check`](load.md#image_check)
|
||||
|
||||
@@ -81,15 +80,15 @@ bookkeeping edits need, and calling any of them on one fails to compile (`#!cpp
|
||||
### Edits
|
||||
|
||||
- [**set**](set.md) - replace a value, or set an object member, an array element, or the value a JSON pointer refers
|
||||
to (editable documents only)
|
||||
- [**push_back**](push_back.md) - append to an array (editable documents only)
|
||||
- [**insert**](insert.md) - insert an element into an array before a given position (editable documents only)
|
||||
to (`#!cpp Editable` documents only)
|
||||
- [**push_back**](push_back.md) - append to an array (`#!cpp Editable` documents only)
|
||||
- [**insert**](insert.md) - insert an element into an array before a given position (`#!cpp Editable` documents only)
|
||||
- [**erase**](erase.md) - remove an object member, an array element, or the value a JSON pointer refers to
|
||||
(editable documents only)
|
||||
(`#!cpp Editable` documents only)
|
||||
|
||||
## Edits
|
||||
|
||||
An editable document (`#!cpp view_mode::editable`) can be changed after parsing, with [`set`](set.md),
|
||||
An editable document (`#!cpp Editable == true`) can be changed after parsing, with [`set`](set.md),
|
||||
[`push_back`](push_back.md), [`insert`](insert.md), and [`erase`](erase.md);
|
||||
[`json_editable_document`](../json_editable_document.md) and
|
||||
[`ordered_json_editable_document`](../ordered_json_editable_document.md) are the corresponding specializations. A few
|
||||
|
||||
@@ -5,7 +5,7 @@ template<typename I, typename V>
|
||||
view_type insert(view_type array, I idx, V&& value);
|
||||
```
|
||||
|
||||
Only an **editable** document (`#!cpp view_mode::editable`, e.g. [`json_editable_document`](../json_editable_document.md))
|
||||
Only an **editable** document (`#!cpp Editable == true`, e.g. [`json_editable_document`](../json_editable_document.md))
|
||||
has `insert`; calling it on a read-only `basic_json_document` fails to compile (`#!cpp static_assert`).
|
||||
|
||||
Inserts `value` into `array` as a new element before position `idx`, which must not be past the end
|
||||
|
||||
@@ -55,7 +55,10 @@ validate with overload 2 first, if the original vector must survive a failed loa
|
||||
|
||||
## Exceptions
|
||||
|
||||
Throws [`parse_error.116`](../../home/exceptions.md#jsonexceptionparse_error116) if `image` is not one
|
||||
On a big-endian target, throws [`type_error.320`](../../home/exceptions.md#jsonexceptiontype_error320) -- the same
|
||||
exception [`save()`](save.md#exceptions) throws there, since the image format is little-endian only.
|
||||
|
||||
Otherwise throws [`parse_error.116`](../../home/exceptions.md#jsonexceptionparse_error116) if `image` is not one
|
||||
`save()` could have written, or fails the requested `check`:
|
||||
|
||||
| message | when |
|
||||
@@ -92,9 +95,6 @@ are checked once, however many nodes refer to it.
|
||||
|
||||
## Notes
|
||||
|
||||
**Little-endian targets only.** On a big-endian target, `load()` does not exist, just like
|
||||
[`save()`](save.md#notes): the image format is little-endian, so a call fails to compile.
|
||||
|
||||
### `image_check` { #image_check }
|
||||
|
||||
```cpp
|
||||
|
||||
@@ -13,7 +13,7 @@ editable, and it does not have to be `array`'s own document -- which is copied s
|
||||
source document afterward; a `BasicJsonType` value; or anything `BasicJsonType` can be constructed from (numbers,
|
||||
strings, `#!cpp bool`, `#!cpp nullptr`, containers, ...).
|
||||
|
||||
Only an **editable** document (`#!cpp view_mode::editable`, e.g. [`json_editable_document`](../json_editable_document.md))
|
||||
Only an **editable** document (`#!cpp Editable == true`, e.g. [`json_editable_document`](../json_editable_document.md))
|
||||
has `push_back`; calling it on a read-only `basic_json_document` fails to compile (`#!cpp static_assert`).
|
||||
|
||||
## Template parameters
|
||||
|
||||
@@ -12,7 +12,7 @@ An edited document is written in its *current* state, with its values in documen
|
||||
parser would have produced them for that JSON text: a member [`set`](set.md) added goes at the end, an
|
||||
[`erase`](erase.md)d member leaves no trace, and a float that is not finite (NaN or positive/negative infinity)
|
||||
becomes null, the same substitution [`dump()`](../basic_json_view/dump.md) makes. The same document always saves to
|
||||
the same bytes -- also across `BasicJsonType` and the [`view_mode`](../view_mode.md), since the image reflects document order and
|
||||
the same bytes -- also across `BasicJsonType` and `#!cpp Editable`, since the image reflects document order and
|
||||
values only, not which specialization produced them.
|
||||
|
||||
## Return value
|
||||
@@ -31,6 +31,9 @@ Throws [`type_error.320`](../../home/exceptions.md#jsonexceptiontype_error320) i
|
||||
[discarded](is_discarded.md) -- a default-constructed document, or one a failed [`parse()`](parse.md)/
|
||||
[`read()`](read.md) with `allow_exceptions == false` left discarded.
|
||||
|
||||
On a big-endian target, throws `type_error.320` with a different message instead: the image format is little-endian
|
||||
only (see [Notes](#notes)).
|
||||
|
||||
Throws [`out_of_range.416`](../../home/exceptions.md#jsonexceptionout_of_range416) if the node count, the text, or
|
||||
the decoded strings of the image would individually reach 4 GiB -- the same 32-bit offsets
|
||||
[`parse()`](parse.md#exceptions) and, for edits, [`set`](set.md)/[`push_back`](push_back.md) are already limited to.
|
||||
@@ -41,6 +44,9 @@ the decoded strings of the image would individually reach 4 GiB -- the same 32-b
|
||||
[json.exception.type_error.320] cannot save a discarded json_document
|
||||
```
|
||||
```
|
||||
[json.exception.type_error.320] json_document images need a little-endian target
|
||||
```
|
||||
```
|
||||
[json.exception.out_of_range.416] images of 4 GiB or more are not supported by json_document
|
||||
```
|
||||
|
||||
@@ -64,9 +70,9 @@ else -- see [`load`'s Exceptions](load.md#exceptions).
|
||||
the *same* build on the *same* (little-endian) machine -- not as a long-term storage format. Keep the original
|
||||
JSON text if you need to read a saved document back with a future library version.
|
||||
|
||||
**Little-endian targets only.** The image is written as raw little-endian bytes, with no byte-swapping. On a
|
||||
big-endian target, `save()` and [`load`](load.md) do not exist: a call fails to compile rather than produce bytes a
|
||||
big-endian reader could not interpret correctly.
|
||||
**Little-endian only.** The image is written as raw little-endian bytes, with no byte-swapping. `save()` (and
|
||||
[`load`](load.md)) throw `type_error.320` on a big-endian target rather than silently produce bytes a big-endian
|
||||
reader could not interpret correctly.
|
||||
|
||||
## Examples
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ template<typename V>
|
||||
view_type set(const json_pointer& ptr, V&& value);
|
||||
```
|
||||
|
||||
Only an **editable** document (`#!cpp view_mode::editable`, e.g. [`json_editable_document`](../json_editable_document.md))
|
||||
Only an **editable** document (`#!cpp Editable == true`, e.g. [`json_editable_document`](../json_editable_document.md))
|
||||
has `set`; calling it on a read-only `basic_json_document` fails to compile (`#!cpp static_assert`).
|
||||
|
||||
1. Replaces the value `target` refers to with `value`.
|
||||
|
||||
@@ -1,32 +1,20 @@
|
||||
# <small>nlohmann::basic_json_view::</small>basic_json_view
|
||||
|
||||
```cpp
|
||||
// (1)
|
||||
basic_json_view() noexcept = default;
|
||||
|
||||
// (2) only for Mode == view_mode::editable
|
||||
basic_json_view(const basic_json_view<BasicJsonType, view_mode::read_only>& other) noexcept;
|
||||
```
|
||||
|
||||
1. Creates an invalid (discarded) view: [`type()`](type.md) is `#!cpp value_t::discarded` and
|
||||
[`is_discarded()`](is_discarded.md) is `#!cpp true`.
|
||||
2. Converts a view of a read-only document into a view of an editable document (implicitly), so that a function
|
||||
taking a [`json_editable_view`](../json_editable_view.md) accepts both. The result is a view of the same value of
|
||||
the same read-only document. See [`view_mode`](../view_mode.md) for why there is no conversion the other way.
|
||||
Creates an invalid (discarded) view: [`type()`](type.md) is `#!cpp value_t::discarded` and
|
||||
[`is_discarded()`](is_discarded.md) is `#!cpp true`.
|
||||
|
||||
## Parameters
|
||||
|
||||
`other` (in)
|
||||
: a view of a read-only document with the same `BasicJsonType`
|
||||
|
||||
Apart from these, a view is obtained from a
|
||||
This is the only constructor a caller can use directly. Every other view is obtained from a
|
||||
[`basic_json_document`](../basic_json_document/index.md), via [`root()`](../basic_json_document/root.md) or by
|
||||
navigating into a container with [`operator[]`](operator[].md), [`at`](at.md), [`front`](front.md), [`back`](back.md),
|
||||
[`find`](find.md), or iteration.
|
||||
|
||||
## Exception safety
|
||||
|
||||
No-throw guarantee: these constructors never throw exceptions.
|
||||
No-throw guarantee: this constructor never throws exceptions.
|
||||
|
||||
## Complexity
|
||||
|
||||
@@ -57,7 +45,6 @@ placeholder for "no value yet" and later be assigned a real view.
|
||||
|
||||
- [is_discarded](is_discarded.md) - return whether the view is invalid
|
||||
- [root](../basic_json_document/root.md) - the view of a document's root value
|
||||
- [view_mode](../view_mode.md) - whether a document and its views can be edited
|
||||
|
||||
## Version history
|
||||
|
||||
|
||||
@@ -19,36 +19,16 @@ For the types below, the conversion works directly on the flat index -- no `Basi
|
||||
document's own buffer of decoded strings (see [`get_string()`](get_string.md))
|
||||
- `BasicJsonType` -- equivalent to [`materialize()`](materialize.md)
|
||||
- `basic_json_view` -- returns `#!cpp *this`
|
||||
- `#!cpp std::vector<U, A>` of the types above -- from an array, element by element, each converted with
|
||||
`#!cpp get<U>()`; `#!cpp std::vector<basic_json_view>` keeps a view of every element instead of a value
|
||||
- `#!cpp std::map<K, basic_json_view, C, A>` and `#!cpp std::unordered_map<K, basic_json_view, H, E, A>`, if `K` is
|
||||
constructible from a `#!cpp (const char*, std::size_t)` pair -- views of the members of an object; with a repeated
|
||||
key, the view of the *last* member is kept, as [`BasicJsonType::parse()`](../basic_json/parse.md) keeps its value
|
||||
- `#!cpp std::vector<U, A>` -- from an array, element by element, each converted with `#!cpp get<U>()`; `#!cpp
|
||||
std::vector<basic_json_view>` keeps a view of every element instead of a value
|
||||
- `#!cpp std::map<K, V, C, A>` and `#!cpp std::unordered_map<K, V, H, E, A>`, if `K` is constructible from a `#!cpp
|
||||
(const char*, std::size_t)` pair -- from an object, member by member, each value converted with `#!cpp get<V>()`; with a repeated
|
||||
key, the *last* value is kept, as [`BasicJsonType::parse()`](../basic_json/parse.md) (and
|
||||
[`materialize()`](materialize.md)) does; `#!cpp std::map<std::string, basic_json_view>` keeps views of the members
|
||||
instead of values
|
||||
|
||||
A default-constructible `T` whose `from_json()` accepts views reads the view directly as well, without building a
|
||||
`BasicJsonType` value. This covers the library's own conversions of the standard library types -- all other
|
||||
`#!cpp std::vector`s, `#!cpp std::map`/`#!cpp std::unordered_map` (also with other key types), `#!cpp std::list`,
|
||||
`#!cpp std::deque`, `#!cpp std::set`, `#!cpp std::forward_list`, `#!cpp std::valarray`, `#!cpp std::array`, C arrays,
|
||||
`#!cpp std::pair`, `#!cpp std::tuple`, `#!cpp std::optional`, enumerations, `#!cpp std::filesystem::path`, ... --
|
||||
which give the same values as `#!cpp materialize().get<T>()` (from an object, a repeated key keeps the *last* value,
|
||||
as [`BasicJsonType::parse()`](../basic_json/parse.md) does), as well as the types of the
|
||||
[`NLOHMANN_DEFINE_TYPE_*`](../macros/nlohmann_define_type_intrusive.md) and
|
||||
[`NLOHMANN_DEFINE_DERIVED_TYPE_*`](../macros/nlohmann_define_derived_type.md) macros and the enumerations of
|
||||
[`NLOHMANN_JSON_SERIALIZE_ENUM`](../macros/nlohmann_json_serialize_enum.md), and any `from_json()` constrained to
|
||||
accept views, e.g. with [`is_json_view`](../is_json_view.md). A `from_json()` that also accepts types that are no JSON
|
||||
values at all, such as the unconstrained `#!cpp template<typename BasicJsonType> void from_json(const BasicJsonType&,
|
||||
T&)` of [arbitrary type conversions](../../features/arbitrary_types.md), is not called with a view: it may use
|
||||
`BasicJsonType` functions a view does not have. See [Writing generic code](../../features/json_view.md#writing-generic-code).
|
||||
|
||||
!!! warning "Duplicate keys"
|
||||
|
||||
Such a `from_json()` looks members up in the view, where a repeated key finds the **first** member, while
|
||||
`#!cpp materialize().get<T>()` sees the **last** one, as [`BasicJsonType::parse()`](../basic_json/parse.md)
|
||||
keeps it: for `#!cpp {"x":1,"x":2}`, `#!cpp get<point>()` reads `#!cpp x == 1`. See
|
||||
[Duplicate keys](../../features/json_view.md#duplicate-keys).
|
||||
|
||||
Every other `T` -- user types whose `from_json()` is written for `BasicJsonType` only, types without a default
|
||||
constructor, `#!cpp std::tuple`s holding references, ... -- is converted by `#!cpp materialize().get<T>()`: the subtree is built into a real `BasicJsonType`
|
||||
Every other `T` -- `#!cpp std::list`, `#!cpp std::pair`, `#!cpp std::array`, enumerations, user types with a
|
||||
`from_json()`, ... -- is converted by `#!cpp materialize().get<T>()`: the subtree is built into a real `BasicJsonType`
|
||||
value first (as [`BasicJsonType::parse()`](../basic_json/parse.md) would), and converted from there exactly as
|
||||
[`BasicJsonType::get<T>()`](../basic_json/get.md) would convert it.
|
||||
|
||||
@@ -73,15 +53,12 @@ Strong guarantee: there are no changes to the view or the document it refers to.
|
||||
throws for the same JSON type and `T`.
|
||||
- For `#!cpp std::vector<U, A>`: throws `type_error.302` if the value is not an array; otherwise, whatever converting
|
||||
an element to `U` throws.
|
||||
- For `#!cpp std::map`/`#!cpp std::unordered_map` of views: throws `type_error.302` if the value is not an object.
|
||||
- For a `T` whose `from_json()` reads the view: whatever that `from_json()` throws; for the library's conversions and
|
||||
the macros, the same exceptions with the same messages as [`BasicJsonType::get<T>()`](../basic_json/get.md) of the
|
||||
same value.
|
||||
- For `#!cpp std::map`/`#!cpp std::unordered_map`: throws `type_error.302` if the value is not an object; otherwise,
|
||||
whatever converting a member to the mapped type throws.
|
||||
- For every other `T`: whatever [`materialize().get<T>()`](../basic_json/get.md) throws -- typically `type_error.302`,
|
||||
or whatever a user-provided `from_json()` throws.
|
||||
|
||||
None of the exceptions thrown directly by this function or by a `from_json()` that reads the view (the first four
|
||||
bullets above) carry a
|
||||
None of the exceptions thrown directly by this function (the first three bullets above) carry a
|
||||
[`JSON_DIAGNOSTICS`](../macros/json_diagnostics.md) path: the view has no `BasicJsonType` value to point at. An
|
||||
exception thrown while converting through `materialize()` (the last bullet) is different: it is thrown by a real
|
||||
`BasicJsonType` value, so it **does** carry a `JSON_DIAGNOSTICS` path if `BasicJsonType` was built with it enabled.
|
||||
@@ -99,8 +76,6 @@ document.
|
||||
- `#!cpp std::map`/`#!cpp std::unordered_map`: linear in the number of members for walking them, plus the container's
|
||||
own insertion cost per member (logarithmic for `#!cpp std::map`, amortized constant for `#!cpp
|
||||
std::unordered_map`), times the complexity of converting one member to the mapped type.
|
||||
- a `T` whose `from_json()` reads the view: the cost of that `from_json()`; for the macros, linear in the number of
|
||||
members times the cost of a lookup, plus the cost of converting the members.
|
||||
- every other `T`: the cost of [`materialize()`](materialize.md) and of destroying the `BasicJsonType` value
|
||||
afterwards, plus that of [`BasicJsonType::get<T>()`](../basic_json/get.md).
|
||||
|
||||
|
||||
@@ -5,13 +5,12 @@ template<typename T>
|
||||
T& get_to(T& v) const;
|
||||
```
|
||||
|
||||
Converts the value to `T` and stores it in `v`, in one of three ways:
|
||||
Converts the value to `T` and stores it in `v`, in one of two ways:
|
||||
|
||||
- For the types that [`get<T>()`](get.md) converts directly -- arithmetic types, `#!cpp bool`,
|
||||
`#!cpp std::nullptr_t`, [`string_view_t`](index.md#member-types), `#!cpp std::basic_string`, `BasicJsonType`,
|
||||
`basic_json_view`, vectors of these, and maps of views -- `v` is assigned: `#!cpp v = get<T>()`.
|
||||
- For a type whose `from_json()` accepts views (see [`get<T>()`](get.md)), that `from_json()` is called with the
|
||||
view and the existing `v`, without building a `BasicJsonType` value.
|
||||
`basic_json_view`, `#!cpp std::vector`, and `#!cpp std::map`/`#!cpp std::unordered_map` with string keys -- `v` is
|
||||
assigned: `#!cpp v = get<T>()`.
|
||||
- For every other type, the subtree is built into a `BasicJsonType` value and `#!cpp materialize().get_to(v)` is
|
||||
called, i.e. `from_json()` is invoked with the existing `v`, exactly as
|
||||
[`BasicJsonType::get_to()`](../basic_json/get_to.md) does.
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<small>Defined in header `<nlohmann/json_view.hpp>`</small>
|
||||
|
||||
```cpp
|
||||
template<typename BasicJsonType, view_mode Mode = view_mode::read_only>
|
||||
template<typename BasicJsonType, bool Editable = false>
|
||||
class basic_json_view;
|
||||
```
|
||||
|
||||
@@ -37,7 +37,7 @@ Moving the document itself does not invalidate its views: the index is heap-allo
|
||||
`#!cpp operator ValueType()`), and no `#!cpp get_ptr()` or `#!cpp get_ref()`; see [`get`](get.md).
|
||||
|
||||
`basic_json_view` itself is always read-only -- it never has a `set` or `push_back` of its own. A view of an
|
||||
**editable** document (`#!cpp view_mode::editable`) sees every edit made through
|
||||
**editable** document (`#!cpp Editable == true`) sees every edit made through
|
||||
[`basic_json_document::set`](../basic_json_document/set.md) and
|
||||
[`basic_json_document::push_back`](../basic_json_document/push_back.md): once a value is changed, every view that
|
||||
still refers to it -- including ones taken before the change -- reads the new value. See
|
||||
@@ -49,10 +49,9 @@ still refers to it -- including ones taken before the change -- reads the new va
|
||||
: a specialization of [`basic_json`](../basic_json/index.md), matching the
|
||||
[`basic_json_document`](../basic_json_document/index.md) the view was taken from.
|
||||
|
||||
`Mode`
|
||||
: a [`view_mode`](../view_mode.md): whether the view is of an editable document, matching the
|
||||
[`basic_json_document`](../basic_json_document/index.md) it was taken from (optional, `#!cpp view_mode::read_only` by
|
||||
default). See [Edits](../basic_json_document/index.md#edits).
|
||||
`Editable`
|
||||
: whether the view is of an editable document, matching the [`basic_json_document`](../basic_json_document/index.md)
|
||||
it was taken from (optional, `#!cpp false` by default). See [Edits](../basic_json_document/index.md#edits).
|
||||
|
||||
## Specializations
|
||||
|
||||
@@ -64,7 +63,6 @@ still refers to it -- including ones taken before the change -- reads the new va
|
||||
|
||||
## Member types
|
||||
|
||||
- **basic_json_type** - `BasicJsonType` (it also marks the class for [`is_json_view`](../is_json_view.md))
|
||||
- **value_t** - the JSON type enumeration, see [`basic_json::value_t`](../basic_json/value_t.md)
|
||||
- **string_t**, **number_integer_t**, **number_unsigned_t**, **number_float_t**, **json_pointer** - the corresponding
|
||||
member types of `BasicJsonType`
|
||||
|
||||
@@ -6,7 +6,7 @@ class byte_container_with_subtype : public BinaryType;
|
||||
```
|
||||
|
||||
This type extends the template parameter `BinaryType` provided to [`basic_json`](../basic_json/index.md) with a subtype
|
||||
used by BSON, CBOR, and MessagePack. This type exists so that the user does not have to specify a type themselves with a
|
||||
used by BSON and MessagePack. This type exists so that the user does not have to specify a type themselves with a
|
||||
specific naming scheme in order to override the binary type.
|
||||
|
||||
## Template parameters
|
||||
|
||||
@@ -1,56 +0,0 @@
|
||||
# <small>nlohmann::</small>is_json_view
|
||||
|
||||
<small>Defined in header `<nlohmann/json_view.hpp>`</small>
|
||||
|
||||
```cpp
|
||||
template<typename T>
|
||||
struct is_json_view;
|
||||
```
|
||||
|
||||
A type trait: `#!cpp is_json_view<T>::value` is `#!cpp true` if `T` is a [`basic_json_view`](basic_json_view/index.md)
|
||||
of any `BasicJsonType` and any [`view_mode`](view_mode.md) -- [`json_view`](json_view.md),
|
||||
[`json_editable_view`](json_editable_view.md), [`ordered_json_view`](ordered_json_view.md), ... -- and
|
||||
`#!cpp false` otherwise, for [`basic_json`](basic_json/index.md) as well.
|
||||
|
||||
It is meant for constraining templates that accept views, in particular a `from_json()` that should read views
|
||||
directly: [`get<T>()`](basic_json_view/get.md) on a view calls a `from_json()` with the view only if that `from_json()`
|
||||
accepts views but not arbitrary types.
|
||||
|
||||
## Template parameters
|
||||
|
||||
`T`
|
||||
: the type to check (without cv-qualifiers or references)
|
||||
|
||||
## Notes
|
||||
|
||||
A view is recognized by its member type `basic_json_type` (a [`basic_json`](basic_json/index.md) specialization) and
|
||||
its [`materialize()`](basic_json_view/materialize.md) returning that type, so the trait needs no declaration of the
|
||||
view class.
|
||||
|
||||
## Examples
|
||||
|
||||
??? example
|
||||
|
||||
The example below shows the trait, and a `from_json()` constrained to `json` values and views: `get<T>()` on a view
|
||||
reads the view directly.
|
||||
|
||||
```cpp
|
||||
--8<-- "examples/is_json_view.cpp"
|
||||
```
|
||||
|
||||
Output:
|
||||
|
||||
```
|
||||
--8<-- "examples/is_json_view.output"
|
||||
```
|
||||
|
||||
## See also
|
||||
|
||||
- [basic_json_view](basic_json_view/index.md) - a handle to one value of a document
|
||||
- [get](basic_json_view/get.md) - which conversions read the view directly
|
||||
- [view_mode](view_mode.md) - read-only or editable
|
||||
- [Writing generic code](../features/json_view.md#writing-generic-code) - functions and `from_json()` for views
|
||||
|
||||
## Version history
|
||||
|
||||
Added in version 3.13.0.
|
||||
@@ -3,7 +3,7 @@
|
||||
<small>Defined in header `<nlohmann/json_view.hpp>`</small>
|
||||
|
||||
```cpp
|
||||
using json_document = basic_json_document<json, view_mode::read_only>;
|
||||
using json_document = basic_json_document<json>;
|
||||
```
|
||||
|
||||
This type is a [`basic_json_document`](basic_json_document/index.md) of the default [`json`](json.md)
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<small>Defined in header `<nlohmann/json_view.hpp>`</small>
|
||||
|
||||
```cpp
|
||||
using json_editable_document = basic_json_document<json, view_mode::editable>;
|
||||
using json_editable_document = basic_json_document<json, true>;
|
||||
```
|
||||
|
||||
This type is an **editable** [`basic_json_document`](basic_json_document/index.md) of the default
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<small>Defined in header `<nlohmann/json_view.hpp>`</small>
|
||||
|
||||
```cpp
|
||||
using json_editable_view = basic_json_view<json, view_mode::editable>;
|
||||
using json_editable_view = basic_json_view<json, true>;
|
||||
```
|
||||
|
||||
This type is a [`basic_json_view`](basic_json_view/index.md) of a value of a
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<small>Defined in header `<nlohmann/json_view.hpp>`</small>
|
||||
|
||||
```cpp
|
||||
using json_view = basic_json_view<json, view_mode::read_only>;
|
||||
using json_view = basic_json_view<json>;
|
||||
```
|
||||
|
||||
This type is a [`basic_json_view`](basic_json_view/index.md) of a value of a [`json_document`](json_document.md).
|
||||
|
||||
@@ -43,6 +43,8 @@ header. See also the [macro overview page](../../features/macros.md).
|
||||
- [**JSON_SKIP_UNSUPPORTED_COMPILER_CHECK**](json_skip_unsupported_compiler_check.md) - do not warn about unsupported compilers
|
||||
- [**JSON_USE_GLOBAL_UDLS**](json_use_global_udls.md) - place user-defined string literals (UDLs) into the global namespace
|
||||
- [**JSON_USE_SIMDUTF**](json_use_simdutf.md) - use the simdutf library to accelerate UTF-8 validation
|
||||
- [**JSON_VIEW_NO_SIMD**](json_view_no_simd.md) - use only portable code in the parser of `json_view.hpp`
|
||||
- [**JSON_VIEW_USE_SSSE3**](json_view_use_ssse3.md) - validate non-ASCII strings with SSSE3 in the parser of `json_view.hpp`
|
||||
|
||||
## Library version
|
||||
|
||||
|
||||
@@ -5,8 +5,7 @@
|
||||
```
|
||||
|
||||
When defined, the library uses only portable C++ code where it would otherwise use vector instructions: when scanning
|
||||
strings during parsing, and when writing floating-point numbers during serialization. This includes the parser of
|
||||
[`basic_json_document`](../basic_json_document/index.md) (`<nlohmann/json_view.hpp>`).
|
||||
strings during parsing, and when writing floating-point numbers during serialization.
|
||||
|
||||
The macro is an escape hatch, for example for toolchains that cannot compile the vector code, for sanitizers or
|
||||
analyzers that do not understand it, or to compare the speed of both variants. It does not change any result: values,
|
||||
@@ -78,7 +77,6 @@ By default, `#!cpp JSON_NO_SIMD` is not defined, and vector instructions are use
|
||||
- [**JSON_USE_SIMDUTF**](json_use_simdutf.md) - use the simdutf library to accelerate UTF-8 validation
|
||||
- [**JSON_DISABLE_STREAM_BULK_SCAN**](json_disable_stream_bulk_scan.md) - read a `std::istream` one character at a time
|
||||
- [Parsing: input sources and performance](../../features/parsing/index.md#input-sources-and-performance)
|
||||
- [json_view](../../features/json_view.md) - the zero-copy view, whose parser the macro also affects
|
||||
|
||||
## Version history
|
||||
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
# JSON_VIEW_NO_SIMD
|
||||
|
||||
```cpp
|
||||
#define JSON_VIEW_NO_SIMD
|
||||
```
|
||||
|
||||
When defined, the parser of [`basic_json_document`](../basic_json_document/index.md) (`<nlohmann/json_view.hpp>`)
|
||||
uses only portable C++ to scan strings. By default, it scans long runs of string bytes 16 at a time with NEON on
|
||||
AArch64 (with GCC and Clang) and SSE2 on x86-64, which are part of the baseline instruction sets of these
|
||||
architectures, and validates non-ASCII text with NEON (or SSSE3, see
|
||||
[`JSON_VIEW_USE_SSSE3`](json_view_use_ssse3.md)).
|
||||
|
||||
The same input is accepted or rejected either way, with the same values, and errors are reported the same way; only
|
||||
the speed differs. The macro exists for platforms whose compilers lack the intrinsics headers, and to test the portable
|
||||
code.
|
||||
|
||||
!!! note "ABI compatibility"
|
||||
|
||||
The macro selects between two definitions of the same inline functions. Whether it is defined is encoded in the
|
||||
[namespace](../../features/namespace.md) (tag `_vns`), resulting in distinct symbol names. Translation units
|
||||
compiled with and without it can therefore be linked into the same program without One Definition Rule (ODR)
|
||||
violations, but they cannot exchange instances of library types.
|
||||
|
||||
## Default definition
|
||||
|
||||
By default, `#!cpp JSON_VIEW_NO_SIMD` is not defined, and the vector code is used where available.
|
||||
|
||||
```cpp
|
||||
#undef JSON_VIEW_NO_SIMD
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
??? example
|
||||
|
||||
The code below uses the portable string scanning of the view.
|
||||
|
||||
```cpp
|
||||
#define JSON_VIEW_NO_SIMD
|
||||
#include <nlohmann/json_view.hpp>
|
||||
|
||||
...
|
||||
```
|
||||
|
||||
## See also
|
||||
|
||||
- [JSON_VIEW_USE_SSSE3](json_view_use_ssse3.md) - validate non-ASCII strings with SSSE3 on x86-64
|
||||
- [json_view](../../features/json_view.md) - the zero-copy view
|
||||
|
||||
## Version history
|
||||
|
||||
- Added in version 3.13.0.
|
||||
@@ -0,0 +1,53 @@
|
||||
# JSON_VIEW_USE_SSSE3
|
||||
|
||||
```cpp
|
||||
#define JSON_VIEW_USE_SSSE3
|
||||
```
|
||||
|
||||
When defined on x86-64, the parser of [`basic_json_document`](../basic_json_document/index.md)
|
||||
(`<nlohmann/json_view.hpp>`) validates non-ASCII text in strings with SSSE3 without asking the CPU first.
|
||||
|
||||
By default, the parser checks once at run time whether the CPU has SSSE3 (all x86-64 CPUs since about 2011 have it)
|
||||
and then validates non-ASCII text 16 bytes at a time, using the "lookup4" algorithm of
|
||||
[simdjson](https://github.com/simdjson/simdjson); on CPUs without SSSE3, it validates one UTF-8 sequence at a time.
|
||||
The vector check is compiled for SSSE3 with a function attribute (GCC 4.9 and later, Clang), so this needs no compiler
|
||||
option. With MSVC, the check uses `__cpuid`. On AArch64, the vector check uses NEON and is always on.
|
||||
|
||||
Define the macro only together with a compiler option that enables SSSE3 (e.g. `-mssse3`, or `-march=` with a CPU that
|
||||
has it), and only for programs that run on such CPUs. It saves the check of the CPU, which costs little. The same
|
||||
input is accepted or rejected either way; only the speed of non-ASCII text differs.
|
||||
|
||||
!!! note "ABI compatibility"
|
||||
|
||||
The macro selects between two definitions of the same inline functions. Whether it is defined is encoded in the
|
||||
[namespace](../../features/namespace.md) (tag `_vssse3`, on every architecture), resulting in distinct symbol
|
||||
names. Translation units compiled with and without it can therefore be linked into the same program without One
|
||||
Definition Rule (ODR) violations, but they cannot exchange instances of library types.
|
||||
|
||||
## Default definition
|
||||
|
||||
By default, `#!cpp JSON_VIEW_USE_SSSE3` is not defined.
|
||||
|
||||
```cpp
|
||||
#undef JSON_VIEW_USE_SSSE3
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
??? example
|
||||
|
||||
With CMake, for a program that only runs on CPUs with SSSE3:
|
||||
|
||||
```cmake
|
||||
target_compile_definitions(your_target PRIVATE JSON_VIEW_USE_SSSE3)
|
||||
target_compile_options(your_target PRIVATE -mssse3)
|
||||
```
|
||||
|
||||
## See also
|
||||
|
||||
- [JSON_VIEW_NO_SIMD](json_view_no_simd.md) - use only portable code in the view's parser
|
||||
- [JSON_USE_SIMDUTF](json_use_simdutf.md) - validate UTF-8 with simdutf in `basic_json`'s parser
|
||||
|
||||
## Version history
|
||||
|
||||
- Added in version 3.13.0.
|
||||
@@ -147,13 +147,6 @@ void to_json(BasicJsonType& j, const B& b) {
|
||||
See Implementation limits for [NLOHMANN_DEFINE_TYPE_INTRUSIVE](nlohmann_define_type_intrusive.md) and
|
||||
[NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE](nlohmann_define_type_non_intrusive.md), respectively.
|
||||
|
||||
!!! info "Views"
|
||||
|
||||
The generated `from_json()` also reads the views of [`json_document`](../json_document.md)s
|
||||
(`<nlohmann/json_view.hpp>`): [`get<T>()`](../basic_json_view/get.md) on a view looks the members up in the
|
||||
view, without building a `json` value first. The base part is read from the view as well if the base's
|
||||
`from_json()` accepts views, and from [`materialize()`](../basic_json_view/materialize.md) otherwise.
|
||||
|
||||
## Examples
|
||||
|
||||
??? example "Example: (1) NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE"
|
||||
@@ -199,5 +192,3 @@ void to_json(BasicJsonType& j, const B& b) {
|
||||
6. Added in version 3.12.0.
|
||||
|
||||
All six macros were changed to allow an empty member list in version 3.13.0.
|
||||
|
||||
The generated `from_json()` reads the views of `json_document`s since version 3.13.0.
|
||||
@@ -81,12 +81,6 @@ See the examples below for the concrete generated code.
|
||||
that serializes a struct's members positionally into a JSON array; for that, write `to_json`/`from_json` by
|
||||
hand, building/reading a `json::array()` of the members in order.
|
||||
|
||||
!!! info "Views"
|
||||
|
||||
The generated `from_json()` also reads the views of [`json_document`](../json_document.md)s
|
||||
(`<nlohmann/json_view.hpp>`): [`get<T>()`](../basic_json_view/get.md) on a view looks the members up in the
|
||||
view, without building a `json` value first.
|
||||
|
||||
## Examples
|
||||
|
||||
??? example "Example: (1) NLOHMANN_DEFINE_TYPE_INTRUSIVE"
|
||||
@@ -195,5 +189,3 @@ See the examples below for the concrete generated code.
|
||||
|
||||
All three macros were changed to work with any `basic_json` specialization (not only `nlohmann::json`) in version 3.12.0,
|
||||
and to allow an empty member list in version 3.13.0.
|
||||
|
||||
The generated `from_json()` reads the views of `json_document`s since version 3.13.0.
|
||||
@@ -80,12 +80,6 @@ See the examples below for the concrete generated code.
|
||||
that serializes a struct's members positionally into a JSON array; for that, write `to_json`/`from_json` by
|
||||
hand, building/reading a `json::array()` of the members in order.
|
||||
|
||||
!!! info "Views"
|
||||
|
||||
The generated `from_json()` also reads the views of [`json_document`](../json_document.md)s
|
||||
(`<nlohmann/json_view.hpp>`): [`get<T>()`](../basic_json_view/get.md) on a view looks the members up in the
|
||||
view, without building a `json` value first.
|
||||
|
||||
## Examples
|
||||
|
||||
??? example "Example: (1) NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE"
|
||||
@@ -194,5 +188,3 @@ See the examples below for the concrete generated code.
|
||||
|
||||
All three macros were changed to work with any `basic_json` specialization (not only `nlohmann::json`) in version 3.12.0,
|
||||
and to allow an empty member list in version 3.13.0.
|
||||
|
||||
The generated `from_json()` reads the views of `json_document`s since version 3.13.0.
|
||||
@@ -39,6 +39,6 @@ the library.
|
||||
## Version history
|
||||
|
||||
- Added in version 3.11.0. Changed inline namespace name in version 3.11.2. Added the ABI tag `_dp` in
|
||||
version 3.12.0, and the ABI tags `_bics`, `_psp`, `_snul`, `_sbu8`, `_ekmo`, `_dsbs`, `_dufio`, and `_ns` in
|
||||
version 3.13.0; see
|
||||
version 3.12.0, and the ABI tags `_bics`, `_psp`, `_snul`, `_sbu8`, `_ekmo`, `_dsbs`, `_dufio`, `_ns`, `_vns`,
|
||||
and `_vssse3` in version 3.13.0; see
|
||||
[`nlohmann` Namespace](../../features/namespace.md#structure).
|
||||
@@ -45,12 +45,6 @@ inline void from_json(const BasicJsonType& j, type& e);
|
||||
Define [`JSON_USE_OBJECTS_FOR_ENUM_KEYED_MAPS`](json_use_objects_for_enum_keyed_maps.md) to store them as objects
|
||||
with the converted keys. Such maps can be read from both forms.
|
||||
|
||||
!!! info "Views"
|
||||
|
||||
The generated `from_json()` also reads the views of [`json_document`](../json_document.md)s
|
||||
(`<nlohmann/json_view.hpp>`), comparing the view with the entries of the mapping, without building a `json` value
|
||||
first.
|
||||
|
||||
## Examples
|
||||
|
||||
??? example "Example: Basic usage"
|
||||
@@ -94,5 +88,3 @@ inline void from_json(const BasicJsonType& j, type& e);
|
||||
## Version history
|
||||
|
||||
Added in version 3.4.0.
|
||||
|
||||
The generated `from_json()` reads the views of `json_document`s since version 3.13.0.
|
||||
@@ -48,12 +48,6 @@ inline void from_json(const BasicJsonType& j, type& e);
|
||||
Define [`JSON_USE_OBJECTS_FOR_ENUM_KEYED_MAPS`](json_use_objects_for_enum_keyed_maps.md) to store them as objects
|
||||
with the converted keys. Such maps can be read from both forms.
|
||||
|
||||
!!! info "Views"
|
||||
|
||||
The generated `from_json()` also reads the views of [`json_document`](../json_document.md)s
|
||||
(`<nlohmann/json_view.hpp>`), comparing the view with the entries of the mapping, without building a `json` value
|
||||
first.
|
||||
|
||||
## Examples
|
||||
|
||||
??? example "Example: Basic usage"
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<small>Defined in header `<nlohmann/json_view.hpp>`</small>
|
||||
|
||||
```cpp
|
||||
using ordered_json_document = basic_json_document<ordered_json, view_mode::read_only>;
|
||||
using ordered_json_document = basic_json_document<ordered_json>;
|
||||
```
|
||||
|
||||
This type is a [`basic_json_document`](basic_json_document/index.md) of the [`ordered_json`](ordered_json.md)
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<small>Defined in header `<nlohmann/json_view.hpp>`</small>
|
||||
|
||||
```cpp
|
||||
using ordered_json_editable_document = basic_json_document<ordered_json, view_mode::editable>;
|
||||
using ordered_json_editable_document = basic_json_document<ordered_json, true>;
|
||||
```
|
||||
|
||||
This type is an **editable** [`basic_json_document`](basic_json_document/index.md) of the
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<small>Defined in header `<nlohmann/json_view.hpp>`</small>
|
||||
|
||||
```cpp
|
||||
using ordered_json_editable_view = basic_json_view<ordered_json, view_mode::editable>;
|
||||
using ordered_json_editable_view = basic_json_view<ordered_json, true>;
|
||||
```
|
||||
|
||||
This type is a [`basic_json_view`](basic_json_view/index.md) of a value of an
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<small>Defined in header `<nlohmann/json_view.hpp>`</small>
|
||||
|
||||
```cpp
|
||||
using ordered_json_view = basic_json_view<ordered_json, view_mode::read_only>;
|
||||
using ordered_json_view = basic_json_view<ordered_json>;
|
||||
```
|
||||
|
||||
This type is a [`basic_json_view`](basic_json_view/index.md) of a value of an
|
||||
|
||||
@@ -1,89 +0,0 @@
|
||||
# <small>nlohmann::</small>view_mode
|
||||
|
||||
<small>Defined in header `<nlohmann/json_view.hpp>`</small>
|
||||
|
||||
```cpp
|
||||
enum class view_mode : std::uint8_t
|
||||
{
|
||||
read_only,
|
||||
editable
|
||||
};
|
||||
```
|
||||
|
||||
The second template parameter of [`basic_json_document`](basic_json_document/index.md) and
|
||||
[`basic_json_view`](basic_json_view/index.md): whether a document can be changed after parsing, and whether a view is
|
||||
of such a document.
|
||||
|
||||
`read_only`
|
||||
: the default: the document is parsed once and then only read. It carries none of the bookkeeping edits need, and
|
||||
calling [`set`](basic_json_document/set.md), [`push_back`](basic_json_document/push_back.md),
|
||||
[`insert`](basic_json_document/insert.md), or [`erase`](basic_json_document/erase.md) on it fails to compile.
|
||||
|
||||
`editable`
|
||||
: the document also offers [`set`](basic_json_document/set.md), [`push_back`](basic_json_document/push_back.md),
|
||||
[`insert`](basic_json_document/insert.md), and [`erase`](basic_json_document/erase.md); its views see every edit,
|
||||
see [Edits](basic_json_document/index.md#edits).
|
||||
|
||||
The shortcuts name both modes: [`json_document`](json_document.md) and [`json_view`](json_view.md) are read-only,
|
||||
[`json_editable_document`](json_editable_document.md) and [`json_editable_view`](json_editable_view.md) are editable
|
||||
(and likewise for `ordered_json`).
|
||||
|
||||
## Notes
|
||||
|
||||
The mode is a compile-time property of the document's and the view's type, not a setting of a call. A read-only view
|
||||
reads a container in place, while a view of an editable document follows the links that edits leave behind. A view of
|
||||
a read-only document converts implicitly to a view of an editable document of the same `BasicJsonType`: a read-only
|
||||
document has no edits, so the converted view reads it like an editable document before its first edit (at the cost of
|
||||
one check per access). There is no conversion the other way, because a read-only view of an editable document would
|
||||
read wrong values after the next edit.
|
||||
|
||||
A function that takes a [`json_editable_view`](json_editable_view.md) therefore accepts the views of both modes. A
|
||||
function template deduces the mode from its argument instead, without conversions, so it names the modes it accepts in
|
||||
its signature:
|
||||
|
||||
```cpp
|
||||
// views of editable documents only
|
||||
template<typename BasicJsonType>
|
||||
void f(basic_json_view<BasicJsonType, view_mode::editable> v);
|
||||
|
||||
// views of read-only documents only
|
||||
template<typename BasicJsonType>
|
||||
void f(basic_json_view<BasicJsonType, view_mode::read_only> v);
|
||||
|
||||
// views of either document type
|
||||
template<typename BasicJsonType, view_mode Mode>
|
||||
void f(basic_json_view<BasicJsonType, Mode> v);
|
||||
```
|
||||
|
||||
A function that takes a [`json_view`](json_view.md) accepts neither an [`ordered_json_view`](ordered_json_view.md)
|
||||
nor a [`json_editable_view`](json_editable_view.md). Views of the two modes compare with
|
||||
[`operator==`](basic_json_view/operator_eq.md).
|
||||
|
||||
## Examples
|
||||
|
||||
??? example
|
||||
|
||||
The example below shows a function template that accepts the views of both modes, one that accepts only views of
|
||||
editable documents, and a function taking a `json_editable_view` that also accepts a view of a read-only document.
|
||||
|
||||
```cpp
|
||||
--8<-- "examples/view_mode.cpp"
|
||||
```
|
||||
|
||||
Output:
|
||||
|
||||
```
|
||||
--8<-- "examples/view_mode.output"
|
||||
```
|
||||
|
||||
## See also
|
||||
|
||||
- [basic_json_document](basic_json_document/index.md) - a parsed JSON text
|
||||
- [basic_json_view](basic_json_view/index.md) - a handle to one value of a document
|
||||
- [json_editable_document](json_editable_document.md) - an editable document of `json`
|
||||
- [(constructor)](basic_json_view/basic_json_view.md) - the conversion from a read-only to an editable view
|
||||
- [Writing generic code](../features/json_view.md#writing-generic-code) - functions that accept views
|
||||
|
||||
## Version history
|
||||
|
||||
Added in version 3.13.0.
|
||||
@@ -1,33 +0,0 @@
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
void print_hex(const char* label, const std::vector<std::uint8_t>& v)
|
||||
{
|
||||
std::cout << label << ':';
|
||||
for (auto b : v)
|
||||
{
|
||||
std::cout << ' ' << std::hex << std::setw(2) << std::setfill('0') << static_cast<int>(b);
|
||||
}
|
||||
std::cout << std::dec << std::setfill(' ') << '\n';
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
// a binary value
|
||||
json j = json::binary({0xCA, 0xFE, 0xBA, 0xBE});
|
||||
|
||||
// Draft 2 (the default) writes an array of integers
|
||||
auto v2 = json::to_bjdata(j, true, true, json::bjdata_version_t::draft2);
|
||||
print_hex("draft2", v2);
|
||||
|
||||
// Draft 3 writes an optimized binary array
|
||||
auto v3 = json::to_bjdata(j, true, true, json::bjdata_version_t::draft3);
|
||||
print_hex("draft3", v3);
|
||||
|
||||
// reading yields an array for Draft 2 and a binary value for Draft 3
|
||||
std::cout << json::from_bjdata(v2) << '\n';
|
||||
std::cout << json::from_bjdata(v3) << '\n';
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
draft2: 5b 24 55 23 69 04 ca fe ba be
|
||||
draft3: 5b 24 42 23 69 04 ca fe ba be
|
||||
[202,254,186,190]
|
||||
{"bytes":[202,254,186,190],"subtype":null}
|
||||
@@ -1,34 +0,0 @@
|
||||
#include <iostream>
|
||||
#include <type_traits>
|
||||
#include <nlohmann/json_view.hpp>
|
||||
|
||||
using nlohmann::json;
|
||||
|
||||
namespace ns
|
||||
{
|
||||
struct person
|
||||
{
|
||||
std::string name;
|
||||
int age = 0;
|
||||
};
|
||||
|
||||
// reads json values and views (of any document type), but nothing else
|
||||
template < typename J, typename std::enable_if < nlohmann::is_json_view<J>::value || std::is_same<J, json>::value, int >::type = 0 >
|
||||
void from_json(const J& j, person& p)
|
||||
{
|
||||
p.name = j.at("name").template get<std::string>();
|
||||
p.age = j.at("age").template get<int>();
|
||||
}
|
||||
} // namespace ns
|
||||
|
||||
int main()
|
||||
{
|
||||
std::cout << std::boolalpha
|
||||
<< nlohmann::is_json_view<nlohmann::json_view>::value << ' '
|
||||
<< nlohmann::is_json_view<nlohmann::ordered_json_editable_view>::value << ' '
|
||||
<< nlohmann::is_json_view<json>::value << '\n';
|
||||
|
||||
const nlohmann::json_document doc = nlohmann::json_document::parse(R"({"name": "Ada", "age": 36})");
|
||||
const auto p = doc.root().get<ns::person>(); // reads the view, no json value is built
|
||||
std::cout << p.name << ' ' << p.age << '\n';
|
||||
}
|
||||
@@ -1,2 +0,0 @@
|
||||
true true false
|
||||
Ada 36
|
||||
@@ -5,7 +5,7 @@ using nlohmann::ordered_json_editable_document;
|
||||
|
||||
int main()
|
||||
{
|
||||
// ordered_json_editable_document is basic_json_document<nlohmann::ordered_json, nlohmann::view_mode::editable>
|
||||
// ordered_json_editable_document is basic_json_document<nlohmann::ordered_json, true>
|
||||
ordered_json_editable_document doc = ordered_json_editable_document::parse(R"({"z": 1, "a": 2, "m": 3})");
|
||||
doc.set(doc.root(), "b", 4); // set() always appends a new member at the end
|
||||
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
#include <iostream>
|
||||
#include <nlohmann/json_view.hpp>
|
||||
|
||||
using nlohmann::basic_json_view;
|
||||
using nlohmann::view_mode;
|
||||
|
||||
// accepts the views of read-only and of editable documents, of json and of ordered_json
|
||||
template<typename BasicJsonType, view_mode Mode>
|
||||
std::size_t count_members(basic_json_view<BasicJsonType, Mode> v)
|
||||
{
|
||||
return v.is_object() ? v.size() : 0;
|
||||
}
|
||||
|
||||
// accepts only the views of editable documents
|
||||
template<typename BasicJsonType>
|
||||
bool is_edited(basic_json_view<BasicJsonType, view_mode::editable> v)
|
||||
{
|
||||
return v.is_string() && v.get_string() == "edited";
|
||||
}
|
||||
|
||||
// a function (no template) taking a json_editable_view also accepts the view of a read-only document
|
||||
std::size_t size_of(nlohmann::json_editable_view v)
|
||||
{
|
||||
return v.size();
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
const nlohmann::json_document doc = nlohmann::json_document::parse(R"({"a": 1, "b": 2})");
|
||||
nlohmann::json_editable_document edoc = nlohmann::json_editable_document::parse(R"({"a": 1})");
|
||||
edoc.set(edoc.root()["a"], "edited");
|
||||
|
||||
std::cout << count_members(doc.root()) << ' ' << count_members(edoc.root()) << '\n';
|
||||
std::cout << std::boolalpha << is_edited(edoc.root()["a"]) << '\n';
|
||||
std::cout << size_of(doc.root()) << ' ' << size_of(edoc.root()) << '\n';
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
2 1
|
||||
true
|
||||
2 1
|
||||
@@ -2,9 +2,9 @@
|
||||
|
||||
The [BJData format](https://neurojson.org) was derived from and improved upon
|
||||
[Universal Binary JSON(UBJSON)](https://ubjson.org) specification (Draft 12). Specifically, it introduces an optimized
|
||||
array container for efficient storage of N-dimensional packed arrays (**ND-arrays**); it also adds four new type markers -
|
||||
`[u] - uint16`, `[m] - uint32`, `[M] - uint64`, and `[h] - float16` - to unambiguously map common binary numeric types
|
||||
(Draft 3 adds `[B] - byte`); furthermore, it uses little-endian (LE) to store all numerics instead of big-endian (BE) as in UBJSON to
|
||||
array container for efficient storage of N-dimensional packed arrays (**ND-arrays**); it also adds 5 new type markers -
|
||||
`[u] - uint16`, `[m] - uint32`, `[M] - uint64`, `[h] - float16` and `[B] - byte` - to unambiguously map common binary
|
||||
numeric types; furthermore, it uses little-endian (LE) to store all numerics instead of big-endian (BE) as in UBJSON to
|
||||
avoid unnecessary conversions on commonly available platforms.
|
||||
|
||||
Compared to other binary JSON-like formats such as MessagePack and CBOR, both BJData and UBJSON demonstrate a rare
|
||||
@@ -15,30 +15,11 @@ simple processing.
|
||||
|
||||
!!! abstract "References"
|
||||
|
||||
- [BJData Specification (Draft 3)](https://neurojson.org/bjdata/draft3)
|
||||
- [BJData Specification (Draft 2)](https://neurojson.org/bjdata/draft2)
|
||||
|
||||
!!! info "Supported drafts"
|
||||
|
||||
The library supports BJData Draft 2 (the default) and Draft 3, except for column-major N-dimensional arrays (see
|
||||
below). The draft used for writing is selected with the
|
||||
[`version` parameter](../../api/basic_json/bjdata_version_t.md) of
|
||||
[`to_bjdata`](../../api/basic_json/to_bjdata.md); [`from_bjdata`](../../api/basic_json/from_bjdata.md) has no such
|
||||
parameter and reads the markers of both drafts.
|
||||
|
||||
!!! warning "Draft 4 and column-major ND-arrays are not supported"
|
||||
|
||||
BJData Draft 4 (April 2026) adds structure-of-arrays (SoA) containers (`[$` or `{$` followed by a schema object)
|
||||
and the extension type `E`. `from_bjdata` does not implement them and throws
|
||||
[`parse_error.112`](../../home/exceptions.md#jsonexceptionparse_error112) for such input; `to_bjdata` never writes
|
||||
them.
|
||||
|
||||
Likewise, column-major ND-arrays of Draft 3 (the `#` marker followed by an array that wraps the dimension vector)
|
||||
are rejected with [`parse_error.113`](../../home/exceptions.md#jsonexceptionparse_error113).
|
||||
- [BJData Specification](https://neurojson.org/bjdata/draft2)
|
||||
|
||||
## Byte layout
|
||||
|
||||
BJData follows the structure of UBJSON: a one-byte, human-readable ASCII *type marker* followed by the payload of that type, with strings prefixed by a length that is itself an integer value. In contrast to UBJSON, numbers are stored in little-endian byte order, and additional markers cover unsigned 16/32/64-bit integers, half-precision floats, and bytes. Containers can be written unoptimized (opened with `[` or `{`, closed with `]` or `}`) or optimized with a count (`#`), optionally preceded by a declared element type (`$`). BJData extends the optimized form: the count can be a list of dimensions, which stores an N-dimensional packed array as a flat sequence of values without any per-element markers.
|
||||
BJData follows the structure of UBJSON: a one-byte, human-readable ASCII *type marker* followed by the payload of that type, with strings prefixed by a length that is itself an integer value. In contrast to UBJSON, numbers are stored in little-endian byte order, and additional markers cover unsigned 16/32/64-bit integers, half-precision floats, and bytes. Containers can be written unoptimized (opened with `[` or `{`, closed with `]` or `}`) or optimized with a declared element type (`$`) and/or count (`#`). BJData extends the optimized form: the count can be a list of dimensions, which stores an N-dimensional packed array as a flat sequence of values without any per-element markers.
|
||||
|
||||
Consider the following JSON value (shown formatted for readability):
|
||||
|
||||
@@ -74,7 +55,7 @@ Consider the following JSON value (shown formatted for readability):
|
||||
The library uses the following mapping from JSON values types to BJData types according to the BJData specification:
|
||||
|
||||
| JSON value type | value/range | BJData type | marker |
|
||||
|-----------------|-------------------------------------------|-------------|-------------------------------------------------------------------------|
|
||||
|-----------------|-------------------------------------------|----------------|--------|
|
||||
| null | `null` | null | `Z` |
|
||||
| boolean | `true` | true | `T` |
|
||||
| boolean | `false` | false | `F` |
|
||||
@@ -101,7 +82,7 @@ The library uses the following mapping from JSON values types to BJData types ac
|
||||
| string | *with shortest length indicator* | string | `S` |
|
||||
| array | *see notes on optimized format/ND-array* | array | `[` |
|
||||
| object | *see notes on optimized format* | map | `{` |
|
||||
| binary | *see notes on binary values* | array | `[$B` (Draft 3 with `use_size` and `use_type`), `[U`, or `[B` otherwise |
|
||||
| binary | *see notes on binary values* | array | `[$B` |
|
||||
|
||||
!!! success "Complete mapping"
|
||||
|
||||
@@ -126,16 +107,10 @@ The library uses the following mapping from JSON values types to BJData types ac
|
||||
|
||||
!!! info "Unused BJData markers"
|
||||
|
||||
The following markers are not written:
|
||||
The following markers are not used in the conversion:
|
||||
|
||||
- `N`: no-op values are not created (they are skipped when reading).
|
||||
- `C`: single-character strings are serialized with `S` markers (`C` is read, and written for the elements of
|
||||
ND-arrays with `"_ArrayType_": "char"`).
|
||||
- `h`: floating-point numbers are written as `D`, not as float16 (`h` is read).
|
||||
- `B`: only written in Draft 3 mode.
|
||||
- `d` is only written for `single` ND-arrays or if `number_float_t` is `float`; `H` is only written for integers
|
||||
wider than 64 bits (custom `number_integer_t`/`number_unsigned_t`). An unsigned integer above 9223372036854775807
|
||||
is written as `M`.
|
||||
- `Z`: no-op values are not created.
|
||||
- `C`: single-byte strings are serialized with `S` markers.
|
||||
|
||||
!!! info "NaN/infinity handling"
|
||||
|
||||
@@ -167,7 +142,7 @@ The library uses the following mapping from JSON values types to BJData types ac
|
||||
BJData extends UBJSON's optimized array **size** marker to support ND-arrays of uniform numerical data types
|
||||
(referred to as *packed arrays*). For example, the 2-D `uint8` integer array `[[1,2],[3,4],[5,6]]`, stored as nested
|
||||
optimized array in UBJSON `[ [$U#i2 1 2 [$U#i2 3 4 [$U#i2 5 6 ]`, can be further compressed in BJData to
|
||||
`[$U#[$i#i2 3 2 1 2 3 4 5 6` or `[$U#[i3 i2] 1 2 3 4 5 6`.
|
||||
`[$U#[$i#i2 2 3 1 2 3 4 5 6` or `[$U#[i2 i3] 1 2 3 4 5 6`.
|
||||
|
||||
To maintain type and size information, ND-arrays are converted to JSON objects following the **annotated array
|
||||
format** (defined in the [JData specification (Draft 3)][JDataAAFmt]), when parsed using
|
||||
@@ -177,14 +152,11 @@ The library uses the following mapping from JSON values types to BJData types ac
|
||||
```json
|
||||
{
|
||||
"_ArrayType_": "uint8",
|
||||
"_ArraySize_": [3,2],
|
||||
"_ArraySize_": [2,3],
|
||||
"_ArrayData_": [1,2,3,4,5,6]
|
||||
}
|
||||
```
|
||||
|
||||
ND-arrays with the element type `h` (float16) are returned with `"_ArrayType_": "half"`. `to_bjdata` does not pack
|
||||
`"half"` objects; they are written as regular objects, which read back as an equal value.
|
||||
|
||||
Likewise, when a JSON object in the above form is serialized using
|
||||
[`to_bjdata`](../../api/basic_json/to_bjdata.md), it is automatically converted into a compact BJData ND-array.
|
||||
|
||||
@@ -195,40 +167,34 @@ The library uses the following mapping from JSON values types to BJData types ac
|
||||
object; otherwise it is serialized as a regular JSON object, so the annotation is never lost in a round trip. This requires
|
||||
all of the following:
|
||||
|
||||
- the object has exactly the three keys `"_ArrayType_"`, `"_ArraySize_"`, and `"_ArrayData_"` (any other key, e.g.,
|
||||
`"_ArrayOrder_"`, makes it a regular object),
|
||||
- `"_ArrayType_"` is one of `uint8`, `int8`, `uint16`, `int16`, `uint32`, `int32`, `uint64`, `int64`, `single`,
|
||||
`double`, `char`, or (only with `version = bjdata_version_t::draft3`, since the `B` marker is not part of Draft 2)
|
||||
`byte`; the names are case-sensitive,
|
||||
`double`, `char`, or `byte`,
|
||||
- `"_ArraySize_"` is an array, since the dimensions are written as the ND-array header's length,
|
||||
- `"_ArraySize_"` has at least two entries and is not a two-entry row vector (`[1,N]`), since other shapes are
|
||||
parsed back as a regular array (`[1,2,2]` is packed, `[1,4]` is not),
|
||||
- `"_ArraySize_"` has at least two entries and is not a 1×N row vector (first entry 1), since other shapes are
|
||||
parsed back as a regular array,
|
||||
- every entry of `"_ArraySize_"` is a positive integer, and their product is representable as a `std::size_t`,
|
||||
- `"_ArrayData_"` is an array holding exactly that many elements, and
|
||||
- every element of `"_ArrayData_"` is a number of the kind named by `"_ArrayType_"`: for the integer types, an
|
||||
integer (a floating-point number such as `1.0` does not qualify) that fits the named width (for `char`, 0..127);
|
||||
for `double`, a floating-point number (an integer such as `1` does not qualify); for `single`, a floating-point
|
||||
number that survives narrowing to `float` and back without change (for instance, `0.1` does not, since it is not
|
||||
exactly representable as `float`).
|
||||
- every element of `"_ArrayData_"` is a number of the kind named by `"_ArrayType_"`: for the integer types, a
|
||||
value that fits the named width; for `double`, any value; for `single`, a value that survives narrowing to
|
||||
`float` and back without change (for instance, `0.1` does not, since it is not exactly representable as
|
||||
`float`).
|
||||
|
||||
With `ordered_json`, an annotated object read from BJData has its keys in the order `"_ArrayType_"`,
|
||||
`"_ArraySize_"`, `"_ArrayData_"`; with `json`, they are sorted like those of any other object.
|
||||
An annotated object is always read back with its keys in the order shown above, `"_ArrayType_"`, `"_ArraySize_"`,
|
||||
`"_ArrayData_"`, regardless of the order the ND-array's header stores them in on the wire. This matters for
|
||||
`ordered_json`, whose comparison takes key order into account.
|
||||
|
||||
The current version of this library does not yet support automatic detection of and conversion from a nested JSON
|
||||
array input to a BJData ND-array.
|
||||
|
||||
[JDataAAFmt]: https://github.com/NeuroJSON/jdata/blob/Draft-3/JData_specification.md#annotated-storage-of-n-d-arrays
|
||||
[JDataAAFmt]: https://github.com/NeuroJSON/jdata/blob/master/JData_specification.md#annotated-storage-of-n-d-arrays
|
||||
|
||||
!!! info "Restrictions in optimized data types for arrays and objects"
|
||||
|
||||
Due to diminished space saving, hampered readability, and increased security risks, in BJData, the
|
||||
allowed data types following the `$` marker in an optimized array and object container are restricted to
|
||||
Due to diminished space saving, hampered readability, and increased security risks, in BJData, the allowed data
|
||||
types following the `$` marker in an optimized array and object container are restricted to
|
||||
**non-zero-fixed-length** data types. Therefore, the valid optimized type markers can only be one of
|
||||
`UiuImlMLhdDC`, plus `B` since Draft 3 (the reader accepts `B` in both drafts). This also means other variable (`[{SH`) or zero-length types (`TFZN`) can not be used in an
|
||||
optimized array or object in BJData. The library enforces this restriction for both drafts. A `C` (char) element above 127 is rejected on read with
|
||||
[`parse_error.113`](../../home/exceptions.md#jsonexceptionparse_error113), in 1-D and in N-dimensional arrays. With `use_type`, the
|
||||
elements must have the same marker (`[1,200,3]` is not optimized, since it mixes `i` and `U`); booleans, null,
|
||||
strings, arrays, and objects are never optimized with `$`.
|
||||
`UiuImlMLhdDCB`. This also means other variable (`[{SH`) or zero-length types (`TFN`) can not be used in an
|
||||
optimized array or object in BJData.
|
||||
|
||||
!!! info "Binary values"
|
||||
|
||||
@@ -236,16 +202,14 @@ The library uses the following mapping from JSON values types to BJData types ac
|
||||
in optimized arrays to designate binary data. This means that, unlike UBJSON, binary data can be both serialized and
|
||||
deserialized.
|
||||
|
||||
To preserve compatibility with BJData Draft 2, the Draft 3 optimized binary array must be explicitly enabled: pass
|
||||
`version = bjdata_version_t::draft3` together with `use_size = true` and `use_type = true` to
|
||||
[`to_bjdata`](../../api/basic_json/to_bjdata.md). With Draft 3 and only `use_size` (or neither), a binary value is
|
||||
written as an array of `B` elements.
|
||||
To preserve compatibility with BJData Draft 2, the Draft 3 optimized binary array must be explicitly enabled using
|
||||
the `version` parameter of [`to_bjdata`](../../api/basic_json/to_bjdata.md).
|
||||
|
||||
In Draft 2 mode (default), if the JSON data contains the binary type, the value is stored as a list of integers, as
|
||||
In Draft2 mode (default), if the JSON data contains the binary type, the value stored as a list of integers, as
|
||||
suggested by the BJData documentation. In particular, this means that the serialization and the deserialization of
|
||||
JSON containing binary values into BJData and back will result in a different JSON object.
|
||||
|
||||
[BJDataBinArr]: https://github.com/NeuroJSON/bjdata/blob/Draft-3/Binary_JData_Specification.md#optimized-binary-array
|
||||
[BJDataBinArr]: https://github.com/NeuroJSON/bjdata/blob/master/Binary_JData_Specification.md#optimized-binary-array
|
||||
|
||||
??? example "Example: serialize JSON values to BJData, with and without size/type optimization"
|
||||
|
||||
@@ -264,7 +228,7 @@ The library uses the following mapping from JSON values types to BJData types ac
|
||||
The library maps BJData types to JSON value types as follows:
|
||||
|
||||
| BJData type | JSON value type | marker |
|
||||
|-----------------------|--------------------------------------------------|----------|
|
||||
|-------------|------------------------------------------|----------|
|
||||
| no-op | *no value, next value is read* | `N` |
|
||||
| null | `null` | `Z` |
|
||||
| false | `false` | `F` |
|
||||
@@ -272,7 +236,6 @@ The library maps BJData types to JSON value types as follows:
|
||||
| float16 | number_float | `h` |
|
||||
| float32 | number_float | `d` |
|
||||
| float64 | number_float | `D` |
|
||||
| high-precision number | number_integer, number_unsigned, or number_float | `H` |
|
||||
| uint8 | number_unsigned | `U` |
|
||||
| int8 | number_integer | `i` |
|
||||
| uint16 | number_unsigned | `u` |
|
||||
@@ -291,18 +254,7 @@ The library maps BJData types to JSON value types as follows:
|
||||
|
||||
!!! success "Complete mapping"
|
||||
|
||||
The mapping is **complete** for the BJData types of Draft 2 and Draft 3 with one exception: column-major
|
||||
N-dimensional arrays are rejected with [`parse_error.113`](../../home/exceptions.md#jsonexceptionparse_error113).
|
||||
The Draft 4 constructs (structure-of-arrays containers and the extension type `E`) are not supported either.
|
||||
|
||||
The digits of an `H` value are parsed like a JSON number: integers that fit 64 bits become `number_integer` or
|
||||
`number_unsigned`, anything else a `number_float`; invalid text throws
|
||||
[`parse_error.115`](../../home/exceptions.md#jsonexceptionparse_error115).
|
||||
|
||||
!!! info "Duplicate object keys"
|
||||
|
||||
If an object contains the same key more than once, `from_bjdata` accepts it and keeps the last value; with
|
||||
`ordered_json`, the key keeps the position of its first occurrence.
|
||||
The mapping is **complete** in the sense that any BJData value can be converted to a JSON value.
|
||||
|
||||
!!! warning "Ill-formed UTF-8 in string values and object keys"
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# BON8
|
||||
|
||||
BON8 (Binary Object Notation 8) is a compact binary serialization format for JSON values. It uses byte values that
|
||||
BON8 (Binary Object Notation 8) is a compact binary serialization format for JSON values. It uses the byte values that
|
||||
cannot begin a UTF-8 character as type markers, so strings are stored as plain UTF-8 without a length prefix: a string
|
||||
ends at the first byte that cannot continue it. Integers from -10 to 39, `true`, `false`, `null`, and the floating-point
|
||||
values -1.0, 0.0, and 1.0 take a single byte, and arrays and objects with up to four elements need no terminator.
|
||||
@@ -12,7 +12,7 @@ values -1.0, 0.0, and 1.0 take a single byte, and arrays and objects with up to
|
||||
|
||||
## Byte layout
|
||||
|
||||
BON8 exploits the fact that some byte values can never start a UTF-8 character. These bytes serve as *type markers*, so strings can be stored as plain UTF-8 without a length prefix: a string ends at the first byte that cannot continue it: a marker byte, or a lead byte 0xC2..0xF7 followed by a byte outside 0x80..0xBF. The ending byte is often the marker of the next value. Small integers, `true`, `false`, `null`, and a few common floats are a single byte. Arrays and objects are introduced by a marker; those with up to four elements encode their size in the marker and need no terminator, while larger ones are closed by the end marker `0xFE`.
|
||||
BON8 exploits the fact that some byte values can never start a UTF-8 character. These bytes serve as *type markers*, so strings can be stored as plain UTF-8 without a length prefix: a string ends at the first byte that cannot continue it (often the marker of the next value). Small integers, `true`, `false`, `null`, and a few common floats are a single byte. Arrays and objects are introduced by a marker; those with up to four elements encode their size in the marker and need no terminator, while larger ones are closed by the end marker `0xFE`.
|
||||
|
||||
Consider the following JSON value (shown formatted for readability):
|
||||
|
||||
@@ -33,7 +33,7 @@ Consider the following JSON value (shown formatted for readability):
|
||||
<div class="byte-layout" markdown="0"><table>
|
||||
<thead><tr><th>JSON</th><th>Bytes</th><th>Meaning</th></tr></thead><tbody>
|
||||
<tr><td><code>{</code></td><td><span class="bl bl-t">8A</span></td><td>object with 4 members</td></tr>
|
||||
<tr><td><code>"id": 300,</code></td><td><span class="bl bl-d">69 64</span> <span class="bl bl-t">C4</span> <span class="bl bl-d">04</span></td><td>key: UTF-8 bytes; the string ends at 0xC4, because the byte after it (0x04) is not a UTF-8 continuation byte, so 0xC4 starts an integer; value: 2-byte positive integer (lead byte, then a byte below 0x80)</td></tr>
|
||||
<tr><td><code>"id": 300,</code></td><td><span class="bl bl-d">69 64</span> <span class="bl bl-t">C4</span> <span class="bl bl-d">04</span></td><td>key: UTF-8 bytes; the string ends at the next byte, which cannot continue a UTF-8 character; value: 2-byte positive integer (lead byte, then a byte below 0x80)</td></tr>
|
||||
<tr><td><code>"name": "json",</code></td><td><span class="bl bl-d">6E 61 6D 65</span> <span class="bl bl-l">FF</span> <span class="bl bl-d">6A 73 6F 6E</span> <span class="bl bl-l">FF</span></td><td>key: UTF-8 bytes; 0xFF terminates the string as another string follows; value: UTF-8 bytes; terminated as a string key follows</td></tr>
|
||||
<tr><td><code>"pi": 3.14,</code></td><td><span class="bl bl-d">70 69</span> <span class="bl bl-t">8F</span> <span class="bl bl-d">40 09 1E B8 51 EB 85 1F</span></td><td>key: UTF-8 bytes; value: binary64 (IEEE 754, big-endian); its marker also ends <code>"pi"</code></td></tr>
|
||||
<tr><td><code>"tags": [</code></td><td><span class="bl bl-d">74 61 67 73</span> <span class="bl bl-t">82</span></td><td>key: UTF-8 bytes; value: array with 2 elements; its marker also ends <code>"tags"</code></td></tr>
|
||||
@@ -100,8 +100,7 @@ serialized as 0x81 0x65 0xFF, but `[1,2,3,4,"e"]` as 0x85 0x91 0x92 0x93 0x94 0x
|
||||
|
||||
The following values can **not** be converted to a BON8 value:
|
||||
|
||||
- integers outside the int64 range (unsigned integers above 9223372036854775807 and, for number types wider than
|
||||
64 bits, any larger or smaller integer), because BON8 integers are limited to int64
|
||||
- unsigned integers above 9223372036854775807, because BON8 has no unsigned 64-bit integer type
|
||||
([out_of_range.407](../../home/exceptions.md#jsonexceptionout_of_range407))
|
||||
- strings that are not valid UTF-8, because the end of a string is determined from its encoding
|
||||
([type_error.316](../../home/exceptions.md#jsonexceptiontype_error316))
|
||||
@@ -169,13 +168,7 @@ The library maps BON8 types to JSON value types as follows:
|
||||
|
||||
Non-negative integers are read as number_unsigned, negative integers as number_integer.
|
||||
|
||||
A byte 0xF5..0xF7 followed by 0x80..0xBF is neither a string nor an integer and is rejected with
|
||||
[parse_error.112](../../home/exceptions.md#jsonexceptionparse_error112) (invalid UTF-8 byte). The same error is
|
||||
reported for any other invalid byte (such as a stray 0xFE), for ill-formed UTF-8, and for an object key that is not a
|
||||
string. Input that ends prematurely, trailing data after the value, and a missing final 0xFF after a string at the end
|
||||
of the message are reported as [parse_error.110](../../home/exceptions.md#jsonexceptionparse_error110).
|
||||
|
||||
!!! info "Non-canonical input"
|
||||
!!! info
|
||||
|
||||
Values that do not use the canonical representation, such as integers with a longer encoding than necessary,
|
||||
arrays and objects with up to four elements that are terminated by 0xFE, unsorted object keys, or a 0xFF after a
|
||||
@@ -183,10 +176,7 @@ of the message are reported as [parse_error.110](../../home/exceptions.md#jsonex
|
||||
|
||||
Strings must be valid UTF-8, and a string at the very end of a message must be terminated by 0xFF.
|
||||
|
||||
Duplicate object keys are accepted; the last value wins (`ordered_json` keeps the position of the first occurrence).
|
||||
The specification does not say how to treat them; the HikoGUI reference decoder keeps the first value.
|
||||
|
||||
!!! info "Round trips"
|
||||
!!! info
|
||||
|
||||
Any BON8 output created by `to_bon8` can be successfully parsed by `from_bon8`.
|
||||
|
||||
|
||||
@@ -66,12 +66,7 @@ The library uses the following mapping from JSON values types to BSON types:
|
||||
!!! warning "Incomplete mapping"
|
||||
|
||||
The mapping is **incomplete**, since only JSON-objects (and things contained therein) can be serialized to BSON.
|
||||
Also, keys may not contain U+0000, since they are serialized as zero-terminated C strings.
|
||||
|
||||
!!! info "Order of object members"
|
||||
|
||||
The members of an object are written in the order in which iteration visits them: sorted by key for
|
||||
[`json`](../../api/json.md), in insertion order for [`ordered_json`](../../api/ordered_json.md).
|
||||
Also, keys may not contain U+0000, since they are serialized a zero-terminated c-strings.
|
||||
|
||||
!!! warning "BSON type 0x11 interoperability"
|
||||
|
||||
@@ -86,19 +81,6 @@ The library uses the following mapping from JSON values types to BSON types:
|
||||
As a result, serializing and deserializing a JSON object containing such a value produces a different JSON object,
|
||||
even though the binary data is unchanged.
|
||||
|
||||
!!! info "Binary subtype 0x02 (old binary)"
|
||||
|
||||
The BSON specification defines the payload of the "binary (old)" subtype `0x02` as an int32 followed by that many
|
||||
bytes, so the value is preceded by two lengths: the length of the binary element and, as the first four bytes of
|
||||
the payload, the number of bytes that follow. A binary value with subtype `2` is therefore written with the outer
|
||||
length 4 bytes larger than its size and the size as inner length: `binary({1, 2, 3}, 2)` becomes
|
||||
`07 00 00 00 02 03 00 00 00 01 02 03`. When reading, the inner length is checked and removed, so the value
|
||||
contains only the bytes that follow it. `from_bson()` throws
|
||||
[`parse_error.112`](../../home/exceptions.md#jsonexceptionparse_error112) if the outer length is less than 4 or the
|
||||
inner length is not the outer length minus 4. Versions before 3.13.0 did not write the inner length and returned
|
||||
it as part of the payload; BSON data written by those versions with subtype 2 is not readable any more and must be
|
||||
written again.
|
||||
|
||||
??? example "Example: serialize a JSON value to BSON"
|
||||
|
||||
```cpp
|
||||
@@ -153,29 +135,12 @@ The library maps BSON record types to JSON value types as follows:
|
||||
The BSON reader is lenient in a few areas where the BSON specification is more restrictive:
|
||||
|
||||
- array element keys are not checked against the required decimal sequence (`0`, `1`, `2`, ...),
|
||||
- any non-zero byte is accepted as `true` for the boolean type,
|
||||
- the payloads of the binary subtypes `0x03` (UUID, old), `0x04` (UUID), and `0x05` (MD5) are not checked to have
|
||||
16 bytes,
|
||||
- duplicate keys within a document are accepted; the last value wins (`{"a": 1, "a": 2}` is read as `{"a": 2}`),
|
||||
while a SAX handler receives every occurrence,
|
||||
- a `string` value may contain embedded `0x00` bytes, and
|
||||
- with `strict` set to `false`, bytes after the end of the document are ignored.
|
||||
- any non-zero byte is accepted as `true` for the boolean type, and
|
||||
- the payload for binary subtype `0x02` is returned as-is, including its inner length prefix.
|
||||
|
||||
If BSON input must be validated for strict specification compliance, validate it separately before passing it to
|
||||
`from_bson()`.
|
||||
|
||||
!!! note "Document size"
|
||||
|
||||
Every document starts with its size. `from_bson()` rejects a document with
|
||||
[`parse_error.112`](../../home/exceptions.md#jsonexceptionparse_error112) if the size is less than 5 (the size prefix and the terminator), if an embedded document does not end before the
|
||||
end of the document that contains it, if the elements do not fit into the declared size, or if the size does not
|
||||
match the number of bytes read when the terminating `0x00` byte is reached. A size that is too small is detected
|
||||
before an element is read whose type byte and name no longer fit; an element that starts inside the declared size
|
||||
but extends past it is read, and reported to a SAX handler, before the mismatch is found at the terminator. A size
|
||||
that is too large is likewise found only at the terminator. Passing `strict` as `false` skips only the check for bytes after
|
||||
the end of the document ([`parse_error.110`](../../home/exceptions.md#jsonexceptionparse_error110)), not the
|
||||
document size checks.
|
||||
|
||||
!!! warning "Ill-formed UTF-8 in string values"
|
||||
|
||||
The BSON specification requires `string` values (type `0x02`) to be valid UTF-8, but this is not required of a
|
||||
@@ -189,9 +154,8 @@ The library maps BSON record types to JSON value types as follows:
|
||||
ill-formed bytes. `to_bson()`'s own `error_handler` parameter defaults to `keep`, so such a string value or element
|
||||
(key) name is written unchanged; with `strict` (the default if
|
||||
[`JSON_STRICT_BINARY_UTF8`](../../api/macros/json_strict_binary_utf8.md) is enabled), it throws the same exception
|
||||
instead. Element (key) names are treated like string values: with `keep` they are read unchanged, with `strict`,
|
||||
`replace`, or `ignore` they are checked and handled in the same way. `binary` values (type `0x05`) are unaffected,
|
||||
since they are not required to hold text.
|
||||
instead. Element (key) names are never validated on read, since they are read byte-by-byte as a C string. `binary`
|
||||
values (type `0x05`) are unaffected, since they are not required to hold text.
|
||||
|
||||
??? example "Example: deserialize a JSON value from BSON"
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ extremely small code sizes, fairly small message size, and extensibility without
|
||||
|
||||
## Byte layout
|
||||
|
||||
CBOR encodes every data item as a *head* followed by optional content. The first byte of the head holds the *major type* in its upper three bits (unsigned integer, negative integer, byte string, text string, array, map, tag, or simple/float) and an *additional information* value in its lower five bits. Additional information below 24 is the argument itself (for example, a small integer or a short length); the values 24 to 27 announce that the argument follows in 1, 2, 4, or 8 big-endian bytes. Strings, arrays, and maps are prefixed with their length (or count of elements/pairs), and content follows directly. A reader of definite-length items knows how many items to expect without a terminator; indefinite-length items (additional information 31) are instead closed by the "break" byte 0xFF, which `from_cbor` reads but `to_cbor` never writes.
|
||||
CBOR encodes every data item as a *head* followed by optional content. The first byte of the head holds the *major type* in its upper three bits (unsigned integer, negative integer, byte string, text string, array, map, tag, or simple/float) and an *additional information* value in its lower five bits. Additional information below 24 is the argument itself (for example, a small integer or a short length); the values 24 to 27 announce that the argument follows in 1, 2, 4, or 8 big-endian bytes. Strings, arrays, and maps are prefixed with their length (or count of elements/pairs), and content follows directly, so a reader always knows how many items to expect without a terminator.
|
||||
|
||||
Consider the following JSON value (shown formatted for readability):
|
||||
|
||||
@@ -52,16 +52,16 @@ The library uses the following mapping from JSON values types to CBOR types acco
|
||||
| null | `null` | Null | 0xF6 |
|
||||
| boolean | `true` | True | 0xF5 |
|
||||
| boolean | `false` | False | 0xF4 |
|
||||
| number_integer | -9223372036854775808..-4294967297 | Negative integer (8 bytes follow) | 0x3B |
|
||||
| number_integer | -4294967296..-65537 | Negative integer (4 bytes follow) | 0x3A |
|
||||
| number_integer | -65536..-257 | Negative integer (2 bytes follow) | 0x39 |
|
||||
| number_integer | -256..-25 | Negative integer (1 byte follow) | 0x38 |
|
||||
| number_integer | -9223372036854775808..-2147483649 | Negative integer (8 bytes follow) | 0x3B |
|
||||
| number_integer | -2147483648..-32769 | Negative integer (4 bytes follow) | 0x3A |
|
||||
| number_integer | -32768..-129 | Negative integer (2 bytes follow) | 0x39 |
|
||||
| number_integer | -128..-25 | Negative integer (1 byte follow) | 0x38 |
|
||||
| number_integer | -24..-1 | Negative integer | 0x20..0x37 |
|
||||
| number_integer | 0..23 | Integer | 0x00..0x17 |
|
||||
| number_integer | 24..255 | Unsigned integer (1 byte follow) | 0x18 |
|
||||
| number_integer | 256..65535 | Unsigned integer (2 bytes follow) | 0x19 |
|
||||
| number_integer | 65536..4294967295 | Unsigned integer (4 bytes follow) | 0x1A |
|
||||
| number_integer | 4294967296..9223372036854775807 | Unsigned integer (8 bytes follow) | 0x1B |
|
||||
| number_integer | 4294967296..18446744073709551615 | Unsigned integer (8 bytes follow) | 0x1B |
|
||||
| number_unsigned | 0..23 | Integer | 0x00..0x17 |
|
||||
| number_unsigned | 24..255 | Unsigned integer (1 byte follow) | 0x18 |
|
||||
| number_unsigned | 256..65535 | Unsigned integer (2 bytes follow) | 0x19 |
|
||||
@@ -95,24 +95,7 @@ see "binary" cells in the table above.
|
||||
|
||||
!!! success "Complete mapping"
|
||||
|
||||
The mapping is **complete** in the sense that any JSON value type can be converted to a CBOR value, with one
|
||||
exception: an integer outside the range of CBOR integers (only possible with a number type wider than 64 bits)
|
||||
throws [`out_of_range.407`](../../home/exceptions.md#jsonexceptionout_of_range407).
|
||||
|
||||
!!! info "Not a deterministic encoding"
|
||||
|
||||
`to_cbor` does not produce the deterministic encoding of
|
||||
[RFC 8949, Section 4.2.1](https://www.rfc-editor.org/rfc/rfc8949.html#section-4.2.1), and not always the preferred
|
||||
serialization of Section 4.1:
|
||||
|
||||
- floating-point numbers are written as single precision (0xFA) when that is exact and as double precision (0xFB)
|
||||
otherwise; half precision (0xF9) is used only for `NaN` and `Infinity`/`-Infinity` (`1.0` is `fa 3f 80 00 00`);
|
||||
- a binary subtype 0..23 is written as `d8 xx` instead of the one-byte tag 0xC0..0xD7 (`d8 01 41 01`);
|
||||
- object members are written in the order of `object_t` (for the default `std::map`: sorted by the key string, not
|
||||
by the encoded key bytes).
|
||||
|
||||
Integers and lengths use the shortest form, and indefinite-length items are never written. Decoders must accept all
|
||||
of this; the RFC does not require the preferred serialization.
|
||||
The mapping is **complete** in the sense that any JSON value type can be converted to a CBOR value.
|
||||
|
||||
!!! info "NaN/infinity handling"
|
||||
|
||||
@@ -122,8 +105,9 @@ see "binary" cells in the table above.
|
||||
|
||||
!!! note
|
||||
|
||||
Prior to version 3.8.0, NaN and Infinity were instead serialized as a CBOR double-precision float (type 0xFB,
|
||||
9 bytes total).
|
||||
Prior to version 3.13.0, NaN and Infinity were instead serialized as a CBOR double-precision float (type 0xFB,
|
||||
9 bytes total), because the check used to select a smaller encoding compared magnitudes with NaN, which is
|
||||
always `false` and caused the intended half-precision path to be skipped.
|
||||
|
||||
!!! info "Unused CBOR types"
|
||||
|
||||
@@ -140,6 +124,7 @@ see "binary" cells in the table above.
|
||||
- expected conversions (0xD5..0xD7)
|
||||
- simple values (0xE0..0xF3, 0xF8)
|
||||
- undefined (0xF7)
|
||||
- half-precision floats (0xF9)
|
||||
- break (0xFF)
|
||||
|
||||
!!! info "Tagged items"
|
||||
@@ -241,20 +226,10 @@ string of the same major type, as required by [RFC 8949, Section 3.2.3](https://
|
||||
([RFC 8392](https://www.rfc-editor.org/rfc/rfc8392.html)), cannot be read with this library and need a
|
||||
general-purpose CBOR library instead.
|
||||
|
||||
A tag in front of a text string key is handled like a tag in front of a value: it is skipped with
|
||||
`cbor_tag_handler_t::ignore` or `cbor_tag_handler_t::store` and rejected with the default `error`. A tag does not
|
||||
turn a key of another type into a text string.
|
||||
|
||||
A map with duplicate keys is well-formed, but invalid under
|
||||
[RFC 8949, Section 5.3.1](https://www.rfc-editor.org/rfc/rfc8949.html#section-5.3.1). `from_cbor` accepts it and the
|
||||
last value wins; the [SAX interface](../parsing/sax_interface.md) reports every occurrence.
|
||||
|
||||
!!! warning "Ill-formed UTF-8 in text strings"
|
||||
|
||||
[RFC 8949, Section 3.1](https://www.rfc-editor.org/rfc/rfc8949.html#section-3.1) requires CBOR text strings (major
|
||||
type 3) to be valid UTF-8 (a string with ill-formed UTF-8 is "well-formed but invalid"), and
|
||||
[Section 5.3.1](https://www.rfc-editor.org/rfc/rfc8949.html#section-5.3.1) leaves it up to the decoder whether to
|
||||
verify this, so checking is opt-in: with the
|
||||
type 3) to be valid UTF-8, but leaves it up to the decoder whether to enforce this, so checking is opt-in: with the
|
||||
[`error_handler`](../../api/basic_json/from_cbor.md) parameter left at `keep` (the default), `from_cbor()` accepts a
|
||||
text string (object keys included) whose bytes are not valid UTF-8 and hands them back unchanged. Passing
|
||||
`error_handler_t::strict` makes `from_cbor()` check and throw
|
||||
@@ -267,14 +242,9 @@ string of the same major type, as required by [RFC 8949, Section 3.2.3](https://
|
||||
[`JSON_STRICT_BINARY_UTF8`](../../api/macros/json_strict_binary_utf8.md) is enabled), it throws the same exception
|
||||
instead. Byte strings (major type 2) are unaffected, since they are not required to hold text.
|
||||
|
||||
The chunks of an indefinite-length text string are checked one by one, as required by
|
||||
[RFC 8949, Section 3.2.3](https://www.rfc-editor.org/rfc/rfc8949.html#section-3.2.3): a code point cannot be spread
|
||||
over two chunks. With `error_handler_t::strict` such a string throws `parse_error.113`; `replace` and `ignore`
|
||||
sanitize each chunk on its own.
|
||||
|
||||
!!! warning "Tagged items"
|
||||
|
||||
Tagged items (0xC0..0xDB) will throw a parse error by default. They can be ignored by passing `cbor_tag_handler_t::ignore` to function `from_cbor`, in which case the tag is skipped and the enclosed data item is parsed on its own. Passing `cbor_tag_handler_t::store` to function `from_cbor` stores tagged byte strings (for bytes 0xd8..0xdb) as binary values with the tag as subtype; other tagged values are read as if the tag were ignored. If several tags precede a byte string, only the tag directly in front of it is stored, and only when it has the form 0xD8..0xDB (a tag 0..23 written as 0xC0..0xD7 is skipped); for example, `D8 05 C1 41 AA` yields subtype `null`, whereas `C1 D8 05 41 AA` yields 5. Tags in front of a text string map key are skipped as well. Note that no tag is ever interpreted: for instance, a text string tagged with tag 0 (date/time) stays a string.
|
||||
Tagged items (0xC0..0xDB) will throw a parse error by default. They can be ignored by passing `cbor_tag_handler_t::ignore` to function `from_cbor`, in which case the tag is skipped and the enclosed data item is parsed on its own. Passing `cbor_tag_handler_t::store` to function `from_cbor` stores tagged byte strings (for bytes 0xd8..0xdb) as binary values with the tag as subtype; other tagged values are read as if the tag were ignored. If several tags precede a byte string, only the innermost one is stored. Note that no tag is ever interpreted: for instance, a text string tagged with tag 0 (date/time) stays a string.
|
||||
|
||||
??? example "Example: deserialize a JSON value from CBOR"
|
||||
|
||||
|
||||
@@ -17,19 +17,19 @@ to efficiently encode JSON values to byte vectors and to decode such vectors.
|
||||
### Completeness
|
||||
|
||||
| Format | Serialization | Deserialization |
|
||||
|-------------|-----------------------------------------------|-----------------------------------------------------------------------|
|
||||
| BJData | complete | incomplete: no column-major ND-arrays, no Draft 4 SoA/extension types |
|
||||
|-------------|-----------------------------------------------|----------------------------------------------|
|
||||
| BJData | complete | complete |
|
||||
| BON8 | incomplete: no unsigned integers above int64 | complete |
|
||||
| BSON | incomplete: top-level value must be an object | incomplete, but all JSON types are supported |
|
||||
| CBOR | complete | incomplete, but all JSON types are supported |
|
||||
| MessagePack | complete | incomplete, but all JSON types are supported |
|
||||
| MessagePack | complete | complete |
|
||||
| UBJSON | complete | complete |
|
||||
|
||||
### Binary values
|
||||
|
||||
| Format | Binary values | Binary subtypes |
|
||||
|-------------|--------------------------|-----------------|
|
||||
| BJData | supported (Draft 3 only) | not supported |
|
||||
|-------------|---------------|-----------------|
|
||||
| BJData | not supported | not supported |
|
||||
| BON8 | not supported | not supported |
|
||||
| BSON | supported | supported |
|
||||
| CBOR | supported | supported |
|
||||
|
||||
@@ -11,7 +11,7 @@ extra byte in addition to the strings themselves.
|
||||
|
||||
## Byte layout
|
||||
|
||||
MessagePack encodes each value as a one-byte *format marker*, optionally followed by a length or the payload. The marker range is partitioned to keep common values small: small non-negative integers (0 to 127) and small negative integers (-32 to -1) are the marker byte itself; short strings, arrays, and maps (up to 31 bytes for strings and up to 15 elements for arrays and maps) hide their length in the marker's lower bits. Larger values use dedicated markers that announce the width (8, 16, 32, or 64 bits) of the length or number that follows, in big-endian byte order. Like CBOR, containers are length-prefixed, so no terminator is needed.
|
||||
MessagePack encodes each value as a one-byte *format marker*, optionally followed by a length or the payload. The marker range is partitioned to keep common values small: small non-negative integers (0 to 127) and small negative integers (-32 to -1) are the marker byte itself; short strings, arrays, and maps (up to 31 or 15 elements) hide their length in the marker's lower bits. Larger values use dedicated markers that announce the width (8, 16, 32, or 64 bits) of the length or number that follows, in big-endian byte order. Like CBOR, containers are length-prefixed, so no terminator is needed.
|
||||
|
||||
Consider the following JSON value (shown formatted for readability):
|
||||
|
||||
@@ -109,9 +109,8 @@ specification:
|
||||
!!! note
|
||||
|
||||
Prior to version 3.13.0, NaN and Infinity were instead serialized as a MessagePack float 64 (type 0xCB, 9 bytes
|
||||
total), because the check used to select the smaller float 32 encoding failed for NaN (all comparisons are `false`)
|
||||
and for Infinity and -Infinity (outside the float range checked against `std::numeric_limits<float>::lowest()` and
|
||||
`max()`), so the float 32 path was skipped.
|
||||
total), because the check used to select the smaller float 32 encoding compared magnitudes with NaN, which is
|
||||
always `false` and caused the float 32 path to be skipped.
|
||||
|
||||
??? example "Example: serialize a JSON value to MessagePack"
|
||||
|
||||
@@ -136,7 +135,6 @@ The library maps MessagePack types to JSON value types as follows:
|
||||
| fixarray | array | 0x90..0x9F |
|
||||
| fixstr | string | 0xA0..0xBF |
|
||||
| nil | `null` | 0xC0 |
|
||||
| (never used) | – | 0xC1 |
|
||||
| false | `false` | 0xC2 |
|
||||
| true | `true` | 0xC3 |
|
||||
| float 32 | number_float | 0xCA |
|
||||
@@ -169,30 +167,6 @@ The library maps MessagePack types to JSON value types as follows:
|
||||
| fixext 16 | binary | 0xD8 |
|
||||
| negative fixint | number_integer | 0xE0-0xFF |
|
||||
|
||||
The byte 0xC1 is reserved as "never used" by the specification. As a value it is rejected with
|
||||
[`parse_error.112`](../../home/exceptions.md#jsonexceptionparse_error112) (`invalid byte: 0xC1`); as a map key it is
|
||||
rejected with [`parse_error.113`](../../home/exceptions.md#jsonexceptionparse_error113) and the generic "expected length
|
||||
specification" message, because the key is read as a string.
|
||||
|
||||
Duplicate keys in a map are accepted; the last value wins.
|
||||
|
||||
### Extension types (ext, fixext)
|
||||
|
||||
MessagePack ext and fixext values are read as binary values, and the ext type byte is stored as the binary subtype.
|
||||
Although the specification defines the type as a signed 8-bit integer (0 to 127 for applications, -128 to -1 reserved,
|
||||
with -1 being the Timestamp extension), the library reads it as an unsigned byte: a negative ext type `n` becomes
|
||||
subtype `256+n`, so ext type -1 is read as subtype 255 and -128 as subtype 128. The Timestamp extension is not
|
||||
interpreted; it is returned as binary with subtype 255. Use
|
||||
[`has_subtype()`](../../api/byte_container_with_subtype/has_subtype.md) to tell a `bin` value (no subtype) from an ext
|
||||
value (subtype, even if it is 0).
|
||||
|
||||
When serializing, a binary value with a subtype is always written as fixext (1, 2, 4, 8, or 16 bytes) or ext, even
|
||||
for subtype 0 (`d6 00 01 02 03 04`); a binary value without a subtype is written as bin. Subtypes 128 to 255 are
|
||||
written as the reserved negative ext types (255 as -1), so `json::binary({1,2,3,4}, 255)` becomes
|
||||
`d6 ff 01 02 03 04`, which other MessagePack libraries decode as a 32-bit timestamp. A subtype above 255 throws
|
||||
[`out_of_range.415`](../../home/exceptions.md#jsonexceptionout_of_range415). The payload length is limited to
|
||||
4294967295 bytes like all other lengths.
|
||||
|
||||
!!! info
|
||||
|
||||
Any MessagePack output created by `to_msgpack` can be successfully parsed by `from_msgpack`.
|
||||
@@ -203,8 +177,7 @@ written as the reserved negative ext types (255 as -1), so `json::binary({1,2,3,
|
||||
JSON-compatible [profile](https://github.com/msgpack/msgpack/blob/master/spec.md#profile) sketched in the
|
||||
MessagePack specification, this library restricts map keys to `str` values. Maps with keys of any other type are
|
||||
rejected with a [`parse_error.113`](../../home/exceptions.md#jsonexceptionparse_error113) exception (or, with
|
||||
`allow_exceptions` set to `false`, a discarded value). For most key types the message names the type that was
|
||||
found, for instance:
|
||||
`allow_exceptions` set to `false`, a discarded value) naming the type of the key that was found, for instance:
|
||||
|
||||
```
|
||||
[json.exception.parse_error.113] parse error at byte 2: syntax error while parsing MessagePack object key: only string keys are supported, but found nil; last byte: 0xC0
|
||||
@@ -216,7 +189,7 @@ written as the reserved negative ext types (255 as -1), so `json::binary({1,2,3,
|
||||
!!! warning "Ill-formed UTF-8 in string values"
|
||||
|
||||
The MessagePack specification explicitly allows a `str` value (`fixstr`, `str 8`, `str 16`, `str 32`) to contain
|
||||
a byte sequence that is not valid UTF-8, and recommends that a deserializer provide a way to obtain the original bytes.
|
||||
a byte sequence that is not valid UTF-8, and expects a deserializer to hand the original bytes back unchanged.
|
||||
This library follows that by default: with its
|
||||
[`error_handler`](../../api/basic_json/from_msgpack.md) parameter left at `keep` (the default),
|
||||
`from_msgpack()` reads `str` bytes (object keys included) as-is, without validating them, so such a value
|
||||
|
||||
@@ -5,11 +5,11 @@ achieve the generality of JSON, combined with being much easier to process than
|
||||
|
||||
!!! abstract "References"
|
||||
|
||||
- [UBJSON Website](https://ubjson.org)
|
||||
- [UBJSON Website](http://ubjson.org)
|
||||
|
||||
## Byte layout
|
||||
|
||||
UBJSON is built from just a one-byte, human-readable ASCII *type marker* (for example, `i` for int8, `S` for string, `[` for array) followed by the payload of that type. Strings and the like are prefixed with their length, which is itself a UBJSON integer value including its marker. Numbers are stored in big-endian byte order. Containers can be written in two ways: as an *unoptimized* container that is opened with `[` or `{` and closed with `]` or `}`, or as an *optimized* container that declares a count (`#`) after the opening marker, optionally preceded by an element type (`$`); an element type is only allowed together with a count. An optimized container saves the closing marker and, with a type, the per-element markers.
|
||||
UBJSON is built from just a one-byte, human-readable ASCII *type marker* (for example, `i` for int8, `S` for string, `[` for array) followed by the payload of that type. Strings and the like are prefixed with their length, which is itself a UBJSON integer value including its marker. Numbers are stored in big-endian byte order. Containers can be written in two ways: as an *unoptimized* container that is opened with `[` or `{` and closed with `]` or `}`, or as an *optimized* container that declares an element type (`$`) and/or a count (`#`) after the opening marker, which saves per-element markers and (for a count) the closing marker.
|
||||
|
||||
Consider the following JSON value (shown formatted for readability):
|
||||
|
||||
@@ -45,7 +45,7 @@ Consider the following JSON value (shown formatted for readability):
|
||||
The library uses the following mapping from JSON values types to UBJSON types according to the UBJSON specification:
|
||||
|
||||
| JSON value type | value/range | UBJSON type | marker |
|
||||
|-----------------|-------------------------------------------|--------------------------------------------------|-----------|
|
||||
|-----------------|-------------------------------------------|----------------|--------|
|
||||
| null | `null` | null | `Z` |
|
||||
| boolean | `true` | true | `T` |
|
||||
| boolean | `false` | false | `F` |
|
||||
@@ -63,10 +63,10 @@ The library uses the following mapping from JSON values types to UBJSON types ac
|
||||
| number_unsigned | 32768..2147483647 | int32 | `l` |
|
||||
| number_unsigned | 2147483648..9223372036854775807 | int64 | `L` |
|
||||
| number_unsigned | 9223372036854775808..18446744073709551615 | high-precision | `H` |
|
||||
| number_float | *any value* | float64 (float32 if `number_float_t` is `float`) | `D` (`d`) |
|
||||
| number_float | *any value* | float64 | `D` |
|
||||
| string | *with shortest length indicator* | string | `S` |
|
||||
| array | *see notes on optimized format* | array | `[` |
|
||||
| object | *see notes on optimized format* | object | `{` |
|
||||
| object | *see notes on optimized format* | map | `{` |
|
||||
|
||||
!!! success "Complete mapping"
|
||||
|
||||
@@ -93,27 +93,20 @@ The library uses the following mapping from JSON values types to UBJSON types ac
|
||||
|
||||
The following markers are not used in the conversion:
|
||||
|
||||
- `N`: no-op values are never written (they are skipped when reading).
|
||||
- `Z`: no-op values are not created.
|
||||
- `C`: single-byte strings are serialized with `S` markers.
|
||||
|
||||
!!! info "NaN/infinity handling"
|
||||
|
||||
NaN and infinity are written as IEEE 754 float64 values (`D`) and read back unchanged. This differs from
|
||||
[`dump()`](../../api/basic_json/dump.md), which serializes them to `null`, and from the UBJSON specification, which
|
||||
encodes infinity as `null` (it does not mention NaN); other UBJSON readers may therefore not accept these values.
|
||||
If NaN or Infinity are stored inside a JSON number, they are serialized properly. This behavior differs from the
|
||||
[`dump()`](../../api/basic_json/dump.md) function which serializes NaN or Infinity to `null`.
|
||||
|
||||
!!! info "Optimized formats"
|
||||
|
||||
The optimized formats for containers are supported: Parameter `use_size` adds size information to the beginning of a
|
||||
container and removes the closing marker. Parameter `use_type` further checks whether all elements of a container
|
||||
have the same type and adds the type marker to the beginning of the container. The `use_type` parameter must only be
|
||||
used together with `use_size = true`: combining `use_type` with `use_size = false` throws
|
||||
[`other_error.502`](../../home/exceptions.md#jsonexceptionother_error502) if the value contains a non-empty array,
|
||||
object, or binary value.
|
||||
|
||||
Two elements have the same type if they are written with the same type marker. For example, `[1, 2]` is written with
|
||||
the type `i`, but `[1, 200]` (`i`, `U`), `[true, false]` (`T`, `F`), and `[1, 2.5]` (`i`, `D`) are not; an empty
|
||||
container is never given a `$` annotation of its own (an array of empty arrays is still typed `[`).
|
||||
used together with `use_size = true`.
|
||||
|
||||
Note that `use_size = true` alone may result in larger representations - the benefit of this parameter is that the
|
||||
receiving side is immediately informed on the number of elements of the container.
|
||||
@@ -122,9 +115,8 @@ The library uses the following mapping from JSON values types to UBJSON types ac
|
||||
already is the value. Its declared count is therefore the only thing that decides how much memory the receiving side
|
||||
allocates, and a handful of bytes can describe billions of elements. `from_ubjson` rejects such an array with
|
||||
[`out_of_range.408`](../../home/exceptions.md#jsonexceptionout_of_range408) when the count exceeds 1,048,576
|
||||
(`1 << 20`), and `to_ubjson` writes longer arrays of these types in the counted but untyped form: the `$` type marker is
|
||||
dropped, the `#` count is kept, and every element is written with its own marker (`[#l 1048577 Z Z ...`), so any value
|
||||
it produces can be read back. Objects and untyped counted arrays are not subject to this limit.
|
||||
(`1 << 20`), and `to_ubjson` writes longer arrays of these types without the annotation, so any value it produces
|
||||
can be read back.
|
||||
|
||||
!!! info "Binary values"
|
||||
|
||||
@@ -149,7 +141,7 @@ The library uses the following mapping from JSON values types to UBJSON types ac
|
||||
The library maps UBJSON types to JSON value types as follows:
|
||||
|
||||
| UBJSON type | JSON value type | marker |
|
||||
|----------------|--------------------------------------------------|--------|
|
||||
|-------------|-----------------------------------------|--------|
|
||||
| no-op | *no value, next value is read* | `N` |
|
||||
| null | `null` | `Z` |
|
||||
| false | `false` | `F` |
|
||||
@@ -163,39 +155,12 @@ The library maps UBJSON types to JSON value types as follows:
|
||||
| int64 | number_integer | `L` |
|
||||
| string | string | `S` |
|
||||
| char | string | `C` |
|
||||
| high-precision | number_unsigned, number_integer, or number_float | `H` |
|
||||
| array | array (optimized values are supported) | `[` |
|
||||
| object | object (optimized values are supported) | `{` |
|
||||
|
||||
!!! info "High-precision numbers"
|
||||
|
||||
The payload of `H` is a length-prefixed string that is parsed as a JSON number (surrounding whitespace is ignored).
|
||||
Integer text in the range of `number_unsigned_t` (non-negative) or `number_integer_t` (negative) is stored as such;
|
||||
any other valid number text (larger or smaller integers, fractions, and exponents such as `1e2`) is stored as
|
||||
`number_float`, so precision may be lost. Text that is not a valid JSON number raises
|
||||
[`parse_error.115`](../../home/exceptions.md#jsonexceptionparse_error115), a number outside the range of
|
||||
`number_float_t` (`1e999`) raises [`out_of_range.406`](../../home/exceptions.md#jsonexceptionout_of_range406).
|
||||
|
||||
!!! success "Complete mapping"
|
||||
|
||||
Every well-formed UBJSON value can be converted to a JSON value, with these exceptions: a high-precision number
|
||||
outside the range of `number_float_t` ([`out_of_range.406`](../../home/exceptions.md#jsonexceptionout_of_range406)),
|
||||
an optimized array of `Z`, `T`, or `F` with more than 1,048,576 elements, and a count that exceeds the capacity of the
|
||||
container ([`out_of_range.408`](../../home/exceptions.md#jsonexceptionout_of_range408)). High-precision numbers that
|
||||
do not fit an integer type are stored as floating-point numbers and may lose precision. Ill-formed input is rejected
|
||||
with a parse error.
|
||||
|
||||
!!! info "Duplicate object keys"
|
||||
|
||||
If an object contains the same key more than once, the last value is kept (the UBJSON specification does not
|
||||
address duplicate keys).
|
||||
|
||||
!!! info "Type marker of optimized containers"
|
||||
|
||||
The type marker after `$` must be one of `Z`, `N`, `T`, `F`, `i`, `U`, `I`, `l`, `L`, `d`, `D`, `H`, `C`, `S`, `[`, or
|
||||
`{`. It is checked even if the count is 0; any other marker raises
|
||||
[`parse_error.112`](../../home/exceptions.md#jsonexceptionparse_error112). A counted object typed `N` (`{$N#i1 ...`)
|
||||
is not supported.
|
||||
The mapping is **complete** in the sense that any UBJSON value can be converted to a JSON value.
|
||||
|
||||
!!! warning "Ill-formed UTF-8 in string values and object keys"
|
||||
|
||||
|
||||
@@ -132,11 +132,8 @@ is an integer or `null`.
|
||||
|
||||
### BJData
|
||||
|
||||
[BJData](binary_formats/bjdata.md) Draft 3 supports binary values as optimized arrays of `B` (byte) elements, but no
|
||||
subtypes. With `version = bjdata_version_t::draft3` and both `use_size` and `use_type` set, `to_bjdata` writes a binary
|
||||
value as `[$B#...`, and `from_bjdata` reads it back as a binary value (without subtype). In all other cases, including
|
||||
the default Draft 2 mode, the library follows the Draft 2 proposal and writes an array of integers (`U` in Draft 2, `B`
|
||||
in Draft 3), which is read back as an array.
|
||||
[BJData](binary_formats/bjdata.md) neither supports binary values nor subtypes and proposes to serialize binary values
|
||||
as an array of uint8 values. The library implements this translation.
|
||||
|
||||
??? example "Example: serialize a binary value to BJData"
|
||||
|
||||
@@ -174,7 +171,7 @@ in Draft 3), which is read back as an array.
|
||||
|
||||
```c
|
||||
0x7B // '{'
|
||||
0x23 0x69 0x01 // '#' 'i' 1 number of object members
|
||||
0x23 0x69 0x01 // '#' 'i' type of the array elements: unsigned integers
|
||||
0x69 0x06 // i 6 (length of the key)
|
||||
0x62 0x69 0x6E 0x61 0x72 0x79 // "binary"
|
||||
0x5B // '[' array
|
||||
@@ -183,7 +180,7 @@ in Draft 3), which is read back as an array.
|
||||
0xCA 0xFE 0xBA 0xBE // content
|
||||
```
|
||||
|
||||
Note that subtype (42) is **not** serialized and that, in Draft 2 mode, BJData has **no binary type**, and deserializing `v` would
|
||||
Note that subtype (42) is **not** serialized and that BJData has **no binary type**, and deserializing `v` would
|
||||
yield the following value:
|
||||
|
||||
```json
|
||||
@@ -216,7 +213,7 @@ array of integers.
|
||||
0x87 // object with 1 member
|
||||
0x62 0x69 0x6E 0x61 0x72 0x79 // "binary"
|
||||
0x84 // array with 4 elements
|
||||
0xC3 0x22 0xC3 0x56 0xC3 0x12 0xC3 0x16 // content (each byte, here all above 39, as a 2-byte integer)
|
||||
0xC3 0x22 0xC3 0x56 0xC3 0x12 0xC3 0x16 // content (each byte as a 2-byte integer)
|
||||
```
|
||||
|
||||
Note that the subtype is lost, and deserializing `v` would yield the following value:
|
||||
@@ -230,10 +227,7 @@ array of integers.
|
||||
### BSON
|
||||
|
||||
[BSON](binary_formats/bson.md) supports binary values and subtypes. If a subtype is given, it is used and added as an
|
||||
unsigned 8-bit integer; a subtype above 255 throws
|
||||
[`out_of_range.415`](../home/exceptions.md#jsonexceptionout_of_range415). If no subtype is given, the generic binary
|
||||
subtype 0x00 is used. The payload of the "old binary" subtype 0x02 is preceded by a second length, which the library
|
||||
writes and removes again when reading; it is not part of the payload.
|
||||
unsigned 8-bit integer. If no subtype is given, the generic binary subtype 0x00 is used.
|
||||
|
||||
??? example "Example: serialize a binary value to BSON"
|
||||
|
||||
@@ -307,8 +301,6 @@ representation using the length of the byte array.
|
||||
[`json::from_cbor`](../api/basic_json/from_cbor.md) (see
|
||||
[`cbor_tag_handler_t`](../api/basic_json/cbor_tag_handler_t.md)).
|
||||
|
||||
With `ignore`, the subtype is dropped (`"subtype": null`); with `store`, the tag is kept (`"subtype": 42`):
|
||||
|
||||
```json
|
||||
{
|
||||
"binary": {
|
||||
@@ -318,21 +310,11 @@ representation using the length of the byte array.
|
||||
}
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"binary": {
|
||||
"bytes": [202, 254, 186, 190],
|
||||
"subtype": 42
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### MessagePack
|
||||
|
||||
[MessagePack](binary_formats/messagepack.md) supports binary values and subtypes. If a subtype is given, the ext family
|
||||
is used. The library will choose the smallest representation among fixext1, fixext2, fixext4, fixext8, fixext16, ext8,
|
||||
ext16, and ext32. The subtype is then written as the signed 8-bit ext type: subtypes 128 to 255 map to the negative
|
||||
(reserved) ext types, and on reading the ext type is exposed as an unsigned subtype from 0 to 255.
|
||||
is used. The library will choose the smallest representation among fixext1, fixext2, fixext4, fixext8, ext8, ext16, and
|
||||
ext32. The subtype is then added as a signed 8-bit integer.
|
||||
|
||||
If no subtype is given, the bin family (bin8, bin16, bin32) is used.
|
||||
|
||||
|
||||
@@ -185,10 +185,6 @@ key as well. Other zero-copy parsers that index the source text, such as yyjson
|
||||
member. RFC 8259 only says that names within an object SHOULD be unique and that the behavior of a receiver that sees
|
||||
duplicates is unpredictable, so neither choice is wrong.
|
||||
|
||||
The same holds for [`get<T>()`](../api/basic_json_view/get.md) of a type whose `from_json()` reads the view, such as
|
||||
the types of the `NLOHMANN_DEFINE_TYPE_*` macros: their members are looked up, so `#!cpp get<point>()` of
|
||||
`#!cpp {"x":1,"x":2}` reads `#!cpp x == 1`, while `#!cpp materialize().get<point>()` reads `#!cpp 2`.
|
||||
|
||||
**What stays the same as `parse()`?** [`materialize()`](../api/basic_json_view/materialize.md) and
|
||||
[`get<std::map<...>>()`](../api/basic_json_view/get.md) replay every member in order, so they keep the *last* value
|
||||
exactly like `#!cpp basic_json::parse()` (at the position of the first occurrence of the key, for an
|
||||
@@ -214,15 +210,14 @@ number of distinct keys, or reject duplicates when iterating.
|
||||
|
||||
## Getting values out without copying
|
||||
|
||||
[`get<T>()`](../api/basic_json_view/get.md) converts most `T` directly from the flat index, without ever building a
|
||||
[`get<T>()`](../api/basic_json_view/get.md) converts many `T` directly from the flat index, without ever building a
|
||||
`basic_json` value for the conversion: `#!cpp bool`, arithmetic types, `#!cpp std::nullptr_t`,
|
||||
`#!cpp std::string`/other `#!cpp std::basic_string`s (copied once), `basic_json_view` itself, the standard containers
|
||||
and other types the library converts (`#!cpp std::vector`, `#!cpp std::map`, `#!cpp std::list`, `#!cpp std::array`,
|
||||
`#!cpp std::pair`, `#!cpp std::tuple`, `#!cpp std::optional`, ...), and the types of the `NLOHMANN_DEFINE_TYPE_*` and
|
||||
`NLOHMANN_JSON_SERIALIZE_ENUM` macros. Types whose `from_json()` is written for `basic_json` only go through
|
||||
`#!cpp std::string`/other `#!cpp std::basic_string`s (copied once), `basic_json`/`ordered_json` (via
|
||||
[`materialize()`](../api/basic_json_view/materialize.md)), `basic_json_view` itself, `#!cpp std::vector<U>`, and
|
||||
`#!cpp std::map`/`#!cpp std::unordered_map` with string-like keys. Every other type -- `#!cpp std::list`,
|
||||
`#!cpp std::pair`, `#!cpp std::array`, enumerations, user types with a `from_json()` -- goes through
|
||||
[`materialize()`](../api/basic_json_view/materialize.md)`.get<T>()` instead: the subtree is built into a real
|
||||
`basic_json` value first, exactly as [`parse()`](../api/basic_json/parse.md) would, and converted from there. See
|
||||
[Writing generic code](#writing-generic-code) for how to write a `from_json()` that reads views.
|
||||
`basic_json` value first, exactly as [`parse()`](../api/basic_json/parse.md) would, and converted from there.
|
||||
|
||||
Two conversions never copy at all:
|
||||
|
||||
@@ -237,93 +232,6 @@ Two conversions never copy at all:
|
||||
|
||||
Both results are only valid as long as the view -- and, for a string with no escapes, the borrowed source text -- is.
|
||||
|
||||
## Writing generic code
|
||||
|
||||
A view's type names its `BasicJsonType` and its [`view_mode`](../api/view_mode.md):
|
||||
[`json_view`](../api/json_view.md) is `#!cpp basic_json_view<json, view_mode::read_only>`, and
|
||||
[`json_editable_view`](../api/json_editable_view.md) is `#!cpp basic_json_view<json, view_mode::editable>`. These are
|
||||
different types. The only conversion between them turns a view of a read-only document into a view of an editable
|
||||
document of the same `BasicJsonType`, so a function written for one shortcut accepts few other views:
|
||||
|
||||
```cpp
|
||||
void print_names(json_view v); // accepts neither an ordered_json_view nor a json_editable_view
|
||||
void print_names(json_editable_view v); // also accepts a json_view, but no ordered_json_view
|
||||
```
|
||||
|
||||
This is the same pitfall as a `to_json`/`from_json` written for `json` instead of any `BasicJsonType`, which then does
|
||||
not work for `ordered_json`. The shortcuts are for declaring documents and views; a function that takes a view names
|
||||
the views it accepts with a template:
|
||||
|
||||
```cpp
|
||||
// views of editable documents only
|
||||
template<typename BasicJsonType>
|
||||
void f(basic_json_view<BasicJsonType, view_mode::editable> v);
|
||||
|
||||
// views of read-only documents only
|
||||
template<typename BasicJsonType>
|
||||
void f(basic_json_view<BasicJsonType, view_mode::read_only> v);
|
||||
|
||||
// views of either document type
|
||||
template<typename BasicJsonType, view_mode Mode>
|
||||
void f(basic_json_view<BasicJsonType, Mode> v);
|
||||
```
|
||||
|
||||
Views are passed by value: they are two pointers, cheap to copy, like a `#!cpp std::string_view`. A `const&` works as
|
||||
well, but a non-`const` reference does not bind to the views that [`root()`](../api/basic_json_document/root.md),
|
||||
[`operator[]`](../api/basic_json_view/operator%5B%5D.md), and [`at()`](../api/basic_json_view/at.md) return, so
|
||||
`#!cpp f(doc.root())` would not compile.
|
||||
|
||||
There is no conversion from an editable view to a read-only one, by design: the mode decides how a view walks the
|
||||
index. A read-only view reads a container in place, while a view of an editable document follows the links that edits
|
||||
leave behind, so a read-only view of an edited document would read stale values. The other direction is safe: a
|
||||
read-only document has no edits, so a view of it [converts](../api/basic_json_view/basic_json_view.md) to an
|
||||
editable view, which reads it like an editable document before its first edit. A template deduces the mode without
|
||||
conversions, so the template forms above still accept only the modes they name. Views of both modes compare with
|
||||
[`operator==`](../api/basic_json_view/operator_eq.md).
|
||||
|
||||
[`is_json_view<T>`](../api/is_json_view.md) tells views from other types, for constraints that cannot be written as a
|
||||
`basic_json_view<...>` parameter.
|
||||
|
||||
### A `from_json()` that reads views
|
||||
|
||||
[`get<T>()`](../api/basic_json_view/get.md) on a view calls `T`'s `from_json()` with the view itself if that
|
||||
`from_json()` accepts views, and with [`materialize()`](../api/basic_json_view/materialize.md) otherwise. The
|
||||
`from_json()` functions of the [`NLOHMANN_DEFINE_TYPE_*`](../api/macros/nlohmann_define_type_intrusive.md),
|
||||
[`NLOHMANN_DEFINE_DERIVED_TYPE_*`](../api/macros/nlohmann_define_derived_type.md), and
|
||||
[`NLOHMANN_JSON_SERIALIZE_ENUM`](../api/macros/nlohmann_json_serialize_enum.md) macros, and those of the library
|
||||
for the standard types, accept views, so these types need nothing else. For decoding the statuses of
|
||||
twitter.json into structs, reading the view is about 5 times faster than `#!cpp materialize().get<T>()`.
|
||||
|
||||
A hand-written `from_json()` reads views if it is constrained to `json` values and views:
|
||||
|
||||
```cpp
|
||||
template < typename J, typename std::enable_if <
|
||||
nlohmann::is_json_view<J>::value || std::is_same<J, nlohmann::json>::value, int >::type = 0 >
|
||||
void from_json(const J& j, person& p)
|
||||
{
|
||||
p.name = j.at("name").template get<std::string>();
|
||||
p.age = j.at("age").template get<int>();
|
||||
}
|
||||
```
|
||||
|
||||
Its body may only use what views and `basic_json` have in common: the type checks, `at()`, `operator[]`, `contains()`,
|
||||
`value()`, `size()`, iteration and `items()`, and `get<T>()`/`get_to()`. An unconstrained
|
||||
`#!cpp template<typename BasicJsonType> void from_json(const BasicJsonType& j, person& p)`, as in
|
||||
[arbitrary type conversions](arbitrary_types.md), is never called with a view, as it might use `basic_json` functions
|
||||
a view does not have; such a type is converted through `materialize()`. A `from_json()` for `json` only is
|
||||
converted through `materialize()` as well.
|
||||
|
||||
Two things differ when a `from_json()` reads the view:
|
||||
|
||||
- **Duplicate keys.** Members looked up by name (`at()`, `value()`, ... and thus the macros) find the **first** member
|
||||
with a repeated key, see [Duplicate keys](#duplicate-keys); `#!cpp materialize().get<T>()` would see the last one.
|
||||
Containers built from an object, such as `#!cpp std::map`, keep the **last** value either way, as
|
||||
[`parse()`](../api/basic_json/parse.md) does.
|
||||
- **[`JSON_DIAGNOSTICS`](../api/macros/json_diagnostics.md).** Exceptions thrown by the view carry no path to the
|
||||
value.
|
||||
|
||||
`to_json()` is unaffected: it writes `basic_json` values, never views.
|
||||
|
||||
## Writing a view back
|
||||
|
||||
[`dump()`](../api/basic_json_view/dump.md) serializes a view directly from the flat index, without ever building a
|
||||
@@ -344,14 +252,14 @@ the stream's `width`/`fill` for indentation.
|
||||
## Editing a document
|
||||
|
||||
Everything above is read-only: a `json_document`/`json_view` lets you look at a parsed text without copying it, but
|
||||
not change it. [`basic_json_document<BasicJsonType, view_mode::editable>`](../api/basic_json_document/index.md) -- more conveniently
|
||||
not change it. [`basic_json_document<BasicJsonType, true>`](../api/basic_json_document/index.md) -- more conveniently
|
||||
spelled [`json_editable_document`](../api/json_editable_document.md) or
|
||||
[`ordered_json_editable_document`](../api/ordered_json_editable_document.md) -- also lets you
|
||||
[`set`](../api/basic_json_document/set.md) a value, [`push_back`](../api/basic_json_document/push_back.md) onto or
|
||||
[`insert`](../api/basic_json_document/insert.md) into an array, and [`erase`](../api/basic_json_document/erase.md)
|
||||
an object member or an array element, still without ever building a `basic_json` tree for parts you do not touch.
|
||||
|
||||
The [mode](../api/view_mode.md) defaults to `#!cpp view_mode::read_only`, so `json_document`/`ordered_json_document` are unaffected -- they carry
|
||||
`#!cpp Editable` defaults to `#!cpp false`, so `json_document`/`ordered_json_document` are unaffected -- they carry
|
||||
none of the bookkeeping edits need, and calling `set`/`push_back`/`insert`/`erase` on one is a compile error, not a
|
||||
runtime one.
|
||||
|
||||
@@ -446,10 +354,9 @@ validation entirely, for an image trusted as much as the process's own memory. S
|
||||
!!! warning "Experimental"
|
||||
|
||||
The image format is versioned but not yet stable, and may change in an incompatible way before it is declared
|
||||
stable. It is little-endian only (on big-endian targets, `save()` and `load()` do not exist), and tied to the
|
||||
library build that wrote it -- use it to cache a document or to hand one to another process running the *same*
|
||||
build, not as a long-term storage format; keep the original JSON text if a saved document needs to be readable by
|
||||
a future library version.
|
||||
stable. It is little-endian only, and tied to the library build that wrote it -- use it to cache a document or to
|
||||
hand one to another process running the *same* build, not as a long-term storage format; keep the original JSON
|
||||
text if a saved document needs to be readable by a future library version.
|
||||
|
||||
The idea of a document you can read without parsing comes from zero-copy formats such as
|
||||
[FlatBuffers](https://github.com/google/flatbuffers) and [YaFF](https://github.com/yandex/yaff); the check
|
||||
|
||||
@@ -287,6 +287,23 @@ external dependency and is not defined by default.
|
||||
|
||||
See [full documentation of `JSON_USE_SIMDUTF`](../api/macros/json_use_simdutf.md).
|
||||
|
||||
## `JSON_VIEW_NO_SIMD`
|
||||
|
||||
When defined, the parser of [`basic_json_document`](../api/basic_json_document/index.md)
|
||||
(`<nlohmann/json_view.hpp>`) uses only portable C++ to scan strings, instead of vector instructions (SSE2 on x86-64,
|
||||
NEON on AArch64). The same input is accepted or rejected either way; only the speed differs. It is not defined by
|
||||
default.
|
||||
|
||||
See [full documentation of `JSON_VIEW_NO_SIMD`](../api/macros/json_view_no_simd.md).
|
||||
|
||||
## `JSON_VIEW_USE_SSSE3`
|
||||
|
||||
When defined on x86-64, the parser of [`basic_json_document`](../api/basic_json_document/index.md)
|
||||
(`<nlohmann/json_view.hpp>`) validates non-ASCII text in strings with SSSE3 without asking the CPU first. It is not
|
||||
defined by default.
|
||||
|
||||
See [full documentation of `JSON_VIEW_USE_SSSE3`](../api/macros/json_view_use_ssse3.md).
|
||||
|
||||
## `NLOHMANN_DEFINE_TYPE_*(...)`, `NLOHMANN_DEFINE_DERIVED_TYPE_*(...)`
|
||||
|
||||
The library defines 12 macros to simplify the serialization/deserialization of types. See the page on
|
||||
|
||||
@@ -28,6 +28,8 @@ The complete default namespace name is derived as follows:
|
||||
- [`JSON_DISABLE_UNLOCKED_FILE_IO`](../api/macros/json_disable_unlocked_file_io.md) defined non-zero appends
|
||||
`_dufio`.
|
||||
- [`JSON_NO_SIMD`](../api/macros/json_no_simd.md) defined appends `_ns`.
|
||||
- [`JSON_VIEW_NO_SIMD`](../api/macros/json_view_no_simd.md) defined appends `_vns`.
|
||||
- [`JSON_VIEW_USE_SSSE3`](../api/macros/json_view_use_ssse3.md) defined appends `_vssse3`.
|
||||
- The inline namespace ends with the suffix `_v` followed by the 3 components of the version number separated by
|
||||
underscores. To omit the version component, see [Disabling the version component](#disabling-the-version-component)
|
||||
below.
|
||||
@@ -113,5 +115,7 @@ follows:
|
||||
([`JSON_STRICT_BINARY_UTF8`](../api/macros/json_strict_binary_utf8.md)), `_ekmo`
|
||||
([`JSON_USE_OBJECTS_FOR_ENUM_KEYED_MAPS`](../api/macros/json_use_objects_for_enum_keyed_maps.md)), `_dsbs`
|
||||
([`JSON_DISABLE_STREAM_BULK_SCAN`](../api/macros/json_disable_stream_bulk_scan.md)), `_dufio`
|
||||
([`JSON_DISABLE_UNLOCKED_FILE_IO`](../api/macros/json_disable_unlocked_file_io.md)), and `_ns`
|
||||
([`JSON_NO_SIMD`](../api/macros/json_no_simd.md)) in version 3.13.0.
|
||||
([`JSON_DISABLE_UNLOCKED_FILE_IO`](../api/macros/json_disable_unlocked_file_io.md)), `_ns`
|
||||
([`JSON_NO_SIMD`](../api/macros/json_no_simd.md)), `_vns`
|
||||
([`JSON_VIEW_NO_SIMD`](../api/macros/json_view_no_simd.md)), and `_vssse3`
|
||||
([`JSON_VIEW_USE_SSSE3`](../api/macros/json_view_use_ssse3.md)) in version 3.13.0.
|
||||
@@ -130,6 +130,17 @@ parameters of [`parse()`](../../api/basic_json/parse.md) or [`accept()`](../../a
|
||||
enable either for input whose conformance you cannot otherwise control, since interoperability with strictly
|
||||
conforming JSON consumers is exactly what the default rejects.
|
||||
|
||||
## JSON Pointers and flattened keys
|
||||
|
||||
A [JSON Pointer](../json_pointer.md) can come from untrusted input as well, for instance as a path in a request or as a
|
||||
key of a flattened object. The non-const [`operator[]`](../../api/basic_json/operator%5B%5D.md) with a JSON Pointer and
|
||||
[`unflatten`](../../api/basic_json/unflatten.md) create missing values, and when an array index lies beyond the end of
|
||||
an array, they fill the array with `#!json null` values up to that index. The memory used therefore grows with the
|
||||
index, not with the size of the pointer: on a 64-bit platform, the index `10000000` allocates about 160 MB, the index
|
||||
`100000000` about 1.6 GB. The library does not limit the index. For pointers from untrusted input, check the array
|
||||
indices (or the pointer as a whole) before using them, or use [`at`](../../api/basic_json/at.md) or
|
||||
[`contains`](../../api/basic_json/contains.md), which never add values.
|
||||
|
||||
## Checklist
|
||||
|
||||
- Wrap parsing in a `#!cpp try`/`#!cpp catch` block, or use `allow_exceptions=false`/`accept()` if your environment
|
||||
@@ -145,6 +156,8 @@ conforming JSON consumers is exactly what the default rejects.
|
||||
`JSON_STRICT_NUL_HANDLING`.
|
||||
- Decide whether duplicate object keys should be an error for your application, and add a callback if so.
|
||||
- Do not enable `ignore_comments` or `ignore_trailing_commas` for input that must be strictly conforming JSON.
|
||||
- Check the array indices of untrusted JSON Pointers and flattened keys before passing them to the non-const
|
||||
`operator[]` or `unflatten()`, which fill arrays with `#!json null` values up to the index.
|
||||
|
||||
For the broader design rationale and how it is tested (fuzzing, sanitizers, static analysis), see the
|
||||
[assurance case](../../community/assurance_case.md) and [quality assurance](../../community/quality_assurance.md). To
|
||||
|
||||
@@ -368,7 +368,8 @@ using array_t = ArrayType<basic_json, AllocatorType<basic_json>>;
|
||||
`#!cpp std::from_chars` is not available or declines the token, and `std::strtold` reads up to the null character. A type whose `data()`
|
||||
is not null-terminated does not fail to compile; with such a `NumberFloatType` it can silently misparse
|
||||
floating-point numbers.
|
||||
- `append(const char*, size_type)`, used by [`dump`](../../api/basic_json/dump.md) and by the binary readers. The library's internal string concatenation additionally has
|
||||
- `append(const char*, size_type)`, used by [`dump`](../../api/basic_json/dump.md), and `append(const StringType&)`,
|
||||
used by the CBOR reader for indefinite-length strings. The library's internal string concatenation additionally has
|
||||
to append a `#!cpp char` and a `#!cpp const char*`; for each it selects between `append(arg)`, `#!cpp operator+=`,
|
||||
`append(first, last)`, and `append(data, size)`.
|
||||
- The comparison operator `==` against another `StringType`, and `<` for use as a key of the chosen
|
||||
@@ -678,7 +679,8 @@ using binary_t = nlohmann::byte_container_with_subtype<BinaryType>;
|
||||
[`StringType`](#stringtype), whose non-`#!cpp const` `data()` is C++17 and later only.
|
||||
- Default-constructible, copy-constructible, and move-constructible.
|
||||
- Member functions `size()`, `empty()`, `data()`, `resize()`, `operator[]`, `back()`, `begin()`, `end()`, `cbegin()`,
|
||||
and `cend()` with random-access iterators. `push_back()` is **not** required.
|
||||
and `cend()` with random-access iterators, and `insert(pos, first, last)`, which the CBOR reader uses to join the
|
||||
chunks of an indefinite-length byte string. `push_back()` is **not** required.
|
||||
- Comparison operators: `==` is used by
|
||||
[`byte_container_with_subtype`](../../api/byte_container_with_subtype/index.md), the relational operators by
|
||||
[`basic_json`'s comparison operators](../../api/basic_json/operator_le.md).
|
||||
|
||||
@@ -21,10 +21,10 @@ ABI tags are not covered and may show raw internal fields instead. To generate a
|
||||
```
|
||||
|
||||
3. Generate a Natvis file with the tags of your configuration, for example for `JSON_DIAGNOSTICS`,
|
||||
`JSON_DIAGNOSTIC_POSITIONS`, and `JSON_NO_SIMD`:
|
||||
`JSON_DIAGNOSTIC_POSITIONS`, and `JSON_VIEW_NO_SIMD`:
|
||||
|
||||
```shell
|
||||
make natvis NATVIS_ARGS="--abi-tags _diag,_dp,_ns --output my_nlohmann_json.natvis"
|
||||
make natvis NATVIS_ARGS="--abi-tags _diag,_dp,_vns --output my_nlohmann_json.natvis"
|
||||
```
|
||||
|
||||
4. Use the generated file instead of `nlohmann_json.natvis`.
|
||||
|
||||
@@ -330,7 +330,7 @@ where they cannot be resolved.
|
||||
### json.exception.parse_error.110
|
||||
|
||||
When parsing a [binary format](../features/binary_formats/index.md), the byte vector ends before the complete value has
|
||||
been read, or (with `strict = true`) further bytes follow the value.
|
||||
been read.
|
||||
|
||||
!!! failure "Example messages"
|
||||
|
||||
@@ -346,7 +346,7 @@ been read, or (with `strict = true`) further bytes follow the value.
|
||||
|
||||
### json.exception.parse_error.112
|
||||
|
||||
An unexpected byte was read in a [binary format](../features/binary_formats/index.md) or length information is invalid ([BSON](../features/binary_formats/bson.md)). In [BON8](../features/binary_formats/bon8.md), this exception is also thrown for a key that is not a string and for ill-formed UTF-8.
|
||||
An unexpected byte was read in a [binary format](../features/binary_formats/index.md) or length information is invalid ([BSON](../features/binary_formats/bson.md)).
|
||||
|
||||
!!! failure "Example messages"
|
||||
|
||||
@@ -371,21 +371,15 @@ An unexpected byte was read in a [binary format](../features/binary_formats/inde
|
||||
```
|
||||
[json.exception.parse_error.112] parse error at byte 5: syntax error while parsing BSON document: document size 6 does not match the number of bytes read (5)
|
||||
```
|
||||
```
|
||||
[json.exception.parse_error.112] parse error at byte 2: syntax error while parsing BON8 string: invalid UTF-8 byte: 0x80
|
||||
```
|
||||
|
||||
### json.exception.parse_error.113
|
||||
|
||||
A string could not be read from a [binary format](../features/binary_formats/index.md): either a value that is not a
|
||||
string was read where one was required (for instance as a map key), the string's length specification is invalid, or
|
||||
the string's bytes are not valid UTF-8 and the `error_handler` parameter of the corresponding `from_*` function is
|
||||
set to `strict`. By default (`error_handler_t::keep`), the bytes of a string are not checked for valid UTF-8 on read.
|
||||
This applies to the `from_*` functions that have an `error_handler` parameter; `from_bon8` does not have one.
|
||||
See the ill-formed UTF-8 notes on the individual [binary format](../features/binary_formats/index.md) pages for how
|
||||
set to `strict`. By default (`error_handler_t::keep`), the bytes of a string are not checked for valid UTF-8 on read;
|
||||
see the ill-formed UTF-8 notes on the individual [binary format](../features/binary_formats/index.md) pages for how
|
||||
such a string is handled depending on `error_handler`.
|
||||
[`from_bon8()`](../api/basic_json/from_bon8.md) never throws this exception: BON8 non-string keys and ill-formed UTF-8
|
||||
are reported as [parse_error.112](#jsonexceptionparse_error112).
|
||||
|
||||
CBOR and MessagePack allow map keys of any type, but JSON object keys are always strings. Maps with keys of any other
|
||||
type (for instance integers or `null`) are therefore not supported; see the notes on
|
||||
@@ -424,16 +418,13 @@ The parsing of the corresponding BSON record type is not implemented (yet).
|
||||
|
||||
### json.exception.parse_error.115
|
||||
|
||||
A UBJSON or BJData high-precision number could not be parsed.
|
||||
A UBJSON high-precision number could not be parsed.
|
||||
|
||||
!!! failure "Example messages"
|
||||
!!! failure "Example message"
|
||||
|
||||
```
|
||||
[json.exception.parse_error.115] parse error at byte 5: syntax error while parsing UBJSON high-precision number: invalid number text: 1A
|
||||
```
|
||||
```
|
||||
[json.exception.parse_error.115] parse error at byte 5: syntax error while parsing BJData high-precision number: invalid number text: 1A
|
||||
```
|
||||
|
||||
### json.exception.parse_error.116
|
||||
|
||||
@@ -821,9 +812,6 @@ The binary writers [`to_cbor()`](../api/basic_json/to_cbor.md), [`to_ubjson()`](
|
||||
as well for a string value or object key that is not valid UTF-8 if their `error_handler` is `strict` (the default if
|
||||
[`JSON_STRICT_BINARY_UTF8`](../api/macros/json_strict_binary_utf8.md) is enabled). So does
|
||||
[`to_msgpack()`](../api/basic_json/to_msgpack.md) if `error_handler_t::strict` is passed.
|
||||
[`to_bon8()`](../api/basic_json/to_bon8.md) always throws this exception for such a string or key, regardless of
|
||||
[`JSON_STRICT_BINARY_UTF8`](../api/macros/json_strict_binary_utf8.md), because the end of a BON8 string is determined
|
||||
from its UTF-8 encoding.
|
||||
|
||||
!!! failure "Example message"
|
||||
|
||||
@@ -895,12 +883,17 @@ from JSON text.
|
||||
|
||||
[`basic_json_document::save()`](../api/basic_json_document/save.md) cannot write an
|
||||
[image](../features/json_view.md#images) of a [discarded](../api/basic_json_document/is_discarded.md) document.
|
||||
[`save()`](../api/basic_json_document/save.md) and [`load()`](../api/basic_json_document/load.md) also throw this
|
||||
exception on a big-endian target, since the image format is little-endian only.
|
||||
|
||||
!!! failure "Example messages"
|
||||
|
||||
```
|
||||
[json.exception.type_error.320] cannot save a discarded json_document
|
||||
```
|
||||
```
|
||||
[json.exception.type_error.320] json_document images need a little-endian target
|
||||
```
|
||||
|
||||
!!! note
|
||||
|
||||
@@ -1013,8 +1006,7 @@ double-precision number when `number_float_t` is `#!cpp float`.
|
||||
An integer number cannot be represented by the binary format it is serialized to:
|
||||
|
||||
- [BON8](../features/binary_formats/bon8.md) only stores integers that fit into int64, so
|
||||
[`to_bon8`](../api/basic_json/to_bon8.md) throws for unsigned integers greater than 9223372036854775807 and, with a
|
||||
number type wider than 64 bits, for any integer outside the int64 range.
|
||||
[`to_bon8`](../api/basic_json/to_bon8.md) throws for unsigned integers greater than 9223372036854775807.
|
||||
- [CBOR](../features/binary_formats/cbor.md), [MessagePack](../features/binary_formats/messagepack.md), and
|
||||
[BSON](../features/binary_formats/bson.md) store integers in at most 64 bits. With the default number types, every
|
||||
integer fits, but a [`number_integer_t`](../api/basic_json/number_integer_t.md) or
|
||||
@@ -1033,7 +1025,7 @@ exception, because they serialize integers beyond 64 bits as high-precision numb
|
||||
- Since version 3.12.0, integer numbers beyond int64 are serialized as uint64 BSON numbers.
|
||||
|
||||
Before version 3.13.0, CBOR, MessagePack, and BSON silently truncated integers wider than 64 bits, and BJData
|
||||
truncated unsigned integers wider than 64 bits that were elements of ND-arrays with `"_ArrayType_": "uint64"`.
|
||||
truncated unsigned integers wider than 64 bits.
|
||||
|
||||
!!! failure "Example messages"
|
||||
|
||||
@@ -1053,8 +1045,8 @@ or the encoded length for [CBOR](../features/binary_formats/cbor.md).
|
||||
The exception is also thrown for a [UBJSON](../features/binary_formats/ubjson.md) array of a type that is encoded by its
|
||||
marker alone (`Z`, `T` or `F`) whose declared count exceeds 1,048,576 (`1 << 20`). Such an array has no payload, so its
|
||||
count alone decides how much memory is allocated, and a handful of bytes would otherwise describe billions of values.
|
||||
[`to_ubjson`](../api/basic_json/to_ubjson.md) writes longer arrays of these types without the `$` type annotation (the `#`
|
||||
count and one marker per element are kept), so any value it produces can still be read back.
|
||||
[`to_ubjson`](../api/basic_json/to_ubjson.md) writes longer arrays of these types without the size and type annotation,
|
||||
so any value it produces can still be read back.
|
||||
|
||||
!!! failure "Example messages"
|
||||
|
||||
@@ -1168,18 +1160,14 @@ A JSON Patch `move` operation's `"from"` location is a proper prefix of its `"pa
|
||||
### json.exception.out_of_range.415
|
||||
|
||||
MessagePack's ext type and BSON's binary subtype are each stored in a single byte. This exception is thrown when serializing a
|
||||
[`byte_container_with_subtype`](../api/byte_container_with_subtype/index.md) whose subtype exceeds 255, the largest value the library can store in that byte.
|
||||
[`byte_container_with_subtype`](../api/byte_container_with_subtype/index.md) whose subtype exceeds 255.
|
||||
|
||||
!!! failure "Example messages"
|
||||
!!! failure "Example message"
|
||||
|
||||
```
|
||||
[json.exception.out_of_range.415] subtype 70000 is too large for the MessagePack ext type (max 255)
|
||||
```
|
||||
|
||||
```
|
||||
[json.exception.out_of_range.415] subtype 70000 is too large for the BSON binary subtype (max 255)
|
||||
```
|
||||
|
||||
!!! note
|
||||
|
||||
This exception was added in version 3.13.0. Before that, subtypes above 255 were silently truncated modulo 256 instead of raising an error.
|
||||
@@ -1248,9 +1236,7 @@ A JSON Patch operation 'test' failed. The unsuccessful operation is also printed
|
||||
### json.exception.other_error.502
|
||||
|
||||
[`to_ubjson`](../api/basic_json/to_ubjson.md) and [`to_bjdata`](../api/basic_json/to_bjdata.md) were called with
|
||||
`use_type = true` but `use_size = false`, and the value contains a non-empty array or object (or, with BJData Draft 3,
|
||||
any binary value). UBJSON requires a size marker (`#`) after a type marker (`$`); scalars and empty arrays or objects
|
||||
do not throw.
|
||||
`use_type = true` but `use_size = false`. UBJSON requires a size marker (`#`) after a type marker (`$`).
|
||||
|
||||
!!! failure "Example message"
|
||||
|
||||
|
||||
@@ -173,7 +173,6 @@ nav:
|
||||
- 'begin': api/basic_json/begin.md
|
||||
- 'binary': api/basic_json/binary.md
|
||||
- 'binary_t': api/basic_json/binary_t.md
|
||||
- 'bjdata_version_t': api/basic_json/bjdata_version_t.md
|
||||
- 'boolean_t': api/basic_json/boolean_t.md
|
||||
- 'cbegin': api/basic_json/cbegin.md
|
||||
- 'cbor_tag_handler_t': api/basic_json/cbor_tag_handler_t.md
|
||||
@@ -362,7 +361,6 @@ nav:
|
||||
- 'Overview': api/adl_serializer/index.md
|
||||
- 'from_json': api/adl_serializer/from_json.md
|
||||
- 'to_json': api/adl_serializer/to_json.md
|
||||
- 'is_json_view': api/is_json_view.md
|
||||
- 'json': api/json.md
|
||||
- 'json_document': api/json_document.md
|
||||
- 'json_editable_document': api/json_editable_document.md
|
||||
@@ -412,7 +410,6 @@ nav:
|
||||
- 'ordered_json_editable_view': api/ordered_json_editable_view.md
|
||||
- 'ordered_json_view': api/ordered_json_view.md
|
||||
- 'ordered_map': api/ordered_map.md
|
||||
- 'view_mode': api/view_mode.md
|
||||
- macros:
|
||||
- 'Overview': api/macros/index.md
|
||||
- 'JSON_ASSERT': api/macros/json_assert.md
|
||||
@@ -447,6 +444,8 @@ nav:
|
||||
- 'JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON': api/macros/json_use_legacy_discarded_value_comparison.md
|
||||
- 'JSON_USE_OBJECTS_FOR_ENUM_KEYED_MAPS': api/macros/json_use_objects_for_enum_keyed_maps.md
|
||||
- 'JSON_USE_SIMDUTF': api/macros/json_use_simdutf.md
|
||||
- 'JSON_VIEW_NO_SIMD': api/macros/json_view_no_simd.md
|
||||
- 'JSON_VIEW_USE_SSSE3': api/macros/json_view_use_ssse3.md
|
||||
- 'NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE, NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE_WITH_DEFAULT, NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE_ONLY_SERIALIZE, NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE, NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE_WITH_DEFAULT, NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE_ONLY_SERIALIZE': api/macros/nlohmann_define_derived_type.md
|
||||
- 'NLOHMANN_DEFINE_TYPE_INTRUSIVE, NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT, NLOHMANN_DEFINE_TYPE_INTRUSIVE_ONLY_SERIALIZE': api/macros/nlohmann_define_type_intrusive.md
|
||||
- 'NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE, NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT, NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_ONLY_SERIALIZE': api/macros/nlohmann_define_type_non_intrusive.md
|
||||
|
||||
@@ -128,14 +128,26 @@
|
||||
#define NLOHMANN_JSON_ABI_TAG_NO_SIMD
|
||||
#endif
|
||||
|
||||
#ifdef JSON_VIEW_NO_SIMD
|
||||
#define NLOHMANN_JSON_ABI_TAG_VIEW_NO_SIMD _vns
|
||||
#else
|
||||
#define NLOHMANN_JSON_ABI_TAG_VIEW_NO_SIMD
|
||||
#endif
|
||||
|
||||
#ifdef JSON_VIEW_USE_SSSE3
|
||||
#define NLOHMANN_JSON_ABI_TAG_VIEW_USE_SSSE3 _vssse3
|
||||
#else
|
||||
#define NLOHMANN_JSON_ABI_TAG_VIEW_USE_SSSE3
|
||||
#endif
|
||||
|
||||
#ifndef NLOHMANN_JSON_NAMESPACE_NO_VERSION
|
||||
#define NLOHMANN_JSON_NAMESPACE_NO_VERSION 0
|
||||
#endif
|
||||
|
||||
// Construct the namespace ABI tags component
|
||||
#define NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b, c, d, e, f, g, h, i, j, k) json_abi ## a ## b ## c ## d ## e ## f ## g ## h ## i ## j ## k
|
||||
#define NLOHMANN_JSON_ABI_TAGS_CONCAT(a, b, c, d, e, f, g, h, i, j, k) \
|
||||
NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b, c, d, e, f, g, h, i, j, k)
|
||||
#define NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b, c, d, e, f, g, h, i, j, k, l, m) json_abi ## a ## b ## c ## d ## e ## f ## g ## h ## i ## j ## k ## l ## m
|
||||
#define NLOHMANN_JSON_ABI_TAGS_CONCAT(a, b, c, d, e, f, g, h, i, j, k, l, m) \
|
||||
NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b, c, d, e, f, g, h, i, j, k, l, m)
|
||||
|
||||
#define NLOHMANN_JSON_ABI_TAGS \
|
||||
NLOHMANN_JSON_ABI_TAGS_CONCAT( \
|
||||
@@ -149,7 +161,9 @@
|
||||
NLOHMANN_JSON_ABI_TAG_OBJECTS_FOR_ENUM_KEYED_MAPS, \
|
||||
NLOHMANN_JSON_ABI_TAG_DISABLE_STREAM_BULK_SCAN, \
|
||||
NLOHMANN_JSON_ABI_TAG_DISABLE_UNLOCKED_FILE_IO, \
|
||||
NLOHMANN_JSON_ABI_TAG_NO_SIMD)
|
||||
NLOHMANN_JSON_ABI_TAG_NO_SIMD, \
|
||||
NLOHMANN_JSON_ABI_TAG_VIEW_NO_SIMD, \
|
||||
NLOHMANN_JSON_ABI_TAG_VIEW_USE_SSSE3)
|
||||
|
||||
// Construct the namespace version component
|
||||
#define NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT_EX(major, minor, patch) \
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
|
||||
#include <algorithm> // min, transform
|
||||
#include <array> // array
|
||||
#include <cstddef> // nullptr_t
|
||||
#include <forward_list> // forward_list
|
||||
#include <iterator> // inserter, front_inserter, end
|
||||
#include <map> // map
|
||||
@@ -28,7 +27,6 @@
|
||||
#include <nlohmann/detail/meta/identity_tag.hpp>
|
||||
#include <nlohmann/detail/meta/std_fs.hpp>
|
||||
#include <nlohmann/detail/meta/type_traits.hpp>
|
||||
#include <nlohmann/detail/output/error_handler.hpp>
|
||||
#include <nlohmann/detail/string_concat.hpp>
|
||||
#include <nlohmann/detail/value_t.hpp>
|
||||
|
||||
@@ -45,70 +43,6 @@ NLOHMANN_JSON_NAMESPACE_BEGIN
|
||||
namespace detail
|
||||
{
|
||||
|
||||
// The from_json() overloads below read basic_json values and the views of
|
||||
// <nlohmann/json_view.hpp> (BasicJsonType is then a view, and
|
||||
// json_type_of_t<BasicJsonType> its basic_json type). The helpers below are
|
||||
// the accesses that differ between the two.
|
||||
|
||||
// the enable_if parameter of the overloads that read basic_json values (written
|
||||
// with negation<> because astyle spaces out a template argument list with '!')
|
||||
template<typename T>
|
||||
using enable_if_not_view_t = enable_if_t<negation<is_json_view<T>>::value, int>;
|
||||
|
||||
// the boolean of j, a boolean
|
||||
template<typename BasicJsonType, enable_if_not_view_t<BasicJsonType> = 0>
|
||||
typename BasicJsonType::boolean_t boolean_value(const BasicJsonType& j)
|
||||
{
|
||||
return *j.template get_ptr<const typename BasicJsonType::boolean_t*>();
|
||||
}
|
||||
|
||||
template<typename View, enable_if_t<is_json_view<View>::value, int> = 0>
|
||||
bool boolean_value(const View& v)
|
||||
{
|
||||
return v.template get<bool>();
|
||||
}
|
||||
|
||||
// the string of j, a string
|
||||
template<typename BasicJsonType, enable_if_not_view_t<BasicJsonType> = 0>
|
||||
const typename BasicJsonType::string_t& string_value(const BasicJsonType& j)
|
||||
{
|
||||
return *j.template get_ptr<const typename BasicJsonType::string_t*>();
|
||||
}
|
||||
|
||||
template<typename View, enable_if_t<is_json_view<View>::value, int> = 0>
|
||||
typename View::string_t string_value(const View& v)
|
||||
{
|
||||
const auto s = v.get_string();
|
||||
return typename View::string_t(s.data(), s.size());
|
||||
}
|
||||
|
||||
// the binary value of j, a binary value (never a view: a view of a JSON text
|
||||
// holds no binary values)
|
||||
template<typename BasicJsonType, enable_if_not_view_t<BasicJsonType> = 0>
|
||||
const typename BasicJsonType::binary_t& binary_value(const BasicJsonType& j)
|
||||
{
|
||||
return *j.template get_ptr<const typename BasicJsonType::binary_t*>();
|
||||
}
|
||||
|
||||
template<typename View, enable_if_t<is_json_view<View>::value, int> = 0>
|
||||
typename View::basic_json_type::binary_t binary_value(const View& /*unused*/)
|
||||
{
|
||||
return {}; // LCOV_EXCL_LINE
|
||||
}
|
||||
|
||||
// the elements of j, an array, for a range-based for loop
|
||||
template<typename BasicJsonType, enable_if_not_view_t<BasicJsonType> = 0>
|
||||
const typename BasicJsonType::array_t& array_elements(const BasicJsonType& j)
|
||||
{
|
||||
return *j.template get_ptr<const typename BasicJsonType::array_t*>();
|
||||
}
|
||||
|
||||
template<typename View, enable_if_t<is_json_view<View>::value, int> = 0>
|
||||
View array_elements(const View& v) noexcept
|
||||
{
|
||||
return v; // (a view is two pointers)
|
||||
}
|
||||
|
||||
template<typename BasicJsonType>
|
||||
inline void from_json(const BasicJsonType& j, typename std::nullptr_t& n)
|
||||
{
|
||||
@@ -137,7 +71,7 @@ void from_json(const BasicJsonType& j, std::optional<T>& opt)
|
||||
|
||||
// read a number value of any of the three number types into val;
|
||||
// returns false (leaving val untouched) if j is not a number
|
||||
template<typename BasicJsonType, typename ArithmeticType, enable_if_not_view_t<BasicJsonType> = 0>
|
||||
template<typename BasicJsonType, typename ArithmeticType>
|
||||
bool get_number_value(const BasicJsonType& j, ArithmeticType& val)
|
||||
{
|
||||
switch (static_cast<value_t>(j))
|
||||
@@ -174,22 +108,10 @@ bool get_number_value(const BasicJsonType& j, ArithmeticType& val)
|
||||
}
|
||||
}
|
||||
|
||||
// a view converts numbers itself (as basic_json does)
|
||||
template<typename View, typename ArithmeticType, enable_if_t<is_json_view<View>::value, int> = 0>
|
||||
bool get_number_value(const View& v, ArithmeticType& val)
|
||||
{
|
||||
if (!v.is_number())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
val = v.template get<ArithmeticType>();
|
||||
return true;
|
||||
}
|
||||
|
||||
// overloads for basic_json template parameters
|
||||
template < typename BasicJsonType, typename ArithmeticType,
|
||||
enable_if_t < std::is_arithmetic<ArithmeticType>::value&&
|
||||
!std::is_same<ArithmeticType, typename json_type_of_t<BasicJsonType>::boolean_t>::value,
|
||||
!std::is_same<ArithmeticType, typename BasicJsonType::boolean_t>::value,
|
||||
int > = 0 >
|
||||
void get_arithmetic_value(const BasicJsonType& j, ArithmeticType& val)
|
||||
{
|
||||
@@ -200,31 +122,31 @@ void get_arithmetic_value(const BasicJsonType& j, ArithmeticType& val)
|
||||
}
|
||||
|
||||
template<typename BasicJsonType>
|
||||
inline void from_json(const BasicJsonType& j, typename json_type_of_t<BasicJsonType>::boolean_t& b)
|
||||
inline void from_json(const BasicJsonType& j, typename BasicJsonType::boolean_t& b)
|
||||
{
|
||||
if (JSON_HEDLEY_UNLIKELY(!j.is_boolean()))
|
||||
{
|
||||
throw_type_must_be("boolean", j);
|
||||
}
|
||||
b = boolean_value(j);
|
||||
b = *j.template get_ptr<const typename BasicJsonType::boolean_t*>();
|
||||
}
|
||||
|
||||
template<typename BasicJsonType>
|
||||
inline void from_json(const BasicJsonType& j, typename json_type_of_t<BasicJsonType>::string_t& s)
|
||||
inline void from_json(const BasicJsonType& j, typename BasicJsonType::string_t& s)
|
||||
{
|
||||
if (JSON_HEDLEY_UNLIKELY(!j.is_string()))
|
||||
{
|
||||
throw_type_must_be("string", j);
|
||||
}
|
||||
s = string_value(j);
|
||||
s = *j.template get_ptr<const typename BasicJsonType::string_t*>();
|
||||
}
|
||||
|
||||
template <
|
||||
typename BasicJsonType, typename StringType,
|
||||
enable_if_t <
|
||||
std::is_assignable<StringType&, const typename json_type_of_t<BasicJsonType>::string_t>::value
|
||||
&& is_detected_exact<typename json_type_of_t<BasicJsonType>::string_t::value_type, value_type_t, StringType>::value
|
||||
&& !std::is_same<typename json_type_of_t<BasicJsonType>::string_t, StringType>::value
|
||||
std::is_assignable<StringType&, const typename BasicJsonType::string_t>::value
|
||||
&& is_detected_exact<typename BasicJsonType::string_t::value_type, value_type_t, StringType>::value
|
||||
&& !std::is_same<typename BasicJsonType::string_t, StringType>::value
|
||||
&& !is_json_ref<StringType>::value, int > = 0 >
|
||||
inline void from_json(const BasicJsonType& j, StringType& s)
|
||||
{
|
||||
@@ -233,23 +155,23 @@ inline void from_json(const BasicJsonType& j, StringType& s)
|
||||
throw_type_must_be("string", j);
|
||||
}
|
||||
|
||||
s = string_value(j);
|
||||
s = *j.template get_ptr<const typename BasicJsonType::string_t*>();
|
||||
}
|
||||
|
||||
template<typename BasicJsonType>
|
||||
inline void from_json(const BasicJsonType& j, typename json_type_of_t<BasicJsonType>::number_float_t& val)
|
||||
inline void from_json(const BasicJsonType& j, typename BasicJsonType::number_float_t& val)
|
||||
{
|
||||
get_arithmetic_value(j, val);
|
||||
}
|
||||
|
||||
template<typename BasicJsonType>
|
||||
inline void from_json(const BasicJsonType& j, number_unsigned_overload_t<json_type_of_t<BasicJsonType>>& val)
|
||||
inline void from_json(const BasicJsonType& j, number_unsigned_overload_t<BasicJsonType>& val)
|
||||
{
|
||||
get_arithmetic_value(j, val);
|
||||
}
|
||||
|
||||
template<typename BasicJsonType>
|
||||
inline void from_json(const BasicJsonType& j, typename json_type_of_t<BasicJsonType>::number_integer_t& val)
|
||||
inline void from_json(const BasicJsonType& j, typename BasicJsonType::number_integer_t& val)
|
||||
{
|
||||
get_arithmetic_value(j, val);
|
||||
}
|
||||
@@ -261,8 +183,8 @@ inline void from_json(const BasicJsonType& j, EnumType& e)
|
||||
{
|
||||
using underlying_type = typename std::underlying_type<EnumType>::type;
|
||||
// get_arithmetic_value() does not accept boolean_t; read the number that to_json() wrote instead
|
||||
using value_type = typename std::conditional<std::is_same<underlying_type, typename json_type_of_t<BasicJsonType>::boolean_t>::value,
|
||||
typename json_type_of_t<BasicJsonType>::number_unsigned_t, underlying_type>::type;
|
||||
using value_type = typename std::conditional<std::is_same<underlying_type, typename BasicJsonType::boolean_t>::value,
|
||||
typename BasicJsonType::number_unsigned_t, underlying_type>::type;
|
||||
value_type val;
|
||||
get_arithmetic_value(j, val);
|
||||
e = static_cast<EnumType>(bool_aware_static_cast<underlying_type>(val));
|
||||
@@ -271,7 +193,7 @@ inline void from_json(const BasicJsonType& j, EnumType& e)
|
||||
|
||||
// forward_list doesn't have an insert method
|
||||
template<typename BasicJsonType, typename T, typename Allocator,
|
||||
enable_if_t<is_getable<json_type_of_t<BasicJsonType>, T>::value, int> = 0>
|
||||
enable_if_t<is_getable<BasicJsonType, T>::value, int> = 0>
|
||||
inline void from_json(const BasicJsonType& j, std::forward_list<T, Allocator>& l)
|
||||
{
|
||||
if (JSON_HEDLEY_UNLIKELY(!j.is_array()))
|
||||
@@ -279,16 +201,16 @@ inline void from_json(const BasicJsonType& j, std::forward_list<T, Allocator>& l
|
||||
throw_type_must_be("array", j);
|
||||
}
|
||||
l.clear();
|
||||
auto pos = l.before_begin();
|
||||
for (const auto& elem : array_elements(j))
|
||||
std::transform(j.rbegin(), j.rend(),
|
||||
std::front_inserter(l), [](const BasicJsonType & i)
|
||||
{
|
||||
pos = l.insert_after(pos, elem.template get<T>());
|
||||
}
|
||||
return i.template get<T>();
|
||||
});
|
||||
}
|
||||
|
||||
// valarray doesn't have an insert method
|
||||
template<typename BasicJsonType, typename T,
|
||||
enable_if_t<is_getable<json_type_of_t<BasicJsonType>, T>::value, int> = 0>
|
||||
enable_if_t<is_getable<BasicJsonType, T>::value, int> = 0>
|
||||
inline void from_json(const BasicJsonType& j, std::valarray<T>& l)
|
||||
{
|
||||
if (JSON_HEDLEY_UNLIKELY(!j.is_array()))
|
||||
@@ -296,11 +218,11 @@ inline void from_json(const BasicJsonType& j, std::valarray<T>& l)
|
||||
throw_type_must_be("array", j);
|
||||
}
|
||||
l.resize(j.size());
|
||||
std::size_t i = 0;
|
||||
for (const auto& elem : array_elements(j))
|
||||
std::transform(j.begin(), j.end(), std::begin(l),
|
||||
[](const BasicJsonType & elem)
|
||||
{
|
||||
l[i++] = elem.template get<T>();
|
||||
}
|
||||
return elem.template get<T>();
|
||||
});
|
||||
}
|
||||
|
||||
// element is not itself a C array: read it directly
|
||||
@@ -328,8 +250,7 @@ auto from_json(const BasicJsonType& j, T (&arr)[N]) // NOLINT(cppcoreguidelines
|
||||
from_json_c_array_element(j, arr);
|
||||
}
|
||||
|
||||
// (for a view, array_t is read element by element below)
|
||||
template<typename BasicJsonType, enable_if_not_view_t<BasicJsonType> = 0>
|
||||
template<typename BasicJsonType>
|
||||
inline void from_json_array_impl(const BasicJsonType& j, typename BasicJsonType::array_t& arr, priority_tag<3> /*unused*/)
|
||||
{
|
||||
arr = *j.template get_ptr<const typename BasicJsonType::array_t*>();
|
||||
@@ -338,7 +259,7 @@ inline void from_json_array_impl(const BasicJsonType& j, typename BasicJsonType:
|
||||
// fill a std::array from the JSON array j: the size is checked once and the
|
||||
// elements are read in order, so a short array converts the elements it has and
|
||||
// then throws the out_of_range error at() would throw for the first missing one
|
||||
template<typename BasicJsonType, typename T, std::size_t N, enable_if_not_view_t<BasicJsonType> = 0>
|
||||
template<typename BasicJsonType, typename T, std::size_t N>
|
||||
void from_json_std_array(const BasicJsonType& j, std::array<T, N>& arr)
|
||||
{
|
||||
const auto& inner_array = *j.template get_ptr<const typename BasicJsonType::array_t*>();
|
||||
@@ -353,21 +274,6 @@ void from_json_std_array(const BasicJsonType& j, std::array<T, N>& arr)
|
||||
}
|
||||
}
|
||||
|
||||
// (a view has no random access to the elements: they are read in order)
|
||||
template<typename View, typename T, std::size_t N, enable_if_t<is_json_view<View>::value, int> = 0>
|
||||
void from_json_std_array(const View& v, std::array<T, N>& arr)
|
||||
{
|
||||
std::size_t size = 0;
|
||||
for (auto it = v.begin(); size < N && it != v.end(); ++it)
|
||||
{
|
||||
arr[size++] = (*it).template get<T>();
|
||||
}
|
||||
if (JSON_HEDLEY_UNLIKELY(size < N))
|
||||
{
|
||||
static_cast<void>(v.at(size));
|
||||
}
|
||||
}
|
||||
|
||||
template<typename BasicJsonType, typename T, std::size_t N>
|
||||
auto from_json_array_impl(const BasicJsonType& j, std::array<T, N>& arr,
|
||||
priority_tag<2> /*unused*/)
|
||||
@@ -416,8 +322,9 @@ auto from_json_array_impl(const BasicJsonType& j, ConstructibleArrayType& arr, p
|
||||
void())
|
||||
{
|
||||
ConstructibleArrayType ret;
|
||||
reserve_if_possible(ret, j.size(), priority_tag<1> {});
|
||||
for (const auto& elem : array_elements(j))
|
||||
const auto* inner_array = j.template get_ptr<const typename BasicJsonType::array_t*>();
|
||||
reserve_if_possible(ret, inner_array->size(), priority_tag<1> {});
|
||||
for (const auto& elem : *inner_array)
|
||||
{
|
||||
// get<BasicJsonType>() returns *this, this won't call a from_json
|
||||
// method when value_type is BasicJsonType
|
||||
@@ -428,11 +335,11 @@ auto from_json_array_impl(const BasicJsonType& j, ConstructibleArrayType& arr, p
|
||||
|
||||
template < typename BasicJsonType, typename ConstructibleArrayType,
|
||||
enable_if_t <
|
||||
is_constructible_array_type<json_type_of_t<BasicJsonType>, ConstructibleArrayType>::value&&
|
||||
!is_constructible_object_type<json_type_of_t<BasicJsonType>, ConstructibleArrayType>::value&&
|
||||
!is_constructible_string_type<json_type_of_t<BasicJsonType>, ConstructibleArrayType>::value&&
|
||||
!std::is_same<ConstructibleArrayType, typename json_type_of_t<BasicJsonType>::binary_t>::value&&
|
||||
!is_compatible_binary_type<json_type_of_t<BasicJsonType>, ConstructibleArrayType>::value&&
|
||||
is_constructible_array_type<BasicJsonType, ConstructibleArrayType>::value&&
|
||||
!is_constructible_object_type<BasicJsonType, ConstructibleArrayType>::value&&
|
||||
!is_constructible_string_type<BasicJsonType, ConstructibleArrayType>::value&&
|
||||
!std::is_same<ConstructibleArrayType, typename BasicJsonType::binary_t>::value&&
|
||||
!is_compatible_binary_type<BasicJsonType, ConstructibleArrayType>::value&&
|
||||
!is_basic_json<ConstructibleArrayType>::value,
|
||||
int > = 0 >
|
||||
auto from_json(const BasicJsonType& j, ConstructibleArrayType& arr)
|
||||
@@ -499,24 +406,24 @@ auto from_json(const BasicJsonType& j, identity_tag<std::array<T, N>> tag)
|
||||
}
|
||||
|
||||
template<typename BasicJsonType>
|
||||
inline void from_json(const BasicJsonType& j, typename json_type_of_t<BasicJsonType>::binary_t& bin)
|
||||
inline void from_json(const BasicJsonType& j, typename BasicJsonType::binary_t& bin)
|
||||
{
|
||||
if (JSON_HEDLEY_UNLIKELY(!j.is_binary()))
|
||||
{
|
||||
throw_type_must_be("binary", j);
|
||||
}
|
||||
|
||||
bin = binary_value(j);
|
||||
bin = *j.template get_ptr<const typename BasicJsonType::binary_t*>();
|
||||
}
|
||||
|
||||
template < typename BasicJsonType, typename CompatibleArrayType,
|
||||
enable_if_t < is_compatible_binary_type<json_type_of_t<BasicJsonType>, CompatibleArrayType>::value,
|
||||
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>(binary_value(j));
|
||||
bin = static_cast<CompatibleArrayType>(*j.template get_ptr<const typename BasicJsonType::binary_t*>());
|
||||
}
|
||||
else if (j.is_array())
|
||||
{
|
||||
@@ -545,47 +452,8 @@ void from_json_object_emplace(ConstructibleObjectType& obj, Key&& key, Value&& v
|
||||
obj.emplace(std::forward<Key>(key), std::forward<Value>(value));
|
||||
}
|
||||
|
||||
// a member of a view's object: a later member with the same key replaces an
|
||||
// earlier one, as parse() keeps the last value of a repeated key (containers
|
||||
// without operator[] keep the first)
|
||||
template<typename ConstructibleObjectType, typename Key, typename Value>
|
||||
auto from_json_object_assign(ConstructibleObjectType& obj, Key&& key, Value&& value, priority_tag<1> /*unused*/)
|
||||
-> decltype(obj[std::forward<Key>(key)] = std::forward<Value>(value), void())
|
||||
{
|
||||
obj[std::forward<Key>(key)] = std::forward<Value>(value);
|
||||
}
|
||||
|
||||
template<typename ConstructibleObjectType, typename Key, typename Value>
|
||||
void from_json_object_assign(ConstructibleObjectType& obj, Key&& key, Value&& value, priority_tag<0> /*unused*/)
|
||||
{
|
||||
obj.emplace(std::forward<Key>(key), std::forward<Value>(value));
|
||||
}
|
||||
|
||||
template<typename BasicJsonType, typename ConstructibleObjectType, enable_if_not_view_t<BasicJsonType> = 0>
|
||||
void from_json_object_impl(const BasicJsonType& j, ConstructibleObjectType& ret)
|
||||
{
|
||||
const auto* inner_object = j.template get_ptr<const typename BasicJsonType::object_t*>();
|
||||
reserve_if_possible(ret, inner_object->size(), priority_tag<1> {});
|
||||
for (const auto& p : *inner_object)
|
||||
{
|
||||
from_json_object_emplace(ret, p.first, p.second.template get<typename ConstructibleObjectType::mapped_type>(), priority_tag<1> {});
|
||||
}
|
||||
}
|
||||
|
||||
template<typename View, typename ConstructibleObjectType, enable_if_t<is_json_view<View>::value, int> = 0>
|
||||
void from_json_object_impl(const View& v, ConstructibleObjectType& ret)
|
||||
{
|
||||
using string_t = typename View::basic_json_type::object_t::key_type;
|
||||
reserve_if_possible(ret, v.size(), priority_tag<1> {});
|
||||
for (const auto item : v.items())
|
||||
{
|
||||
const auto key = item.key();
|
||||
from_json_object_assign(ret, string_t(key.data(), key.size()), item.value().template get<typename ConstructibleObjectType::mapped_type>(), priority_tag<1> {});
|
||||
}
|
||||
}
|
||||
|
||||
template<typename BasicJsonType, typename ConstructibleObjectType,
|
||||
enable_if_t<is_constructible_object_type<json_type_of_t<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)
|
||||
{
|
||||
if (JSON_HEDLEY_UNLIKELY(!j.is_object()))
|
||||
@@ -594,7 +462,12 @@ inline void from_json(const BasicJsonType& j, ConstructibleObjectType& obj)
|
||||
}
|
||||
|
||||
ConstructibleObjectType ret;
|
||||
from_json_object_impl(j, ret);
|
||||
const auto* inner_object = j.template get_ptr<const typename BasicJsonType::object_t*>();
|
||||
reserve_if_possible(ret, inner_object->size(), priority_tag<1> {});
|
||||
for (const auto& p : *inner_object)
|
||||
{
|
||||
from_json_object_emplace(ret, p.first, p.second.template get<typename ConstructibleObjectType::mapped_type>(), priority_tag<1> {});
|
||||
}
|
||||
obj = std::move(ret);
|
||||
}
|
||||
|
||||
@@ -603,10 +476,10 @@ inline void from_json(const BasicJsonType& j, ConstructibleObjectType& obj)
|
||||
template < typename BasicJsonType, typename ArithmeticType,
|
||||
enable_if_t <
|
||||
std::is_arithmetic<ArithmeticType>::value&&
|
||||
!std::is_same<ArithmeticType, typename json_type_of_t<BasicJsonType>::number_unsigned_t>::value&&
|
||||
!std::is_same<ArithmeticType, typename json_type_of_t<BasicJsonType>::number_integer_t>::value&&
|
||||
!std::is_same<ArithmeticType, typename json_type_of_t<BasicJsonType>::number_float_t>::value&&
|
||||
!std::is_same<ArithmeticType, typename json_type_of_t<BasicJsonType>::boolean_t>::value,
|
||||
!std::is_same<ArithmeticType, typename BasicJsonType::number_unsigned_t>::value&&
|
||||
!std::is_same<ArithmeticType, typename BasicJsonType::number_integer_t>::value&&
|
||||
!std::is_same<ArithmeticType, typename BasicJsonType::number_float_t>::value&&
|
||||
!std::is_same<ArithmeticType, typename BasicJsonType::boolean_t>::value,
|
||||
int > = 0 >
|
||||
inline void from_json(const BasicJsonType& j, ArithmeticType& val)
|
||||
{
|
||||
@@ -620,7 +493,7 @@ inline void from_json(const BasicJsonType& j, ArithmeticType& val)
|
||||
{
|
||||
throw_type_must_be("number", j);
|
||||
}
|
||||
val = static_cast<ArithmeticType>(boolean_value(j));
|
||||
val = static_cast<ArithmeticType>(*j.template get_ptr<const typename BasicJsonType::boolean_t*>());
|
||||
}
|
||||
|
||||
template<typename BasicJsonType, typename Type>
|
||||
@@ -630,7 +503,7 @@ detail::uncvref_t<Type> from_json_tuple_get_impl(BasicJsonType&& j, detail::iden
|
||||
}
|
||||
|
||||
template<typename BasicJsonType, typename Type,
|
||||
detail::enable_if_t<conjunction<is_basic_json<uncvref_t<BasicJsonType>>, is_compatible_reference_type<BasicJsonType, Type>>::value, int> = 0>
|
||||
detail::enable_if_t<detail::is_compatible_reference_type<BasicJsonType, Type>::value, int> = 0>
|
||||
Type from_json_tuple_get_impl(BasicJsonType && j, detail::identity_tag<Type> /*unused*/, detail::priority_tag<1> /*unused*/)
|
||||
{
|
||||
return std::forward<BasicJsonType>(j).template get_ref<Type>();
|
||||
@@ -674,7 +547,7 @@ inline void from_json_tuple_impl(const BasicJsonType& j, std::pair<A1, A2>& p, p
|
||||
template<typename BasicJsonType, typename... Args>
|
||||
std::tuple<Args...> from_json_tuple_impl(const BasicJsonType& j, identity_tag<std::tuple<Args...>> /*unused*/, priority_tag<2> /*unused*/)
|
||||
{
|
||||
static_assert(conjunction<disjunction<negation<std::is_reference<Args>>, conjunction<is_basic_json<BasicJsonType>, is_compatible_reference_type<const BasicJsonType&, Args>>>...>::value,
|
||||
static_assert(conjunction<disjunction<negation<std::is_reference<Args>>, is_compatible_reference_type<const BasicJsonType&, Args>>...>::value,
|
||||
"Can not return a tuple containing references to types not contained in a Json, try Json::get_to()");
|
||||
return from_json_tuple_impl_base<1, Args...>(j, index_sequence_for<Args...> {});
|
||||
}
|
||||
@@ -720,7 +593,7 @@ void from_json_pair_array_to_map(const BasicJsonType& j, MapType& m)
|
||||
// read a map with enum keys from an object, using the enum's own from_json for
|
||||
// the keys (e.g., from NLOHMANN_JSON_SERIALIZE_ENUM); this is the form written
|
||||
// with JSON_USE_OBJECTS_FOR_ENUM_KEYED_MAPS
|
||||
template<typename BasicJsonType, typename Map, enable_if_not_view_t<BasicJsonType> = 0>
|
||||
template<typename BasicJsonType, typename Map>
|
||||
inline bool from_json_enum_keyed_object(const BasicJsonType& j, Map& m, std::true_type /*key is enum*/)
|
||||
{
|
||||
if (!j.is_object())
|
||||
@@ -735,24 +608,6 @@ inline bool from_json_enum_keyed_object(const BasicJsonType& j, Map& m, std::tru
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename View, typename Map, enable_if_t<is_json_view<View>::value, int> = 0>
|
||||
inline bool from_json_enum_keyed_object(const View& v, Map& m, std::true_type /*key is enum*/)
|
||||
{
|
||||
using json_t = typename View::basic_json_type;
|
||||
if (!v.is_object())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
m.clear();
|
||||
for (const auto item : v.items())
|
||||
{
|
||||
const auto key = item.key();
|
||||
from_json_object_assign(m, json_t(typename json_t::string_t(key.data(), key.size())).template get<typename Map::key_type>(),
|
||||
item.value().template get<typename Map::mapped_type>(), priority_tag<1> {});
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename BasicJsonType, typename Map>
|
||||
inline bool from_json_enum_keyed_object(const BasicJsonType& /*j*/, Map& /*m*/, std::false_type /*key is enum*/)
|
||||
{
|
||||
@@ -761,7 +616,7 @@ inline bool from_json_enum_keyed_object(const BasicJsonType& /*j*/, Map& /*m*/,
|
||||
|
||||
template < typename BasicJsonType, typename Key, typename Value, typename Compare, typename Allocator,
|
||||
typename = enable_if_t < !std::is_constructible <
|
||||
typename json_type_of_t<BasicJsonType>::string_t, Key >::value >>
|
||||
typename BasicJsonType::string_t, Key >::value >>
|
||||
void from_json(const BasicJsonType& j, std::map<Key, Value, Compare, Allocator>& m)
|
||||
{
|
||||
// NOLINTNEXTLINE(modernize-type-traits) we use C++11
|
||||
@@ -774,7 +629,7 @@ void from_json(const BasicJsonType& j, std::map<Key, Value, Compare, Allocator>&
|
||||
|
||||
template < typename BasicJsonType, typename Key, typename Value, typename Hash, typename KeyEqual, typename Allocator,
|
||||
typename = enable_if_t < !std::is_constructible <
|
||||
typename json_type_of_t<BasicJsonType>::string_t, Key >::value >>
|
||||
typename BasicJsonType::string_t, Key >::value >>
|
||||
void from_json(const BasicJsonType& j, std::unordered_map<Key, Value, Hash, KeyEqual, Allocator>& m)
|
||||
{
|
||||
// NOLINTNEXTLINE(modernize-type-traits) we use C++11
|
||||
@@ -798,7 +653,7 @@ inline void from_json(const BasicJsonType& j, std_fs::path& p)
|
||||
{
|
||||
throw_type_must_be("string", j);
|
||||
}
|
||||
const auto& s = string_value(j);
|
||||
const auto& s = *j.template get_ptr<const typename BasicJsonType::string_t*>();
|
||||
// Checking for C++20 standard or later can be insufficient in case the
|
||||
// library support for char8_t is either incomplete or was disabled
|
||||
// altogether. Use the __cpp_lib_char8_t feature test instead.
|
||||
@@ -810,100 +665,17 @@ inline void from_json(const BasicJsonType& j, std_fs::path& p)
|
||||
}
|
||||
#endif
|
||||
|
||||
namespace from_json_adl
|
||||
{
|
||||
// hides the library's from_json() overloads above (and the from_json object):
|
||||
// a call from this namespace finds only the from_json() functions of the
|
||||
// arguments' own namespaces and classes (ADL); the declaration is never viable
|
||||
// and never defined (not "= delete", which GCC before 6 reports as a use)
|
||||
struct hidden;
|
||||
void from_json(const hidden&);
|
||||
|
||||
// a type no from_json() written for JSON values accepts: a from_json() that
|
||||
// accepts it is not constrained to them (see has_view_from_json; it lives
|
||||
// here, so that ADL finds no other from_json() for it)
|
||||
struct probe
|
||||
{};
|
||||
|
||||
struct fn
|
||||
{
|
||||
template<typename SourceType, typename T>
|
||||
auto operator()(const SourceType& j, T&& val) const
|
||||
noexcept(noexcept(from_json(j, std::forward<T>(val))))
|
||||
-> decltype(from_json(j, std::forward<T>(val)))
|
||||
{
|
||||
return from_json(j, std::forward<T>(val));
|
||||
}
|
||||
};
|
||||
} // namespace from_json_adl
|
||||
|
||||
// the sources whose from_json() is only looked up by ADL: the probe
|
||||
template<typename T>
|
||||
struct is_adl_only_from_json_source : std::is_same<T, from_json_adl::probe> {};
|
||||
|
||||
struct from_json_fn
|
||||
{
|
||||
template<typename BasicJsonType, typename T,
|
||||
enable_if_t<negation<is_adl_only_from_json_source<BasicJsonType>>::value, int> = 0>
|
||||
auto operator()(const BasicJsonType& j, T && val) const
|
||||
template<typename BasicJsonType, typename T>
|
||||
auto operator()(const BasicJsonType& j, T&& val) const
|
||||
noexcept(noexcept(from_json(j, std::forward<T>(val))))
|
||||
-> decltype(from_json(j, std::forward<T>(val)))
|
||||
{
|
||||
return from_json(j, std::forward<T>(val));
|
||||
}
|
||||
|
||||
template<typename SourceType, typename T,
|
||||
enable_if_t<is_adl_only_from_json_source<SourceType>::value, int> = 0>
|
||||
auto operator()(const SourceType& j, T && val) const
|
||||
noexcept(noexcept(from_json_adl::fn {}(j, std::forward<T>(val))))
|
||||
-> decltype(from_json_adl::fn {}(j, std::forward<T>(val)))
|
||||
{
|
||||
return from_json_adl::fn {}(j, std::forward<T>(val));
|
||||
}
|
||||
};
|
||||
|
||||
// Whether JSONSerializer::from_json(view, T&) reads T from a view (of
|
||||
// <nlohmann/json_view.hpp>) directly: it must accept the view but not the
|
||||
// probe. An unconstrained from_json() template (written for basic_json, but
|
||||
// accepting anything) is thus not called with a view, nor are the library's
|
||||
// own conversions; the view converts such types through materialize().
|
||||
template<typename Serializer, typename SourceType, typename T>
|
||||
using serializer_from_json_t = decltype(Serializer::from_json(std::declval<const SourceType&>(), std::declval<T&>()));
|
||||
|
||||
template<typename Serializer, typename View, typename T>
|
||||
struct has_view_from_json
|
||||
: conjunction < is_detected<serializer_from_json_t, Serializer, View, T>,
|
||||
negation<is_detected<serializer_from_json_t, Serializer, from_json_adl::probe, T>>> {};
|
||||
|
||||
// the base part of a type of the NLOHMANN_DEFINE_DERIVED_TYPE_* macros: from a
|
||||
// view through its get_to(), which reads the base from the view where the
|
||||
// base's from_json() accepts views, and from materialize() otherwise
|
||||
template<typename BasicJsonType, typename T, enable_if_t<is_basic_json<BasicJsonType>::value, int> = 0>
|
||||
void from_json_base(const BasicJsonType& j, T& base)
|
||||
{
|
||||
from_json_fn {}(j, base);
|
||||
}
|
||||
|
||||
template<typename View, typename T, enable_if_t<is_json_view<View>::value, int> = 0>
|
||||
void from_json_base(const View& v, T& base)
|
||||
{
|
||||
v.get_to(base);
|
||||
}
|
||||
|
||||
// a value as an exception message shows it (invalid UTF-8 replaced; the
|
||||
// strings of a view are always valid UTF-8)
|
||||
template<typename BasicJsonType, enable_if_t<is_basic_json<BasicJsonType>::value, int> = 0>
|
||||
typename BasicJsonType::string_t from_json_dump(const BasicJsonType& j)
|
||||
{
|
||||
return j.dump(-1, ' ', false, error_handler_t::replace);
|
||||
}
|
||||
|
||||
template<typename View, enable_if_t<is_json_view<View>::value, int> = 0>
|
||||
typename View::string_t from_json_dump(const View& v)
|
||||
{
|
||||
return v.dump();
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
#ifndef JSON_HAS_CPP_17
|
||||
|
||||
@@ -102,7 +102,7 @@ enum class exception_id : int
|
||||
type_not_serializable = 317, ///< a value cannot be serialized to the requested binary format
|
||||
enum_key_duplicate = 318, ///< an enum-keyed map has two keys that serialize to the same string
|
||||
document_binary_value = 319, ///< a binary value is stored in a json_document
|
||||
document_image_unsupported = 320, ///< a discarded json_document cannot be saved as an image
|
||||
document_image_unsupported = 320, ///< a json_document image cannot be saved or loaded (discarded document, big-endian target)
|
||||
discarded_value_used = 321, ///< a discarded value is used
|
||||
// out_of_range
|
||||
array_index_out_of_range = 401, ///< an array index is out of range
|
||||
@@ -417,20 +417,6 @@ void templated_json_throw(ExceptionType exception)
|
||||
(void)exception;
|
||||
}
|
||||
|
||||
// the context of an exception about j: j itself for a basic_json value (whose
|
||||
// path JSON_DIAGNOSTICS shows), none for a view of <nlohmann/json_view.hpp>
|
||||
template<typename BasicJsonType, enable_if_t<is_basic_json<BasicJsonType>::value, int> = 0>
|
||||
const BasicJsonType * exception_context(const BasicJsonType& j) noexcept
|
||||
{
|
||||
return &j;
|
||||
}
|
||||
|
||||
template<typename View, enable_if_t<is_json_view<View>::value, int> = 0>
|
||||
std::nullptr_t exception_context(const View& /*unused*/) noexcept
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief throws because @a j does not have the type a conversion expects
|
||||
@param[in] expected the expected type(s), e.g. "array" or "binary or array"
|
||||
@@ -442,7 +428,7 @@ JSON_HEDLEY_NO_RETURN JSON_HEDLEY_NEVER_INLINE void throw_type_must_be(const cha
|
||||
{
|
||||
static_cast<void>(expected); // unused when JSON_NOEXCEPTION is defined
|
||||
static_cast<void>(j);
|
||||
JSON_THROW(type_error::create(exception_id::type_mismatch, concat("type must be ", expected, ", but is ", j.type_name()), exception_context(j)));
|
||||
JSON_THROW(type_error::create(exception_id::type_mismatch, concat("type must be ", expected, ", but is ", j.type_name()), &j));
|
||||
}
|
||||
|
||||
/*!
|
||||
|
||||
@@ -235,9 +235,6 @@ class binary_reader
|
||||
/// UBJSON/BJData: the type marker of an optimized container, so that
|
||||
/// its elements are read without one of their own; 0 otherwise
|
||||
char_int_type type_marker;
|
||||
/// BSON: the position right after this document, according to the
|
||||
/// size it declares
|
||||
std::size_t end_position = 0;
|
||||
/// BSON: the size this document declares, in bytes
|
||||
std::int32_t declared_size = 0;
|
||||
/// whether to close this container with end_object() or end_array()
|
||||
@@ -374,23 +371,6 @@ class binary_reader
|
||||
return false;
|
||||
}
|
||||
|
||||
// the smallest document is the size prefix and the terminator
|
||||
if (JSON_HEDLEY_UNLIKELY(document_size < 5))
|
||||
{
|
||||
return bson_document_size_error("document size ", document_size, " is less than 5");
|
||||
}
|
||||
|
||||
// the declared size bounds where the document ends: an embedded
|
||||
// document must end before the terminator of the document that contains it
|
||||
const auto unsigned_size = static_cast<std::size_t>(document_size);
|
||||
const std::size_t document_end = unsigned_size > (std::numeric_limits<std::size_t>::max)() - document_start
|
||||
? (std::numeric_limits<std::size_t>::max)()
|
||||
: document_start + unsigned_size;
|
||||
if (JSON_HEDLEY_UNLIKELY(!container_stack.empty() && document_end >= container_stack.back().end_position))
|
||||
{
|
||||
return bson_document_size_error("document size ", document_size, " exceeds the size of the enclosing document");
|
||||
}
|
||||
|
||||
if (JSON_HEDLEY_UNLIKELY(!enter_container(is_object, detail::unknown_size())))
|
||||
{
|
||||
return false;
|
||||
@@ -398,7 +378,6 @@ class binary_reader
|
||||
|
||||
container_frame& frame = container_stack.back();
|
||||
frame.start_position = document_start;
|
||||
frame.end_position = document_end;
|
||||
frame.declared_size = document_size;
|
||||
return true;
|
||||
}
|
||||
@@ -457,13 +436,6 @@ class binary_reader
|
||||
return false;
|
||||
}
|
||||
|
||||
// an element needs at least its name's terminator, and the
|
||||
// document its own terminator, within the declared size
|
||||
if (JSON_HEDLEY_UNLIKELY(chars_read + 2 > container_stack.back().end_position))
|
||||
{
|
||||
return bson_document_size_error("document size ", container_stack.back().declared_size, " is too small for its content");
|
||||
}
|
||||
|
||||
const std::size_t element_type_parse_position = chars_read;
|
||||
key.clear();
|
||||
if (JSON_HEDLEY_UNLIKELY(!get_bson_cstr(key)))
|
||||
@@ -612,46 +584,9 @@ class binary_reader
|
||||
}
|
||||
result.set_subtype(subtype);
|
||||
|
||||
// the "old binary" subtype 0x02 starts with an int32 that repeats the
|
||||
// size of the payload following it; the payload does not include it
|
||||
if (subtype == 0x02)
|
||||
{
|
||||
return get_bson_old_binary(len, result);
|
||||
}
|
||||
|
||||
return get_binary(len, result);
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Parses the payload of a BSON binary value with subtype 0x02.
|
||||
@param[in] len The length of the binary value, including the inner int32.
|
||||
@param[in,out] result A reference to the binary variable where the payload
|
||||
(without the inner int32) is to be stored.
|
||||
@pre len >= 0
|
||||
@return `true` if the inner length was present and matches @a len
|
||||
*/
|
||||
template<typename NumberType>
|
||||
bool get_bson_old_binary(const NumberType len, binary_t& result)
|
||||
{
|
||||
if (JSON_HEDLEY_UNLIKELY(len < 4))
|
||||
{
|
||||
return bson_length_error("length of binary subtype 0x02 must be at least 4, is ", len, "binary");
|
||||
}
|
||||
|
||||
std::int32_t inner_length{};
|
||||
if (JSON_HEDLEY_UNLIKELY((!get_number<std::int32_t, true>(inner_length))))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (JSON_HEDLEY_UNLIKELY(static_cast<std::int64_t>(inner_length) != static_cast<std::int64_t>(len) - 4))
|
||||
{
|
||||
return bson_length_error("inner length of binary subtype 0x02 does not match the payload size; inner length is ", inner_length, "binary");
|
||||
}
|
||||
|
||||
return get_binary(inner_length, result);
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Read a BSON document element of the given @a element_type.
|
||||
@param[in] element_type The BSON element type, c.f. http://bsonspec.org/spec.html
|
||||
@@ -1283,10 +1218,6 @@ class binary_reader
|
||||
// level as required by RFC 8949, Section 3.2.3
|
||||
bool indefinite = false;
|
||||
|
||||
// the chunk currently being validated; only used for the chunks of an
|
||||
// indefinite-length string when the UTF-8 check can do something
|
||||
string_t chunk;
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (JSON_HEDLEY_UNLIKELY(!unexpect_eof("string")))
|
||||
@@ -1306,82 +1237,26 @@ class binary_reader
|
||||
}
|
||||
|
||||
// a break marker closes the indefinite-length string; outside
|
||||
// of one it falls through to the error below. Every chunk has
|
||||
// been checked on its own, so there is nothing left to check.
|
||||
// of one it falls through to the error below
|
||||
if (indefinite && current == 0xFF)
|
||||
{
|
||||
return true;
|
||||
return check_string_utf8(result, context);
|
||||
}
|
||||
|
||||
if (JSON_HEDLEY_UNLIKELY(!get_cbor_string_chunk(result, indefinite)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!indefinite)
|
||||
{
|
||||
return get_cbor_string_chunk(result, false) && check_string_utf8(result, context);
|
||||
}
|
||||
|
||||
if (error_handler == error_handler_t::keep)
|
||||
{
|
||||
// nothing to check: read the chunk directly into the result
|
||||
if (JSON_HEDLEY_UNLIKELY(!get_cbor_string_chunk(result, true)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// RFC 8949, Section 3.2.3: each chunk is a text string of its
|
||||
// own and must be valid UTF-8 by itself, i.e., a code point
|
||||
// cannot be spread over two chunks
|
||||
chunk.clear();
|
||||
if (JSON_HEDLEY_UNLIKELY(!get_cbor_string_chunk(chunk, true) || !check_string_utf8(chunk, context)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
result.append(chunk.data(), chunk.size());
|
||||
return check_string_utf8(result, context);
|
||||
}
|
||||
|
||||
get();
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief skips the tags in front of a CBOR object key
|
||||
|
||||
A tag may wrap any data item, so it may also wrap a key. Like in front of a
|
||||
value, the tags are skipped for the handlers ignore and store; with the
|
||||
handler error they are left to @ref get_cbor_object_key, which rejects the
|
||||
key. The tag loop is iterative, so the number of tags is not limited by the
|
||||
recursion depth.
|
||||
|
||||
@param[in] tag_handler how CBOR tags should be treated
|
||||
|
||||
@return whether the tags could be skipped (false on EOF in a tag argument)
|
||||
|
||||
@pre @a current is the first byte of the key
|
||||
*/
|
||||
bool skip_cbor_key_tags(const cbor_tag_handler_t tag_handler)
|
||||
{
|
||||
if (tag_handler == cbor_tag_handler_t::error)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// 0xC0..0xDB: tag with the tag number in the head (0xC0..0xD7) or in
|
||||
// the 1, 2, 4, or 8 bytes that follow (0xD8..0xDB)
|
||||
while (current >= 0xC0 && current <= 0xDB)
|
||||
{
|
||||
if (current >= 0xD8)
|
||||
{
|
||||
std::uint64_t tag_to_ignore{};
|
||||
if (JSON_HEDLEY_UNLIKELY(!get_cbor_argument(tag_to_ignore)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
get();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief reads a CBOR object key
|
||||
|
||||
@@ -1748,10 +1623,6 @@ class binary_reader
|
||||
|
||||
if (top.is_object)
|
||||
{
|
||||
if (JSON_HEDLEY_UNLIKELY(!skip_cbor_key_tags(tag_handler)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (JSON_HEDLEY_UNLIKELY(!read_object_key<&binary_reader::get_cbor_object_key>(key)))
|
||||
{
|
||||
return false;
|
||||
@@ -3065,14 +2936,6 @@ class binary_reader
|
||||
return false;
|
||||
}
|
||||
|
||||
// validate the type marker up front: otherwise it would only be
|
||||
// checked when an element is read, and a container with count 0
|
||||
// would accept any marker
|
||||
if (JSON_HEDLEY_UNLIKELY(!is_valid_optimized_type(result.second)))
|
||||
{
|
||||
return optimized_type_error();
|
||||
}
|
||||
|
||||
get_ignore_noop();
|
||||
if (JSON_HEDLEY_UNLIKELY(current != '#'))
|
||||
{
|
||||
@@ -3277,8 +3140,6 @@ class binary_reader
|
||||
// get_ubjson_size_value() (the type marker is known before the dimension vector
|
||||
// that determines size_and_type.first is read, so it is emitted first there to
|
||||
// match the documented _ArrayType_, _ArraySize_, _ArrayData_ key order)
|
||||
// 'C' elements are read as unsigned bytes, but BJData limits a char to 0..127
|
||||
const bool nd_is_char = size_and_type.second == 'C';
|
||||
if (size_and_type.second == 'C' || size_and_type.second == 'B')
|
||||
{
|
||||
size_and_type.second = 'U';
|
||||
@@ -3292,24 +3153,6 @@ class binary_reader
|
||||
|
||||
for (std::size_t i = 0; i < size_and_type.first; ++i)
|
||||
{
|
||||
if (nd_is_char)
|
||||
{
|
||||
get();
|
||||
if (JSON_HEDLEY_UNLIKELY(!unexpect_eof("char")))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (JSON_HEDLEY_UNLIKELY(current > 127))
|
||||
{
|
||||
return last_byte_error(exception_id::invalid_string_or_size, "byte after 'C' must be in range 0x00..0x7F", "char", "");
|
||||
}
|
||||
if (JSON_HEDLEY_UNLIKELY(!sax->number_unsigned(static_cast<number_unsigned_t>(current))))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (JSON_HEDLEY_UNLIKELY(!get_ubjson_value(size_and_type.second)))
|
||||
{
|
||||
return false;
|
||||
@@ -4287,9 +4130,9 @@ class binary_reader
|
||||
// sequence), UBJSON, BJData, or BSON requires a decoder to reject
|
||||
// ill-formed UTF-8. Checking (and, with @ref error_handler_t::strict,
|
||||
// rejecting, or with `replace`/`ignore`, sanitizing) is opt-in via
|
||||
// @ref error_handler, applied by @ref check_string_utf8 at the call
|
||||
// site to the whole string or, for an indefinite-length CBOR string,
|
||||
// to each chunk on its own (RFC 8949, Section 3.2.3).
|
||||
// @ref error_handler, applied once the whole string (all chunks of
|
||||
// an indefinite-length CBOR string included) has been assembled, by
|
||||
// @ref check_string_utf8 at the call site.
|
||||
return get_bytes(len, "string", result);
|
||||
}
|
||||
|
||||
@@ -4484,12 +4327,6 @@ class binary_reader
|
||||
return last_byte_error(exception_id::unexpected_byte, concat("document size ", std::to_string(document_size), " does not match the number of bytes read (", std::to_string(bytes_read), ")"), "document");
|
||||
}
|
||||
|
||||
JSON_HEDLEY_NEVER_INLINE
|
||||
bool bson_document_size_error(const char* prefix, const std::int32_t document_size, const char* suffix) const
|
||||
{
|
||||
return last_byte_error(exception_id::unexpected_byte, concat(prefix, std::to_string(document_size), suffix), "document");
|
||||
}
|
||||
|
||||
JSON_HEDLEY_NEVER_INLINE
|
||||
bool bson_unsupported_type_error(const std::size_t position, const char_int_type element_type) const
|
||||
{
|
||||
@@ -4595,44 +4432,6 @@ class binary_reader
|
||||
std::size_t bon8_pushback_size = 0;
|
||||
|
||||
JSON_PRIVATE_UNLESS_TESTED:
|
||||
/*!
|
||||
@brief check whether @a marker is a type marker that may follow '$'
|
||||
UBJSON: Z N T F i U I l L d D H C S [ {; BJData: the numeric markers and C
|
||||
(BJData's excluded markers are rejected separately).
|
||||
*/
|
||||
bool is_valid_optimized_type(const char_int_type marker) const noexcept
|
||||
{
|
||||
switch (marker)
|
||||
{
|
||||
case 'i':
|
||||
case 'U':
|
||||
case 'I':
|
||||
case 'l':
|
||||
case 'L':
|
||||
case 'd':
|
||||
case 'D':
|
||||
case 'C':
|
||||
return true;
|
||||
case 'Z':
|
||||
case 'N':
|
||||
case 'T':
|
||||
case 'F':
|
||||
case 'H':
|
||||
case 'S':
|
||||
case '[':
|
||||
case '{':
|
||||
return input_format != input_format_t::bjdata;
|
||||
case 'B':
|
||||
case 'u':
|
||||
case 'm':
|
||||
case 'M':
|
||||
case 'h':
|
||||
return input_format == input_format_t::bjdata;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief whether @a marker is excluded from BJData's optimized ND-array types
|
||||
@return whether @a marker is one of 'F', 'H', 'N', 'S', 'T', 'Z', '[', '{'
|
||||
@@ -4675,8 +4474,6 @@ class binary_reader
|
||||
return "uint8";
|
||||
case 'd':
|
||||
return "single";
|
||||
case 'h':
|
||||
return "half";
|
||||
case 'i':
|
||||
return "int8";
|
||||
case 'l':
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <algorithm> // all_of, copy
|
||||
#include <algorithm> // copy
|
||||
#include <array> // array
|
||||
#include <cctype> // isdigit
|
||||
#include <cerrno> // errno, ERANGE
|
||||
@@ -16,9 +16,11 @@
|
||||
#include <cstdint> // uint64_t
|
||||
#include <cstdlib> // strtoull
|
||||
#include <cstring> // memchr, memcmp, memcpy
|
||||
#include <functional> // less
|
||||
#ifndef JSON_NO_IO
|
||||
#include <iosfwd> // ostream
|
||||
#endif // JSON_NO_IO
|
||||
#include <iterator> // next
|
||||
#include <limits> // max
|
||||
#include <string> // string
|
||||
#include <utility> // move
|
||||
@@ -28,6 +30,7 @@
|
||||
#include <nlohmann/detail/macro_scope.hpp>
|
||||
#include <nlohmann/detail/meta/cpp_future.hpp>
|
||||
#include <nlohmann/detail/meta/type_traits.hpp>
|
||||
#include <nlohmann/detail/meta/void_t.hpp>
|
||||
#include <nlohmann/detail/string_concat.hpp>
|
||||
#include <nlohmann/detail/string_escape.hpp>
|
||||
#include <nlohmann/detail/string_utils.hpp>
|
||||
@@ -134,6 +137,26 @@ JSON_HEDLEY_ALWAYS_INLINE array_index_status parse_array_index(const StringType&
|
||||
return array_index_status::ok;
|
||||
}
|
||||
|
||||
/// whether two keys of type @a StringType are equivalent under @a Compare
|
||||
/// exactly if they are equal: std::less<StringType> and std::less<>
|
||||
template<typename Compare, typename StringType>
|
||||
struct is_less_comparator : std::false_type {};
|
||||
|
||||
template<typename StringType>
|
||||
struct is_less_comparator<std::less<StringType>, StringType> : std::true_type {};
|
||||
|
||||
template<typename StringType>
|
||||
struct is_less_comparator<std::less<void>, StringType> : std::true_type {};
|
||||
|
||||
/// whether the objects of type @a ObjectType find a key of type @a StringType
|
||||
/// exactly if it equals a stored key
|
||||
template<typename ObjectType, typename StringType, typename = void>
|
||||
struct finds_equal_keys : std::false_type {};
|
||||
|
||||
template<typename ObjectType, typename StringType>
|
||||
struct finds_equal_keys<ObjectType, StringType, void_t<typename ObjectType::key_compare, typename ObjectType::key_type>>
|
||||
: conjunction<is_less_comparator<typename ObjectType::key_compare, StringType>, std::is_same<typename ObjectType::key_type, StringType>> {};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
/// @brief JSON Pointer defines a string syntax for identifying a specific value within a JSON document
|
||||
@@ -589,6 +612,228 @@ class json_pointer
|
||||
return object_member_impl(object, key, detail::priority_tag<1> {});
|
||||
}
|
||||
|
||||
/// @brief append a null value to @a array, like operator[] with the size of @a array
|
||||
template<typename BasicJsonType>
|
||||
static BasicJsonType& array_append(BasicJsonType& array)
|
||||
{
|
||||
auto& elements = *array.m_data.m_value.array;
|
||||
const auto old_capacity = array.container_capacity();
|
||||
elements.emplace_back();
|
||||
return array.set_parent_after_insert(elements.back(), old_capacity);
|
||||
}
|
||||
|
||||
/// @brief add @a key, which is missing, to @a object
|
||||
template<typename BasicJsonType>
|
||||
static auto object_add_impl(BasicJsonType& object, const string_t& key, detail::priority_tag<1> /*unused*/)
|
||||
-> decltype(object.m_data.m_value.object->emplace(key, nullptr), std::declval<BasicJsonType&>())
|
||||
{
|
||||
const auto old_capacity = object.container_capacity();
|
||||
const auto it = object.m_data.m_value.object->emplace(key, nullptr).first;
|
||||
return object.set_parent_after_insert(it->second, old_capacity);
|
||||
}
|
||||
|
||||
template<typename BasicJsonType>
|
||||
static BasicJsonType& object_add_impl(BasicJsonType& object, const string_t& key, detail::priority_tag<0> /*unused*/)
|
||||
{
|
||||
return object.operator[](key);
|
||||
}
|
||||
|
||||
template<typename BasicJsonType>
|
||||
static BasicJsonType& object_add(BasicJsonType& object, const string_t& key)
|
||||
{
|
||||
return object_add_impl(object, key, detail::priority_tag<1> {});
|
||||
}
|
||||
|
||||
/// @brief search @a key in @a members: the result is where the key is or,
|
||||
/// for objects that can insert at a position (std::map), where it belongs
|
||||
template<typename ObjectType>
|
||||
static auto object_search_impl(ObjectType& members, const string_t& key, detail::priority_tag<1> /*unused*/)
|
||||
-> decltype(members.key_comp()(key, members.lower_bound(key)->first), members.lower_bound(key))
|
||||
{
|
||||
return members.lower_bound(key);
|
||||
}
|
||||
|
||||
template<typename ObjectType>
|
||||
static auto object_search_impl(ObjectType& members, const string_t& key, detail::priority_tag<0> /*unused*/)
|
||||
-> decltype(members.find(key))
|
||||
{
|
||||
return members.find(key);
|
||||
}
|
||||
|
||||
template<typename ObjectType>
|
||||
static auto object_search(ObjectType& members, const string_t& key)
|
||||
-> decltype(object_search_impl(members, key, detail::priority_tag<1> {}))
|
||||
{
|
||||
return object_search_impl(members, key, detail::priority_tag<1> {});
|
||||
}
|
||||
|
||||
/// @brief whether @a it, the result of @ref object_search for @a key, points to @a key
|
||||
///
|
||||
/// With std::less, the key at the lower bound is equivalent to @a key
|
||||
/// exactly if it is equal to it, and comparing for equality is cheaper.
|
||||
template<typename ObjectType, typename Iterator,
|
||||
detail::enable_if_t<detail::finds_equal_keys<ObjectType, string_t>::value, int> = 0>
|
||||
static auto object_search_found_impl(ObjectType& members, const Iterator& it, const string_t& key, detail::priority_tag<2> /*unused*/)
|
||||
-> decltype(members.lower_bound(key), it->first == key)
|
||||
{
|
||||
return it != members.end() && it->first == key;
|
||||
}
|
||||
|
||||
template<typename ObjectType, typename Iterator>
|
||||
static auto object_search_found_impl(ObjectType& members, const Iterator& it, const string_t& key, detail::priority_tag<1> /*unused*/)
|
||||
-> decltype(members.key_comp()(key, it->first), members.lower_bound(key), bool())
|
||||
{
|
||||
return it != members.end() && !members.key_comp()(key, it->first);
|
||||
}
|
||||
|
||||
template<typename ObjectType, typename Iterator>
|
||||
static bool object_search_found_impl(ObjectType& members, const Iterator& it, const string_t& /*key*/, detail::priority_tag<0> /*unused*/)
|
||||
{
|
||||
return it != members.end();
|
||||
}
|
||||
|
||||
template<typename ObjectType, typename Iterator>
|
||||
static bool object_search_found(ObjectType& members, const Iterator& it, const string_t& key)
|
||||
{
|
||||
return object_search_found_impl(members, it, key, detail::priority_tag<2> {});
|
||||
}
|
||||
|
||||
/// @brief insert @a key, which is missing, into @a object at @a it, the
|
||||
/// result of @ref object_search for @a key
|
||||
template<typename BasicJsonType, typename Iterator>
|
||||
static auto object_insert_impl(BasicJsonType& object, const Iterator& it, const string_t& key, detail::priority_tag<1> /*unused*/)
|
||||
-> decltype(object.m_data.m_value.object->emplace_hint(it, key, nullptr), std::declval<BasicJsonType&>())
|
||||
{
|
||||
const auto old_capacity = object.container_capacity();
|
||||
const auto pos = object.m_data.m_value.object->emplace_hint(it, key, nullptr);
|
||||
return object.set_parent_after_insert(pos->second, old_capacity);
|
||||
}
|
||||
|
||||
template<typename BasicJsonType, typename Iterator>
|
||||
static BasicJsonType& object_insert_impl(BasicJsonType& object, const Iterator& /*it*/, const string_t& key, detail::priority_tag<0> /*unused*/)
|
||||
{
|
||||
return object_add(object, key);
|
||||
}
|
||||
|
||||
template<typename BasicJsonType, typename Iterator>
|
||||
static BasicJsonType& object_insert(BasicJsonType& object, const Iterator& it, const string_t& key)
|
||||
{
|
||||
return object_insert_impl(object, it, key, detail::priority_tag<1> {});
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief undoes the change @ref get_unchecked_create made to an existing value
|
||||
|
||||
@ref get_unchecked walks existing values without changing them. At the
|
||||
first reference token that does not select an existing value, @ref
|
||||
get_unchecked_create makes exactly one change to an existing value: it
|
||||
converts a null value, inserts a key into an object, or grows an array.
|
||||
Everything it creates afterwards lies below that change. If a later step
|
||||
throws, the destructor of this guard reverts that one change, which
|
||||
removes everything created after it, so the value is left as it was
|
||||
(strong exception safety). The guard needs no try/catch and therefore also
|
||||
compiles with JSON_NOEXCEPTION.
|
||||
|
||||
Reverting the change must not throw, as it happens in a destructor. It
|
||||
erases the inserted member by its iterator (no key is converted or
|
||||
compared, nothing is allocated), erases the added elements at the end of
|
||||
the array, or swaps the null value back. This holds for std::map,
|
||||
std::vector, ordered_map, and every object_t, array_t, and
|
||||
json_base_class_t whose erase() and move operations do not throw.
|
||||
Between recording and reverting, nothing is inserted into or erased from
|
||||
the object or array, so the iterator stays valid.
|
||||
*/
|
||||
template<typename BasicJsonType>
|
||||
class get_unchecked_rollback
|
||||
{
|
||||
public:
|
||||
using object_iterator = typename BasicJsonType::object_t::iterator;
|
||||
|
||||
/// record that @a member was inserted into the object @a value
|
||||
get_unchecked_rollback(BasicJsonType* value, const object_iterator& member)
|
||||
: m_value(value)
|
||||
, m_member(member)
|
||||
, m_change(change::key_inserted)
|
||||
{}
|
||||
|
||||
/// record the change that the next reference token makes to the null value or array @a value
|
||||
explicit get_unchecked_rollback(BasicJsonType* value)
|
||||
: m_value(value)
|
||||
{
|
||||
if (value->is_null())
|
||||
{
|
||||
// keep the null value (with its base class and positions) and
|
||||
// continue with a fresh null value in its place, which is what
|
||||
// assigning an array or object to it would have left there
|
||||
m_saved_null.swap(*value);
|
||||
m_change = change::null_converted;
|
||||
}
|
||||
else
|
||||
{
|
||||
JSON_ASSERT(value->is_array());
|
||||
m_old_size = value->m_data.m_value.array->size();
|
||||
m_change = change::array_grown;
|
||||
}
|
||||
}
|
||||
|
||||
get_unchecked_rollback(const get_unchecked_rollback&) = delete;
|
||||
get_unchecked_rollback(get_unchecked_rollback&&) = delete;
|
||||
get_unchecked_rollback& operator=(const get_unchecked_rollback&) = delete;
|
||||
get_unchecked_rollback& operator=(get_unchecked_rollback&&) = delete;
|
||||
|
||||
~get_unchecked_rollback()
|
||||
{
|
||||
if (JSON_HEDLEY_UNLIKELY(m_change != change::none))
|
||||
{
|
||||
undo();
|
||||
}
|
||||
}
|
||||
|
||||
/// keep the change
|
||||
void commit() noexcept
|
||||
{
|
||||
m_change = change::none;
|
||||
}
|
||||
|
||||
private:
|
||||
JSON_HEDLEY_NEVER_INLINE void undo() noexcept
|
||||
{
|
||||
switch (m_change)
|
||||
{
|
||||
case change::null_converted:
|
||||
// the values created since go away with m_saved_null
|
||||
m_value->swap(m_saved_null);
|
||||
break;
|
||||
case change::key_inserted:
|
||||
m_value->m_data.m_value.object->erase(m_member);
|
||||
break;
|
||||
case change::array_grown:
|
||||
{
|
||||
auto& elements = *m_value->m_data.m_value.array;
|
||||
elements.erase(std::next(elements.begin(), static_cast<typename BasicJsonType::difference_type>(m_old_size)), elements.end());
|
||||
break;
|
||||
}
|
||||
case change::none:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
enum class change
|
||||
{
|
||||
none,
|
||||
null_converted,
|
||||
key_inserted,
|
||||
array_grown
|
||||
};
|
||||
|
||||
BasicJsonType* m_value;
|
||||
object_iterator m_member {};
|
||||
typename BasicJsonType::size_type m_old_size = 0;
|
||||
change m_change = change::none;
|
||||
BasicJsonType m_saved_null {};
|
||||
};
|
||||
|
||||
JSON_PRIVATE_UNLESS_TESTED:
|
||||
json_pointer top() const
|
||||
{
|
||||
@@ -972,47 +1217,245 @@ class json_pointer
|
||||
|
||||
Complexity: Linear in the length of the JSON pointer.
|
||||
|
||||
@throw parse_error.106 if an array index begins with '0'
|
||||
@throw parse_error.109 if an array index was not a number
|
||||
@throw out_of_range.404 if the JSON pointer can not be resolved
|
||||
Exception safety: Strong guarantee. This function walks existing values
|
||||
until the first reference token that does not select one. If that is the
|
||||
last reference token, inserting the key into the object or growing the
|
||||
array is strongly exception safe by itself; any other change is made by
|
||||
@ref get_unchecked_create, which undoes it if a later step throws.
|
||||
|
||||
@throw parse_error.106 if an array index of an existing array begins with '0'
|
||||
@throw parse_error.109 if an array index of an existing array was not a number
|
||||
@throw out_of_range.404 if the JSON pointer can not be resolved, or if an
|
||||
array index is too large for strtoull
|
||||
@throw out_of_range.410 if an array index exceeds size_type
|
||||
@throw std::length_error if padding an array exceeds its maximal size
|
||||
@throw std::bad_alloc if an allocation fails
|
||||
*/
|
||||
template<typename BasicJsonType>
|
||||
BasicJsonType& get_unchecked(BasicJsonType* ptr) const
|
||||
{
|
||||
for (const auto& reference_token : reference_tokens)
|
||||
const auto* token = reference_tokens.data();
|
||||
const auto* const end = token + reference_tokens.size();
|
||||
if (token == end)
|
||||
{
|
||||
return *ptr;
|
||||
}
|
||||
if (ptr->is_null())
|
||||
{
|
||||
// the null value is converted to an array or an object
|
||||
return get_unchecked_create(ptr, token, end);
|
||||
}
|
||||
|
||||
// walk existing values; the walk itself inserts nothing, which keeps
|
||||
// the loop fast (insertions are done below or in get_unchecked_create)
|
||||
typename BasicJsonType::object_t::iterator it;
|
||||
do
|
||||
{
|
||||
if (ptr->is_object())
|
||||
{
|
||||
auto& members = *ptr->m_data.m_value.object;
|
||||
it = object_search(members, *token);
|
||||
if (!object_search_found(members, it, *token))
|
||||
{
|
||||
// the key is inserted below or in get_unchecked_create
|
||||
break;
|
||||
}
|
||||
ptr = &it->second;
|
||||
}
|
||||
else if (ptr->is_array())
|
||||
{
|
||||
if (is_dash(*token))
|
||||
{
|
||||
if (token + 1 == end)
|
||||
{
|
||||
// explicitly treat "-" as index beyond the end
|
||||
return array_append(*ptr);
|
||||
}
|
||||
// an element is appended in get_unchecked_create
|
||||
break;
|
||||
}
|
||||
if (token + 1 == end)
|
||||
{
|
||||
// convert array index to number; unchecked access
|
||||
return ptr->operator[](array_index<BasicJsonType>(*token));
|
||||
}
|
||||
const auto idx = array_index<BasicJsonType>(*token);
|
||||
if (idx >= ptr->m_data.m_value.array->size())
|
||||
{
|
||||
// the array is padded in get_unchecked_create
|
||||
break;
|
||||
}
|
||||
ptr = &(*ptr->m_data.m_value.array)[idx];
|
||||
}
|
||||
else if (ptr->is_null())
|
||||
{
|
||||
// the null value is converted in get_unchecked_create
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
// primitive value with a reference token left
|
||||
throw_unresolved(*token, ptr);
|
||||
}
|
||||
}
|
||||
while (++token != end);
|
||||
|
||||
if (token == end)
|
||||
{
|
||||
return *ptr;
|
||||
}
|
||||
if (token + 1 == end && ptr->is_object())
|
||||
{
|
||||
// insert the missing key where the walk found it belongs
|
||||
return object_insert(*ptr, it, *token);
|
||||
}
|
||||
return get_unchecked_create(ptr, token, end);
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief create the values for the reference tokens from @a first on
|
||||
|
||||
Continues @ref get_unchecked at the first reference token that does not
|
||||
select an existing value. That token changes @a ptr, an existing value (see
|
||||
@ref get_unchecked_rollback); all later tokens only change values created
|
||||
here.
|
||||
|
||||
If the emplace() of the object type finds a member that the lookup in @ref
|
||||
get_unchecked did not find (the two disagree, e.g. for fifo_map), nothing
|
||||
is inserted, and the walk continues with that member as in @ref
|
||||
get_unchecked, which is what basic_json::operator[] does.
|
||||
|
||||
@param[in] ptr the value the reference token @a first is applied to
|
||||
@param[in] first the first reference token to resolve (an element of
|
||||
@ref reference_tokens)
|
||||
@param[in] end the end of @ref reference_tokens
|
||||
|
||||
@throw parse_error.106 if an array index of an existing array begins with
|
||||
'0' (only after emplace() found a member, see above)
|
||||
@throw parse_error.109 if an array index of an existing array was not a
|
||||
number (only after emplace() found a member)
|
||||
@throw out_of_range.404 if an array index is too large for strtoull, or (only
|
||||
after emplace() found a member) if the JSON pointer
|
||||
can not be resolved
|
||||
@throw out_of_range.410 if an array index exceeds size_type
|
||||
@throw std::length_error if padding an array exceeds its maximal size
|
||||
@throw std::bad_alloc if an allocation fails
|
||||
*/
|
||||
template<typename BasicJsonType>
|
||||
JSON_HEDLEY_NEVER_INLINE static BasicJsonType& get_unchecked_create(BasicJsonType* ptr, const string_t* first, const string_t* end)
|
||||
{
|
||||
const auto* token = first;
|
||||
while (ptr->is_object())
|
||||
{
|
||||
const auto old_capacity = ptr->container_capacity();
|
||||
const auto inserted = ptr->m_data.m_value.object->emplace(*token, nullptr);
|
||||
if (JSON_HEDLEY_LIKELY(inserted.second))
|
||||
{
|
||||
get_unchecked_rollback<BasicJsonType> rollback(ptr, inserted.first);
|
||||
BasicJsonType& result = create_values(&ptr->set_parent_after_insert(inserted.first->second, old_capacity), token + 1, end);
|
||||
rollback.commit();
|
||||
return result;
|
||||
}
|
||||
|
||||
// nothing was inserted: walk existing values from the member
|
||||
// emplace() found on, like get_unchecked
|
||||
ptr = &inserted.first->second;
|
||||
while (++token != end)
|
||||
{
|
||||
if (ptr->is_object())
|
||||
{
|
||||
auto& members = *ptr->m_data.m_value.object;
|
||||
const auto it = object_search(members, *token);
|
||||
if (!object_search_found(members, it, *token))
|
||||
{
|
||||
break;
|
||||
}
|
||||
ptr = &it->second;
|
||||
}
|
||||
else if (ptr->is_array())
|
||||
{
|
||||
if (is_dash(*token))
|
||||
{
|
||||
break;
|
||||
}
|
||||
const auto idx = array_index<BasicJsonType>(*token);
|
||||
if (idx >= ptr->m_data.m_value.array->size())
|
||||
{
|
||||
break;
|
||||
}
|
||||
ptr = &(*ptr->m_data.m_value.array)[idx];
|
||||
}
|
||||
else if (ptr->is_null())
|
||||
{
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
// primitive value with a reference token left
|
||||
throw_unresolved(*token, ptr);
|
||||
}
|
||||
}
|
||||
if (token == end)
|
||||
{
|
||||
return *ptr;
|
||||
}
|
||||
}
|
||||
|
||||
get_unchecked_rollback<BasicJsonType> rollback(ptr);
|
||||
BasicJsonType& result = create_values(ptr, token, end);
|
||||
rollback.commit();
|
||||
return result;
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief the loop of @ref get_unchecked_create
|
||||
|
||||
@a ptr is a null value or an array. Every value created here is a fresh
|
||||
one, so every object a key is added to is empty.
|
||||
|
||||
@throw out_of_range.404 if an array index is too large for strtoull
|
||||
@throw out_of_range.410 if an array index exceeds size_type
|
||||
@throw std::length_error if padding an array exceeds its maximal size
|
||||
@throw std::bad_alloc if an allocation fails
|
||||
*/
|
||||
template<typename BasicJsonType>
|
||||
static BasicJsonType& create_values(BasicJsonType* ptr, const string_t* first, const string_t* end)
|
||||
{
|
||||
for (const auto* token = first; token != end; ++token)
|
||||
{
|
||||
const auto& reference_token = *token;
|
||||
|
||||
// convert null values to arrays or objects before continuing
|
||||
if (ptr->is_null())
|
||||
{
|
||||
// check if the reference token is a valid array index, that is
|
||||
// a nonempty sequence of digits without a leading '0'
|
||||
// (cf. RFC 6901, Sect. 4); tokens that could never be a valid
|
||||
// array index (such as "01" or "") are treated as object keys
|
||||
const bool nums = !reference_token.empty()
|
||||
&& (reference_token.size() == 1 || reference_token[0] != '0')
|
||||
&& std::all_of(reference_token.begin(), reference_token.end(),
|
||||
[](const unsigned char x)
|
||||
// change value to an array for array indices or "-" or to an
|
||||
// object otherwise; every null value here is a fresh one (see
|
||||
// get_unchecked_rollback), so converting it in place leaves
|
||||
// the same value as assigning an array or object to it
|
||||
if (is_array_index_token(reference_token) || is_dash(reference_token))
|
||||
{
|
||||
return std::isdigit(x);
|
||||
});
|
||||
|
||||
// change value to an array for array indices or "-" or to object otherwise
|
||||
*ptr = (nums || reference_token == "-")
|
||||
? detail::value_t::array
|
||||
: detail::value_t::object;
|
||||
ptr->template convert_null_to<typename BasicJsonType::array_t>();
|
||||
}
|
||||
else
|
||||
{
|
||||
ptr->template convert_null_to<typename BasicJsonType::object_t>();
|
||||
}
|
||||
}
|
||||
|
||||
if (ptr->is_object())
|
||||
{
|
||||
// use unchecked object access
|
||||
ptr = &object_member(*ptr, reference_token);
|
||||
// the object is new and empty
|
||||
ptr = &object_add(*ptr, reference_token);
|
||||
}
|
||||
else if (ptr->is_array())
|
||||
else
|
||||
{
|
||||
if (reference_token == "-")
|
||||
// only the first value is not created here, and it is a null
|
||||
// value or an array (see get_unchecked_create)
|
||||
JSON_ASSERT(ptr->is_array());
|
||||
if (is_dash(reference_token))
|
||||
{
|
||||
// explicitly treat "-" as index beyond the end
|
||||
ptr = &ptr->operator[](ptr->m_data.m_value.array->size());
|
||||
ptr = &array_append(*ptr);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1020,16 +1463,31 @@ class json_pointer
|
||||
ptr = &ptr->operator[](array_index<BasicJsonType>(reference_token));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// primitive value with a reference token left
|
||||
throw_unresolved(reference_token, ptr);
|
||||
}
|
||||
}
|
||||
|
||||
return *ptr;
|
||||
}
|
||||
|
||||
/// whether @a s is a valid array index, that is a nonempty sequence of
|
||||
/// digits without a leading '0' (cf. RFC 6901, Sect. 4); tokens that could
|
||||
/// never be a valid array index (such as "01" or "") are object keys
|
||||
static bool is_array_index_token(const string_t& s)
|
||||
{
|
||||
const std::size_t size = s.size();
|
||||
if (size == 0 || (size > 1 && s[0] == '0'))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
for (std::size_t i = 0; i < size; ++i)
|
||||
{
|
||||
if (std::isdigit(static_cast<unsigned char>(s[i])) == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/*!
|
||||
@throw parse_error.106 if an array index begins with '0'
|
||||
@throw parse_error.109 if an array index was not a number
|
||||
|
||||
@@ -291,17 +291,15 @@
|
||||
}); \
|
||||
j = ((it != std::end(m)) ? it : std::begin(m))->second; \
|
||||
} \
|
||||
template<typename BasicJsonType, nlohmann::detail::enable_if_t<nlohmann::detail::is_basic_json_or_view<BasicJsonType>::value, int> = 0> \
|
||||
template<typename BasicJsonType> \
|
||||
inline void from_json(const BasicJsonType& j, ENUM_TYPE& e) \
|
||||
{ \
|
||||
/* NOLINTNEXTLINE(modernize-type-traits) we use C++11 */ \
|
||||
static_assert(std::is_enum<ENUM_TYPE>::value, #ENUM_TYPE " must be an enum!"); \
|
||||
/* (for a view, the table holds basic_json values, which compare with the view) */ \
|
||||
using nlohmann_json_value_t = nlohmann::detail::json_type_of_t<BasicJsonType>; \
|
||||
/* NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) we don't want to depend on <array> */ \
|
||||
static const std::pair<ENUM_TYPE, nlohmann_json_value_t> m[] = __VA_ARGS__; \
|
||||
static const std::pair<ENUM_TYPE, BasicJsonType> m[] = __VA_ARGS__; \
|
||||
auto it = std::find_if(std::begin(m), std::end(m), \
|
||||
[&j](const std::pair<ENUM_TYPE, nlohmann_json_value_t>& ej_pair) -> bool \
|
||||
[&j](const std::pair<ENUM_TYPE, BasicJsonType>& ej_pair) -> bool \
|
||||
{ \
|
||||
return ej_pair.second == j; \
|
||||
}); \
|
||||
@@ -332,22 +330,20 @@
|
||||
if (it != std::end(m)) j = it->second; \
|
||||
else ::nlohmann::detail::templated_json_throw<nlohmann::detail::out_of_range>(nlohmann::detail::out_of_range::create(nlohmann::detail::exception_id::value_out_of_range,"enum value out of range for " #ENUM_TYPE, nullptr)); \
|
||||
} \
|
||||
template<typename BasicJsonType, nlohmann::detail::enable_if_t<nlohmann::detail::is_basic_json_or_view<BasicJsonType>::value, int> = 0> \
|
||||
template<typename BasicJsonType> \
|
||||
inline void from_json(const BasicJsonType& j, ENUM_TYPE& e) \
|
||||
{ \
|
||||
/* NOLINTNEXTLINE(modernize-type-traits) we use C++11 */ \
|
||||
static_assert(std::is_enum<ENUM_TYPE>::value, #ENUM_TYPE " must be an enum!"); \
|
||||
/* (for a view, the table holds basic_json values, which compare with the view) */ \
|
||||
using nlohmann_json_value_t = nlohmann::detail::json_type_of_t<BasicJsonType>; \
|
||||
/* NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) we don't want to depend on <array> */ \
|
||||
static const std::pair<ENUM_TYPE, nlohmann_json_value_t> m[] = __VA_ARGS__; \
|
||||
static const std::pair<ENUM_TYPE, BasicJsonType> m[] = __VA_ARGS__; \
|
||||
auto it = std::find_if(std::begin(m), std::end(m), \
|
||||
[&j](const std::pair<ENUM_TYPE, nlohmann_json_value_t>& ej_pair) -> bool \
|
||||
[&j](const std::pair<ENUM_TYPE, BasicJsonType>& ej_pair) -> bool \
|
||||
{ \
|
||||
return ej_pair.second == j; \
|
||||
}); \
|
||||
if (it != std::end(m)) e = it->first; \
|
||||
else ::nlohmann::detail::templated_json_throw<nlohmann::detail::out_of_range>(nlohmann::detail::out_of_range::create(nlohmann::detail::exception_id::value_out_of_range, nlohmann::detail::concat("enum value out of range for " #ENUM_TYPE ": ", nlohmann::detail::from_json_dump(j)), nlohmann::detail::exception_context(j))); \
|
||||
else ::nlohmann::detail::templated_json_throw<nlohmann::detail::out_of_range>(nlohmann::detail::out_of_range::create(nlohmann::detail::exception_id::value_out_of_range, nlohmann::detail::concat("enum value out of range for " #ENUM_TYPE ": ", j.dump(-1, ' ', false, nlohmann::detail::error_handler_t::replace)), &j)); \
|
||||
}
|
||||
|
||||
// Ugly macros to avoid uglier copy-paste when specializing basic_json. They
|
||||
@@ -607,8 +603,6 @@
|
||||
#define NLOHMANN_JSON_FROM_WITH_DEFAULT_WITH_NAME(v1, v2) nlohmann_json_t.v2 = !nlohmann_json_j.is_null() ? nlohmann_json_j.value(v1, nlohmann_json_default_obj.v2) : nlohmann_json_default_obj.v2;
|
||||
|
||||
#define NLOHMANN_JSON_BASIC_TYPE_TEMPLATE(...) template<typename BasicJsonType, nlohmann::detail::enable_if_t<nlohmann::detail::is_basic_json<BasicJsonType>::value, int> = 0> __VA_ARGS__
|
||||
// from_json() also reads from the views of <nlohmann/json_view.hpp>
|
||||
#define NLOHMANN_JSON_FROM_TYPE_TEMPLATE(...) template<typename BasicJsonType, nlohmann::detail::enable_if_t<nlohmann::detail::is_basic_json_or_view<BasicJsonType>::value, int> = 0> __VA_ARGS__
|
||||
|
||||
// Helpers used to dispatch the NLOHMANN_DEFINE_TYPE_*/NLOHMANN_DEFINE_DERIVED_TYPE_*
|
||||
// macros below between a zero-member and a one-or-more-member implementation
|
||||
@@ -661,18 +655,18 @@
|
||||
*/
|
||||
#define NLOHMANN_JSON_DEFINE_TYPE_INTRUSIVE_MEMBERS(Type, ...) \
|
||||
NLOHMANN_JSON_BASIC_TYPE_TEMPLATE(friend void to_json(BasicJsonType& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) }) \
|
||||
NLOHMANN_JSON_FROM_TYPE_TEMPLATE(friend void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, __VA_ARGS__)) })
|
||||
NLOHMANN_JSON_BASIC_TYPE_TEMPLATE(friend void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, __VA_ARGS__)) })
|
||||
|
||||
#define NLOHMANN_JSON_DEFINE_TYPE_INTRUSIVE_EMPTY(Type) \
|
||||
NLOHMANN_JSON_BASIC_TYPE_TEMPLATE(friend void to_json(BasicJsonType& nlohmann_json_j, const Type&) { nlohmann_json_j = BasicJsonType::object(); }) \
|
||||
/* NOLINTNEXTLINE(bugprone-macro-parentheses) Type is used as a declarator type, not in an expression */ \
|
||||
NLOHMANN_JSON_FROM_TYPE_TEMPLATE(friend void from_json(const BasicJsonType&, Type&) noexcept { })
|
||||
NLOHMANN_JSON_BASIC_TYPE_TEMPLATE(friend void from_json(const BasicJsonType&, Type&) noexcept { })
|
||||
|
||||
#define NLOHMANN_DEFINE_TYPE_INTRUSIVE(...) NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_TYPE_BODY(NLOHMANN_JSON_DEFINE_TYPE_INTRUSIVE_, __VA_ARGS__)(__VA_ARGS__))
|
||||
|
||||
#define NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_NAMES(Type, ...) \
|
||||
NLOHMANN_JSON_BASIC_TYPE_TEMPLATE(friend void to_json(BasicJsonType& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_DOUBLE_PASTE(NLOHMANN_JSON_TO_WITH_NAME, __VA_ARGS__)) }) \
|
||||
NLOHMANN_JSON_FROM_TYPE_TEMPLATE(friend void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_DOUBLE_PASTE(NLOHMANN_JSON_FROM_WITH_NAME, __VA_ARGS__)) })
|
||||
NLOHMANN_JSON_BASIC_TYPE_TEMPLATE(friend void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_DOUBLE_PASTE(NLOHMANN_JSON_FROM_WITH_NAME, __VA_ARGS__)) })
|
||||
|
||||
/*!
|
||||
@brief macro
|
||||
@@ -682,7 +676,7 @@
|
||||
*/
|
||||
#define NLOHMANN_JSON_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT_MEMBERS(Type, ...) \
|
||||
NLOHMANN_JSON_BASIC_TYPE_TEMPLATE(friend void to_json(BasicJsonType& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) }) \
|
||||
NLOHMANN_JSON_FROM_TYPE_TEMPLATE(friend void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { const Type nlohmann_json_default_obj{}; NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM_WITH_DEFAULT, __VA_ARGS__)) })
|
||||
NLOHMANN_JSON_BASIC_TYPE_TEMPLATE(friend void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { const Type nlohmann_json_default_obj{}; NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM_WITH_DEFAULT, __VA_ARGS__)) })
|
||||
|
||||
// identical to NLOHMANN_JSON_DEFINE_TYPE_INTRUSIVE_EMPTY: with no members there is nothing to default
|
||||
#define NLOHMANN_JSON_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT_EMPTY(Type) NLOHMANN_JSON_DEFINE_TYPE_INTRUSIVE_EMPTY(Type)
|
||||
@@ -691,7 +685,7 @@
|
||||
|
||||
#define NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT_WITH_NAMES(Type, ...) \
|
||||
NLOHMANN_JSON_BASIC_TYPE_TEMPLATE(friend void to_json(BasicJsonType& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_DOUBLE_PASTE(NLOHMANN_JSON_TO_WITH_NAME, __VA_ARGS__)) }) \
|
||||
NLOHMANN_JSON_FROM_TYPE_TEMPLATE(friend void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { const Type nlohmann_json_default_obj{}; NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_DOUBLE_PASTE(NLOHMANN_JSON_FROM_WITH_DEFAULT_WITH_NAME, __VA_ARGS__)) })
|
||||
NLOHMANN_JSON_BASIC_TYPE_TEMPLATE(friend void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { const Type nlohmann_json_default_obj{}; NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_DOUBLE_PASTE(NLOHMANN_JSON_FROM_WITH_DEFAULT_WITH_NAME, __VA_ARGS__)) })
|
||||
|
||||
/*!
|
||||
@brief macro
|
||||
@@ -718,18 +712,18 @@
|
||||
*/
|
||||
#define NLOHMANN_JSON_DEFINE_TYPE_NON_INTRUSIVE_MEMBERS(Type, ...) \
|
||||
NLOHMANN_JSON_BASIC_TYPE_TEMPLATE(void to_json(BasicJsonType& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) }) \
|
||||
NLOHMANN_JSON_FROM_TYPE_TEMPLATE(void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, __VA_ARGS__)) })
|
||||
NLOHMANN_JSON_BASIC_TYPE_TEMPLATE(void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, __VA_ARGS__)) })
|
||||
|
||||
#define NLOHMANN_JSON_DEFINE_TYPE_NON_INTRUSIVE_EMPTY(Type) \
|
||||
NLOHMANN_JSON_BASIC_TYPE_TEMPLATE(void to_json(BasicJsonType& nlohmann_json_j, const Type&) { nlohmann_json_j = BasicJsonType::object(); }) \
|
||||
/* NOLINTNEXTLINE(bugprone-macro-parentheses) Type is used as a declarator type, not in an expression */ \
|
||||
NLOHMANN_JSON_FROM_TYPE_TEMPLATE(void from_json(const BasicJsonType&, Type&) noexcept { })
|
||||
NLOHMANN_JSON_BASIC_TYPE_TEMPLATE(void from_json(const BasicJsonType&, Type&) noexcept { })
|
||||
|
||||
#define NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(...) NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_TYPE_BODY(NLOHMANN_JSON_DEFINE_TYPE_NON_INTRUSIVE_, __VA_ARGS__)(__VA_ARGS__))
|
||||
|
||||
#define NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_NAMES(Type, ...) \
|
||||
NLOHMANN_JSON_BASIC_TYPE_TEMPLATE(void to_json(BasicJsonType& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_DOUBLE_PASTE(NLOHMANN_JSON_TO_WITH_NAME, __VA_ARGS__)) }) \
|
||||
NLOHMANN_JSON_FROM_TYPE_TEMPLATE(void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_DOUBLE_PASTE(NLOHMANN_JSON_FROM_WITH_NAME, __VA_ARGS__)) })
|
||||
NLOHMANN_JSON_BASIC_TYPE_TEMPLATE(void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_DOUBLE_PASTE(NLOHMANN_JSON_FROM_WITH_NAME, __VA_ARGS__)) })
|
||||
|
||||
/*!
|
||||
@brief macro
|
||||
@@ -739,7 +733,7 @@
|
||||
*/
|
||||
#define NLOHMANN_JSON_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT_MEMBERS(Type, ...) \
|
||||
NLOHMANN_JSON_BASIC_TYPE_TEMPLATE(void to_json(BasicJsonType& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) }) \
|
||||
NLOHMANN_JSON_FROM_TYPE_TEMPLATE(void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { const Type nlohmann_json_default_obj{}; NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM_WITH_DEFAULT, __VA_ARGS__)) })
|
||||
NLOHMANN_JSON_BASIC_TYPE_TEMPLATE(void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { const Type nlohmann_json_default_obj{}; NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM_WITH_DEFAULT, __VA_ARGS__)) })
|
||||
|
||||
// identical to NLOHMANN_JSON_DEFINE_TYPE_NON_INTRUSIVE_EMPTY: with no members there is nothing to default
|
||||
#define NLOHMANN_JSON_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT_EMPTY(Type) NLOHMANN_JSON_DEFINE_TYPE_NON_INTRUSIVE_EMPTY(Type)
|
||||
@@ -748,7 +742,7 @@
|
||||
|
||||
#define NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT_WITH_NAMES(Type, ...) \
|
||||
NLOHMANN_JSON_BASIC_TYPE_TEMPLATE(void to_json(BasicJsonType& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_DOUBLE_PASTE(NLOHMANN_JSON_TO_WITH_NAME, __VA_ARGS__)) }) \
|
||||
NLOHMANN_JSON_FROM_TYPE_TEMPLATE(void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { const Type nlohmann_json_default_obj{}; NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_DOUBLE_PASTE(NLOHMANN_JSON_FROM_WITH_DEFAULT_WITH_NAME, __VA_ARGS__)) })
|
||||
NLOHMANN_JSON_BASIC_TYPE_TEMPLATE(void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { const Type nlohmann_json_default_obj{}; NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_DOUBLE_PASTE(NLOHMANN_JSON_FROM_WITH_DEFAULT_WITH_NAME, __VA_ARGS__)) })
|
||||
|
||||
/*!
|
||||
@brief macro
|
||||
@@ -775,18 +769,18 @@
|
||||
*/
|
||||
#define NLOHMANN_JSON_DEFINE_DERIVED_TYPE_INTRUSIVE_MEMBERS(Type, BaseType, ...) \
|
||||
NLOHMANN_JSON_BASIC_TYPE_TEMPLATE(friend void to_json(BasicJsonType& nlohmann_json_j, const Type& nlohmann_json_t) { nlohmann::to_json(nlohmann_json_j, static_cast<const BaseType &>(nlohmann_json_t)); NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) }) \
|
||||
NLOHMANN_JSON_FROM_TYPE_TEMPLATE(friend void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { ::nlohmann::detail::from_json_base(nlohmann_json_j, static_cast<BaseType&>(nlohmann_json_t)); NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, __VA_ARGS__)) })
|
||||
NLOHMANN_JSON_BASIC_TYPE_TEMPLATE(friend void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { nlohmann::from_json(nlohmann_json_j, static_cast<BaseType&>(nlohmann_json_t)); NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, __VA_ARGS__)) })
|
||||
|
||||
#define NLOHMANN_JSON_DEFINE_DERIVED_TYPE_INTRUSIVE_EMPTY(Type, BaseType) \
|
||||
NLOHMANN_JSON_BASIC_TYPE_TEMPLATE(friend void to_json(BasicJsonType& nlohmann_json_j, const Type& nlohmann_json_t) { nlohmann::to_json(nlohmann_json_j, static_cast<const BaseType &>(nlohmann_json_t)); }) \
|
||||
/* NOLINTNEXTLINE(bugprone-macro-parentheses) Type/BaseType are used as declarator types, not in expressions */ \
|
||||
NLOHMANN_JSON_FROM_TYPE_TEMPLATE(friend void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { ::nlohmann::detail::from_json_base(nlohmann_json_j, static_cast<BaseType&>(nlohmann_json_t)); })
|
||||
NLOHMANN_JSON_BASIC_TYPE_TEMPLATE(friend void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { nlohmann::from_json(nlohmann_json_j, static_cast<BaseType&>(nlohmann_json_t)); })
|
||||
|
||||
#define NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE(...) NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_DERIVED_TYPE_BODY(NLOHMANN_JSON_DEFINE_DERIVED_TYPE_INTRUSIVE_, __VA_ARGS__)(__VA_ARGS__))
|
||||
|
||||
#define NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE_WITH_NAMES(Type, BaseType, ...) \
|
||||
NLOHMANN_JSON_BASIC_TYPE_TEMPLATE(friend void to_json(BasicJsonType& nlohmann_json_j, const Type& nlohmann_json_t) { nlohmann::to_json(nlohmann_json_j, static_cast<const BaseType &>(nlohmann_json_t)); NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_DOUBLE_PASTE(NLOHMANN_JSON_TO_WITH_NAME, __VA_ARGS__)) }) \
|
||||
NLOHMANN_JSON_FROM_TYPE_TEMPLATE(friend void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { ::nlohmann::detail::from_json_base(nlohmann_json_j, static_cast<BaseType&>(nlohmann_json_t)); NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_DOUBLE_PASTE(NLOHMANN_JSON_FROM_WITH_NAME, __VA_ARGS__)) })
|
||||
NLOHMANN_JSON_BASIC_TYPE_TEMPLATE(friend void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { nlohmann::from_json(nlohmann_json_j, static_cast<BaseType&>(nlohmann_json_t)); NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_DOUBLE_PASTE(NLOHMANN_JSON_FROM_WITH_NAME, __VA_ARGS__)) })
|
||||
|
||||
/*!
|
||||
@brief macro
|
||||
@@ -796,7 +790,7 @@
|
||||
*/
|
||||
#define NLOHMANN_JSON_DEFINE_DERIVED_TYPE_INTRUSIVE_WITH_DEFAULT_MEMBERS(Type, BaseType, ...) \
|
||||
NLOHMANN_JSON_BASIC_TYPE_TEMPLATE(friend void to_json(BasicJsonType& nlohmann_json_j, const Type& nlohmann_json_t) { nlohmann::to_json(nlohmann_json_j, static_cast<const BaseType&>(nlohmann_json_t)); NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) }) \
|
||||
NLOHMANN_JSON_FROM_TYPE_TEMPLATE(friend void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { ::nlohmann::detail::from_json_base(nlohmann_json_j, static_cast<BaseType&>(nlohmann_json_t)); const Type nlohmann_json_default_obj{}; NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM_WITH_DEFAULT, __VA_ARGS__)) })
|
||||
NLOHMANN_JSON_BASIC_TYPE_TEMPLATE(friend void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { nlohmann::from_json(nlohmann_json_j, static_cast<BaseType&>(nlohmann_json_t)); const Type nlohmann_json_default_obj{}; NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM_WITH_DEFAULT, __VA_ARGS__)) })
|
||||
|
||||
// identical to NLOHMANN_JSON_DEFINE_DERIVED_TYPE_INTRUSIVE_EMPTY: with no members there is nothing to default
|
||||
#define NLOHMANN_JSON_DEFINE_DERIVED_TYPE_INTRUSIVE_WITH_DEFAULT_EMPTY(Type, BaseType) NLOHMANN_JSON_DEFINE_DERIVED_TYPE_INTRUSIVE_EMPTY(Type, BaseType)
|
||||
@@ -805,7 +799,7 @@
|
||||
|
||||
#define NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE_WITH_DEFAULT_WITH_NAMES(Type, BaseType, ...) \
|
||||
NLOHMANN_JSON_BASIC_TYPE_TEMPLATE(friend void to_json(BasicJsonType& nlohmann_json_j, const Type& nlohmann_json_t) { nlohmann::to_json(nlohmann_json_j, static_cast<const BaseType&>(nlohmann_json_t)); NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_DOUBLE_PASTE(NLOHMANN_JSON_TO_WITH_NAME, __VA_ARGS__)) }) \
|
||||
NLOHMANN_JSON_FROM_TYPE_TEMPLATE(friend void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { ::nlohmann::detail::from_json_base(nlohmann_json_j, static_cast<BaseType&>(nlohmann_json_t)); const Type nlohmann_json_default_obj{}; NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_DOUBLE_PASTE(NLOHMANN_JSON_FROM_WITH_DEFAULT_WITH_NAME, __VA_ARGS__)) })
|
||||
NLOHMANN_JSON_BASIC_TYPE_TEMPLATE(friend void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { nlohmann::from_json(nlohmann_json_j, static_cast<BaseType&>(nlohmann_json_t)); const Type nlohmann_json_default_obj{}; NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_DOUBLE_PASTE(NLOHMANN_JSON_FROM_WITH_DEFAULT_WITH_NAME, __VA_ARGS__)) })
|
||||
|
||||
/*!
|
||||
@brief macro
|
||||
@@ -833,18 +827,18 @@
|
||||
*/
|
||||
#define NLOHMANN_JSON_DEFINE_DERIVED_TYPE_NON_INTRUSIVE_MEMBERS(Type, BaseType, ...) \
|
||||
NLOHMANN_JSON_BASIC_TYPE_TEMPLATE(void to_json(BasicJsonType& nlohmann_json_j, const Type& nlohmann_json_t) { nlohmann::to_json(nlohmann_json_j, static_cast<const BaseType &>(nlohmann_json_t)); NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) }) \
|
||||
NLOHMANN_JSON_FROM_TYPE_TEMPLATE(void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { ::nlohmann::detail::from_json_base(nlohmann_json_j, static_cast<BaseType&>(nlohmann_json_t)); NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, __VA_ARGS__)) })
|
||||
NLOHMANN_JSON_BASIC_TYPE_TEMPLATE(void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { nlohmann::from_json(nlohmann_json_j, static_cast<BaseType&>(nlohmann_json_t)); NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, __VA_ARGS__)) })
|
||||
|
||||
#define NLOHMANN_JSON_DEFINE_DERIVED_TYPE_NON_INTRUSIVE_EMPTY(Type, BaseType) \
|
||||
NLOHMANN_JSON_BASIC_TYPE_TEMPLATE(void to_json(BasicJsonType& nlohmann_json_j, const Type& nlohmann_json_t) { nlohmann::to_json(nlohmann_json_j, static_cast<const BaseType &>(nlohmann_json_t)); }) \
|
||||
/* NOLINTNEXTLINE(bugprone-macro-parentheses) Type/BaseType are used as declarator types, not in expressions */ \
|
||||
NLOHMANN_JSON_FROM_TYPE_TEMPLATE(void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { ::nlohmann::detail::from_json_base(nlohmann_json_j, static_cast<BaseType&>(nlohmann_json_t)); })
|
||||
NLOHMANN_JSON_BASIC_TYPE_TEMPLATE(void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { nlohmann::from_json(nlohmann_json_j, static_cast<BaseType&>(nlohmann_json_t)); })
|
||||
|
||||
#define NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE(...) NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_DERIVED_TYPE_BODY(NLOHMANN_JSON_DEFINE_DERIVED_TYPE_NON_INTRUSIVE_, __VA_ARGS__)(__VA_ARGS__))
|
||||
|
||||
#define NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE_WITH_NAMES(Type, BaseType, ...) \
|
||||
NLOHMANN_JSON_BASIC_TYPE_TEMPLATE(void to_json(BasicJsonType& nlohmann_json_j, const Type& nlohmann_json_t) { nlohmann::to_json(nlohmann_json_j, static_cast<const BaseType &>(nlohmann_json_t)); NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_DOUBLE_PASTE(NLOHMANN_JSON_TO_WITH_NAME, __VA_ARGS__)) }) \
|
||||
NLOHMANN_JSON_FROM_TYPE_TEMPLATE(void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { ::nlohmann::detail::from_json_base(nlohmann_json_j, static_cast<BaseType&>(nlohmann_json_t)); NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_DOUBLE_PASTE(NLOHMANN_JSON_FROM_WITH_NAME, __VA_ARGS__)) })
|
||||
NLOHMANN_JSON_BASIC_TYPE_TEMPLATE(void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { nlohmann::from_json(nlohmann_json_j, static_cast<BaseType&>(nlohmann_json_t)); NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_DOUBLE_PASTE(NLOHMANN_JSON_FROM_WITH_NAME, __VA_ARGS__)) })
|
||||
|
||||
/*!
|
||||
@brief macro
|
||||
@@ -854,7 +848,7 @@
|
||||
*/
|
||||
#define NLOHMANN_JSON_DEFINE_DERIVED_TYPE_NON_INTRUSIVE_WITH_DEFAULT_MEMBERS(Type, BaseType, ...) \
|
||||
NLOHMANN_JSON_BASIC_TYPE_TEMPLATE(void to_json(BasicJsonType& nlohmann_json_j, const Type& nlohmann_json_t) { nlohmann::to_json(nlohmann_json_j, static_cast<const BaseType &>(nlohmann_json_t)); NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) }) \
|
||||
NLOHMANN_JSON_FROM_TYPE_TEMPLATE(void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { ::nlohmann::detail::from_json_base(nlohmann_json_j, static_cast<BaseType&>(nlohmann_json_t)); const Type nlohmann_json_default_obj{}; NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM_WITH_DEFAULT, __VA_ARGS__)) })
|
||||
NLOHMANN_JSON_BASIC_TYPE_TEMPLATE(void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { nlohmann::from_json(nlohmann_json_j, static_cast<BaseType&>(nlohmann_json_t)); const Type nlohmann_json_default_obj{}; NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM_WITH_DEFAULT, __VA_ARGS__)) })
|
||||
|
||||
// identical to NLOHMANN_JSON_DEFINE_DERIVED_TYPE_NON_INTRUSIVE_EMPTY: with no members there is nothing to default
|
||||
#define NLOHMANN_JSON_DEFINE_DERIVED_TYPE_NON_INTRUSIVE_WITH_DEFAULT_EMPTY(Type, BaseType) NLOHMANN_JSON_DEFINE_DERIVED_TYPE_NON_INTRUSIVE_EMPTY(Type, BaseType)
|
||||
@@ -863,7 +857,7 @@
|
||||
|
||||
#define NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE_WITH_DEFAULT_WITH_NAMES(Type, BaseType, ...) \
|
||||
NLOHMANN_JSON_BASIC_TYPE_TEMPLATE(void to_json(BasicJsonType& nlohmann_json_j, const Type& nlohmann_json_t) { nlohmann::to_json(nlohmann_json_j, static_cast<const BaseType &>(nlohmann_json_t)); NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_DOUBLE_PASTE(NLOHMANN_JSON_TO_WITH_NAME, __VA_ARGS__)) }) \
|
||||
NLOHMANN_JSON_FROM_TYPE_TEMPLATE(void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { ::nlohmann::detail::from_json_base(nlohmann_json_j, static_cast<BaseType&>(nlohmann_json_t)); const Type nlohmann_json_default_obj{}; NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_DOUBLE_PASTE(NLOHMANN_JSON_FROM_WITH_DEFAULT_WITH_NAME, __VA_ARGS__)) })
|
||||
NLOHMANN_JSON_BASIC_TYPE_TEMPLATE(void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { nlohmann::from_json(nlohmann_json_j, static_cast<BaseType&>(nlohmann_json_t)); const Type nlohmann_json_default_obj{}; NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_DOUBLE_PASTE(NLOHMANN_JSON_FROM_WITH_DEFAULT_WITH_NAME, __VA_ARGS__)) })
|
||||
|
||||
/*!
|
||||
@brief macro
|
||||
|
||||
@@ -340,47 +340,6 @@ template<class B> struct negation : std::integral_constant < bool, !B::value > {
|
||||
|
||||
#endif
|
||||
|
||||
///////////////////////
|
||||
// json_view helpers //
|
||||
///////////////////////
|
||||
|
||||
template<typename T>
|
||||
using basic_json_type_t = typename T::basic_json_type;
|
||||
|
||||
template<typename T>
|
||||
using materialize_function_t = decltype(std::declval<const T&>().materialize());
|
||||
|
||||
// a basic_json_view of <nlohmann/json_view.hpp> (detected by its member type
|
||||
// basic_json_type, a basic_json, and materialize() returning that type, so that
|
||||
// json.hpp needs no declaration of the view)
|
||||
template<typename T, typename = void>
|
||||
struct is_json_view : std::false_type {};
|
||||
|
||||
template<typename T>
|
||||
struct is_json_view<T, enable_if_t<is_basic_json<detected_t<basic_json_type_t, T>>::value>>
|
||||
: std::is_same<detected_t<materialize_function_t, T>, basic_json_type_t<T>> {};
|
||||
|
||||
// the types from_json() functions of the NLOHMANN_DEFINE_TYPE_* and
|
||||
// NLOHMANN_JSON_SERIALIZE_ENUM macros read from
|
||||
template<typename T>
|
||||
struct is_basic_json_or_view : disjunction<is_basic_json<T>, is_json_view<T>> {};
|
||||
|
||||
// the basic_json type of a basic_json value or of a view
|
||||
template<typename T, typename = void>
|
||||
struct json_type_of
|
||||
{
|
||||
using type = T;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct json_type_of<T, enable_if_t<is_json_view<T>::value>>
|
||||
{
|
||||
using type = typename T::basic_json_type;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
using json_type_of_t = typename json_type_of<T>::type;
|
||||
|
||||
// Reimplementation of is_constructible and is_default_constructible, due to them being broken for
|
||||
// std::pair and std::tuple until LWG 2367 fix (see https://cplusplus.github.io/LWG/lwg-defects.html#2367).
|
||||
// This causes compile errors in e.g., Clang 3.5 or GCC 4.9.
|
||||
|
||||
@@ -1684,15 +1684,7 @@ class binary_writer
|
||||
throw_subtype_out_of_range(value.subtype(), "the BSON binary subtype", j);
|
||||
}
|
||||
|
||||
// the "old binary" subtype 0x02 repeats the payload size in an inner
|
||||
// int32 in front of the payload
|
||||
return sizeof(std::int32_t) + (is_bson_old_binary(value) ? sizeof(std::int32_t) : 0ul) + value.size() + 1ul;
|
||||
}
|
||||
|
||||
/// @return whether @a value has the BSON subtype 0x02 ("binary (old)")
|
||||
static bool is_bson_old_binary(const binary_t& value) noexcept
|
||||
{
|
||||
return value.has_subtype() && value.subtype() == 0x02;
|
||||
return sizeof(std::int32_t) + value.size() + 1ul;
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -1705,18 +1697,10 @@ class binary_writer
|
||||
{
|
||||
write_bson_entry_header(name, 0x05);
|
||||
|
||||
const bool old_binary = is_bson_old_binary(value);
|
||||
|
||||
// the length field counts the inner int32 of the old binary subtype
|
||||
write_number<std::int32_t>(to_bson_length(value.size() + (old_binary ? sizeof(std::int32_t) : 0ul)), true);
|
||||
write_number<std::int32_t>(to_bson_length(value.size()), true);
|
||||
|
||||
write_number(value.has_subtype() ? static_cast<std::uint8_t>(value.subtype()) : static_cast<std::uint8_t>(0x00));
|
||||
|
||||
if (old_binary)
|
||||
{
|
||||
write_number<std::int32_t>(to_bson_length(value.size()), true);
|
||||
}
|
||||
|
||||
write_bytes(value.data(), value.size());
|
||||
}
|
||||
|
||||
@@ -1876,8 +1860,7 @@ class binary_writer
|
||||
(or the header of a string or binary value) in one reservation
|
||||
@return whether the entry was written; false for a discarded value, a
|
||||
string or binary value whose length does not fit the length
|
||||
field, or a binary value with subtype 0x02, in which case nothing
|
||||
was written
|
||||
field, in which case nothing was written
|
||||
@pre @a name is at most bson_scalar_max_name_size characters long and is
|
||||
not changed by the error handler
|
||||
*/
|
||||
@@ -1938,9 +1921,7 @@ class binary_writer
|
||||
if (j.is_binary())
|
||||
{
|
||||
const binary_t& value = *j.m_data.m_value.binary;
|
||||
// the old binary subtype 0x02 has an inner length that the single
|
||||
// reservation has no room for; write_bson_binary writes it
|
||||
if (JSON_HEDLEY_UNLIKELY(!value_in_range_of<std::int32_t>(value.size()) || is_bson_old_binary(value)))
|
||||
if (JSON_HEDLEY_UNLIKELY(!value_in_range_of<std::int32_t>(value.size())))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -3848,7 +3829,7 @@ class binary_writer
|
||||
A C++11 `constexpr` function cannot contain a `switch`, so this is a plain
|
||||
comparison chain instead; it is only reached once per ND-array candidate
|
||||
object. Keep in sync with binary_reader's `bjd_type_name()`, which maps
|
||||
the other way (it also reads "half", which is never written).
|
||||
the other way.
|
||||
*/
|
||||
static CharType bjdata_ndarray_type_marker(const string_t& name)
|
||||
{
|
||||
@@ -4056,13 +4037,10 @@ class binary_writer
|
||||
switch (dtype)
|
||||
{
|
||||
case 'U':
|
||||
case 'C':
|
||||
case 'B':
|
||||
ok = write_bjdata_ndarray_element<std::uint8_t>(el, dry_run);
|
||||
break;
|
||||
case 'C':
|
||||
// BJData limits a char to 0..127 (the intersection of the int8 and uint8 ranges)
|
||||
ok = bjdata_ndarray_value_in_range<std::int8_t>(el) && bjdata_ndarray_value_in_range<std::uint8_t>(el);
|
||||
break;
|
||||
case 'i':
|
||||
ok = write_bjdata_ndarray_element<std::int8_t>(el, dry_run);
|
||||
break;
|
||||
|
||||
@@ -639,11 +639,11 @@ run_found:
|
||||
switch (cur())
|
||||
{
|
||||
case '{':
|
||||
open(node_kind::object);
|
||||
open(value_t::object);
|
||||
++p;
|
||||
goto obj_first;
|
||||
case '[':
|
||||
open(node_kind::array);
|
||||
open(value_t::array);
|
||||
++p;
|
||||
goto arr_first;
|
||||
default:
|
||||
@@ -665,11 +665,11 @@ run_found:
|
||||
if (NLOHMANN_VIEW_UNLIKELY(!string<true>())) { return false; } \
|
||||
break; \
|
||||
case '{': \
|
||||
open(node_kind::object); \
|
||||
open(value_t::object); \
|
||||
++p; \
|
||||
goto obj_first; \
|
||||
case '[': \
|
||||
open(node_kind::array); \
|
||||
open(value_t::array); \
|
||||
++p; \
|
||||
goto arr_first; \
|
||||
case '-': \
|
||||
@@ -886,17 +886,17 @@ root_done:
|
||||
|
||||
NLOHMANN_VIEW_ALWAYS_INLINE bool literal_true()
|
||||
{
|
||||
return literal("true", node_kind::boolean, node_flags::is_true);
|
||||
return literal("true", value_t::boolean, node_flags::is_true);
|
||||
}
|
||||
|
||||
NLOHMANN_VIEW_ALWAYS_INLINE bool literal_false()
|
||||
{
|
||||
return literal("false", node_kind::boolean, 0);
|
||||
return literal("false", value_t::boolean, 0);
|
||||
}
|
||||
|
||||
NLOHMANN_VIEW_ALWAYS_INLINE bool literal_null()
|
||||
{
|
||||
return literal("null", node_kind::null, 0);
|
||||
return literal("null", value_t::null, 0);
|
||||
}
|
||||
|
||||
/// skip whitespace (and comments); false on a malformed comment
|
||||
@@ -962,7 +962,7 @@ indent_done:
|
||||
|
||||
/// append a node: (kind, flags, extra, off) and the second word (len, or
|
||||
/// an integer's value); two stores on little-endian targets
|
||||
NLOHMANN_VIEW_ALWAYS_INLINE node* push_node(node_kind k, std::uint8_t flags, std::uint16_t extra, std::size_t off, std::uint64_t second)
|
||||
NLOHMANN_VIEW_ALWAYS_INLINE node* push_node(value_t k, std::uint8_t flags, std::uint16_t extra, std::size_t off, std::uint64_t second)
|
||||
{
|
||||
if (NLOHMANN_VIEW_UNLIKELY(out == cap))
|
||||
{
|
||||
@@ -978,7 +978,7 @@ indent_done:
|
||||
std::memcpy(reinterpret_cast<unsigned char*>(n), &first, 8);
|
||||
std::memcpy(reinterpret_cast<unsigned char*>(n) + 8, &second, 8);
|
||||
#else
|
||||
n->kind = k;
|
||||
n->kind = static_cast<std::uint8_t>(k);
|
||||
n->flags = flags;
|
||||
n->extra = extra;
|
||||
n->off = static_cast<std::uint32_t>(off);
|
||||
@@ -990,7 +990,7 @@ indent_done:
|
||||
return n;
|
||||
}
|
||||
|
||||
NLOHMANN_VIEW_ALWAYS_INLINE void open(node_kind k)
|
||||
NLOHMANN_VIEW_ALWAYS_INLINE void open(value_t k)
|
||||
{
|
||||
// (base is read after push_node(), which moves the node array when it
|
||||
// grows; in one expression the order of the two is unspecified)
|
||||
@@ -1017,7 +1017,7 @@ indent_done:
|
||||
max_depth = (std::max)(max_depth, depth);
|
||||
cur_idx = idx;
|
||||
cur_count = 0;
|
||||
cur_is_object = k == node_kind::object;
|
||||
cur_is_object = k == value_t::object;
|
||||
}
|
||||
|
||||
NLOHMANN_VIEW_ALWAYS_INLINE void close()
|
||||
@@ -1047,7 +1047,7 @@ indent_done:
|
||||
|
||||
/// the literal `text` at p (N counts the terminating NUL)
|
||||
template<std::size_t N>
|
||||
NLOHMANN_VIEW_ALWAYS_INLINE bool literal(const char (&text)[N], node_kind k, std::uint8_t flags) // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays): a string literal
|
||||
NLOHMANN_VIEW_ALWAYS_INLINE bool literal(const char (&text)[N], value_t k, std::uint8_t flags) // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays): a string literal
|
||||
{
|
||||
const std::size_t n = N - 1;
|
||||
if (NLOHMANN_VIEW_UNLIKELY(e - p < static_cast<std::ptrdiff_t>(n) || std::memcmp(p, text, n) != 0))
|
||||
@@ -1126,23 +1126,23 @@ indent_done:
|
||||
is_float = true;
|
||||
}
|
||||
|
||||
node_kind kind = node_kind::number_float;
|
||||
value_t kind = value_t::number_float;
|
||||
if (!is_float)
|
||||
{
|
||||
// integers that do not fit become floats, as in parse()
|
||||
if (negative)
|
||||
{
|
||||
kind = digits_exceed(int_start, int_digits, "9223372036854775808") ? node_kind::number_float : node_kind::number_integer;
|
||||
kind = digits_exceed(int_start, int_digits, "9223372036854775808") ? value_t::number_float : value_t::number_integer;
|
||||
}
|
||||
else
|
||||
{
|
||||
kind = digits_exceed(int_start, int_digits, "18446744073709551615") ? node_kind::number_float : node_kind::number_unsigned;
|
||||
kind = digits_exceed(int_start, int_digits, "18446744073709551615") ? value_t::number_float : value_t::number_unsigned;
|
||||
}
|
||||
}
|
||||
// parse() rejects floats that overflow; only numbers whose magnitude
|
||||
// could reach the largest FloatType (1e308 for double, 1e38 for
|
||||
// float) need the conversion
|
||||
if (NLOHMANN_VIEW_UNLIKELY(static_cast<std::int64_t>(int_digits) + exponent > std::numeric_limits<FloatType>::max_exponent10 - 8 && kind == node_kind::number_float))
|
||||
if (NLOHMANN_VIEW_UNLIKELY(static_cast<std::int64_t>(int_digits) + exponent > std::numeric_limits<FloatType>::max_exponent10 - 8 && kind == value_t::number_float))
|
||||
{
|
||||
if (builder::float_overflows(s, p))
|
||||
{
|
||||
@@ -1152,7 +1152,7 @@ indent_done:
|
||||
}
|
||||
const auto layout = static_cast<std::uint16_t>((int_digits < 255 ? int_digits : 255) | ((frac_digits < 255 ? frac_digits : 255) << 8));
|
||||
auto second = static_cast<std::uint64_t>(p - s);
|
||||
if (kind != node_kind::number_float)
|
||||
if (kind != value_t::number_float)
|
||||
{
|
||||
// integers are converted now, while their digits are in cache
|
||||
const std::uint64_t m = int_digits <= 19 ? parse_upto19(int_start, static_cast<unsigned>(int_digits), e)
|
||||
@@ -1175,7 +1175,7 @@ indent_done:
|
||||
p = scan_string_run<Value>(p, e);
|
||||
if (NLOHMANN_VIEW_LIKELY(cur() == '"'))
|
||||
{
|
||||
push_node(node_kind::string, 0, 0, static_cast<std::size_t>(s - b), static_cast<std::uint64_t>(p - s));
|
||||
push_node(value_t::string, 0, 0, static_cast<std::size_t>(s - b), static_cast<std::uint64_t>(p - s));
|
||||
++p;
|
||||
return true;
|
||||
}
|
||||
@@ -1185,7 +1185,7 @@ indent_done:
|
||||
return false;
|
||||
}
|
||||
p = r.p;
|
||||
push_node(node_kind::string, node_flags::escaped, 0, r.start, r.len);
|
||||
push_node(value_t::string, node_flags::escaped, 0, r.start, r.len);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -232,7 +232,7 @@ struct document_data
|
||||
/// following loads.
|
||||
static NLOHMANN_VIEW_ALWAYS_INLINE const node* deref(const node* n) noexcept
|
||||
{
|
||||
return NLOHMANN_VIEW_LIKELY(n->kind != node_kind::link) ? n : follow_link(n);
|
||||
return NLOHMANN_VIEW_LIKELY(n->kind != kind_link) ? n : follow_link(n);
|
||||
}
|
||||
|
||||
static NLOHMANN_VIEW_NOINLINE const node* follow_link(const node* n) noexcept
|
||||
|
||||
@@ -26,10 +26,12 @@
|
||||
#include <nlohmann/detail/view/lookup.hpp>
|
||||
#include <nlohmann/detail/view/macro_scope.hpp>
|
||||
#include <nlohmann/detail/view/node.hpp>
|
||||
#include <nlohmann/detail/view/view_mode.hpp>
|
||||
|
||||
NLOHMANN_JSON_NAMESPACE_BEGIN
|
||||
|
||||
template<typename BasicJsonType, bool Editable>
|
||||
class basic_json_view;
|
||||
|
||||
namespace detail
|
||||
{
|
||||
namespace view
|
||||
@@ -118,15 +120,15 @@ class editor
|
||||
View set(const View& object, string_view_t key, V&& value)
|
||||
{
|
||||
node* const o = own(object);
|
||||
if (o->kind != node_kind::object && o->kind != node_kind::null)
|
||||
if (o->kind != static_cast<std::uint8_t>(value_t::object) && o->kind != static_cast<std::uint8_t>(value_t::null))
|
||||
{
|
||||
throw_type_error(exception_id::subscript_wrong_type, "cannot use operator[] with a string argument with ", object.type_name());
|
||||
}
|
||||
check_utf8(key.data(), key.size());
|
||||
const encoded e = encode(std::forward<V>(value));
|
||||
if (o->kind == node_kind::null)
|
||||
if (o->kind == static_cast<std::uint8_t>(value_t::null))
|
||||
{
|
||||
become_empty(o, node_kind::object);
|
||||
become_empty(o, value_t::object);
|
||||
}
|
||||
// an existing member: assign it (and drop later duplicates, so that
|
||||
// lookups, iteration, and materialize() agree)
|
||||
@@ -169,7 +171,7 @@ class editor
|
||||
View set(const View& array, std::size_t idx, V&& value)
|
||||
{
|
||||
node* const a = own(array);
|
||||
if (a->kind != node_kind::array)
|
||||
if (a->kind != static_cast<std::uint8_t>(value_t::array))
|
||||
{
|
||||
throw_type_error(exception_id::subscript_wrong_type, "cannot use operator[] with a numeric argument with ", array.type_name());
|
||||
}
|
||||
@@ -186,14 +188,14 @@ class editor
|
||||
View push_back(const View& array, V&& value)
|
||||
{
|
||||
node* const a = own(array);
|
||||
if (a->kind != node_kind::array && a->kind != node_kind::null)
|
||||
if (a->kind != static_cast<std::uint8_t>(value_t::array) && a->kind != static_cast<std::uint8_t>(value_t::null))
|
||||
{
|
||||
throw_type_error(exception_id::push_back_wrong_type, "cannot use push_back() with ", array.type_name());
|
||||
}
|
||||
const encoded e = encode(std::forward<V>(value));
|
||||
if (a->kind == node_kind::null)
|
||||
if (a->kind == static_cast<std::uint8_t>(value_t::null))
|
||||
{
|
||||
become_empty(a, node_kind::array);
|
||||
become_empty(a, value_t::array);
|
||||
}
|
||||
node* const slot = new_slot(e);
|
||||
node* const h = block_of(m_doc, a, 1);
|
||||
@@ -210,7 +212,7 @@ class editor
|
||||
View insert(const View& array, std::size_t idx, V&& value)
|
||||
{
|
||||
node* const a = own(array);
|
||||
if (a->kind != node_kind::array)
|
||||
if (a->kind != static_cast<std::uint8_t>(value_t::array))
|
||||
{
|
||||
throw_type_error(exception_id::insert_wrong_type, "cannot use insert() with ", array.type_name());
|
||||
}
|
||||
@@ -230,7 +232,7 @@ class editor
|
||||
std::size_t erase(const View& object, string_view_t key)
|
||||
{
|
||||
node* const o = own(object);
|
||||
if (o->kind != node_kind::object)
|
||||
if (o->kind != static_cast<std::uint8_t>(value_t::object))
|
||||
{
|
||||
throw_type_error(exception_id::erase_wrong_type, "cannot use erase() with ", object.type_name());
|
||||
}
|
||||
@@ -248,7 +250,7 @@ class editor
|
||||
void erase(const View& array, std::size_t idx)
|
||||
{
|
||||
node* const a = own(array);
|
||||
if (a->kind != node_kind::array)
|
||||
if (a->kind != static_cast<std::uint8_t>(value_t::array))
|
||||
{
|
||||
throw_type_error(exception_id::erase_wrong_type, "cannot use erase() with ", array.type_name());
|
||||
}
|
||||
@@ -322,11 +324,11 @@ class editor
|
||||
}
|
||||
|
||||
/// turn a null into an empty array/object in place
|
||||
static void become_empty(node* n, node_kind k) noexcept
|
||||
static void become_empty(node* n, value_t k) noexcept
|
||||
{
|
||||
const std::uint8_t linked = n->flags & node_flags::linked;
|
||||
*n = node{};
|
||||
n->kind = k;
|
||||
n->kind = static_cast<std::uint8_t>(k);
|
||||
n->flags = static_cast<std::uint8_t>(node_flags::is_new | linked);
|
||||
n->next = 1;
|
||||
}
|
||||
@@ -403,8 +405,8 @@ class editor
|
||||
template<typename T>
|
||||
struct is_view : std::false_type {};
|
||||
|
||||
template<typename J, view_mode M>
|
||||
struct is_view<basic_json_view<J, M>> : std::true_type {};
|
||||
template<typename J, bool E>
|
||||
struct is_view<basic_json_view<J, E>> : std::true_type {};
|
||||
|
||||
template<typename V>
|
||||
encoded encode(V&& v)
|
||||
@@ -419,8 +421,8 @@ class editor
|
||||
}
|
||||
|
||||
/// a view of any document (copied; nothing is shared with it)
|
||||
template<typename J, view_mode M>
|
||||
encoded encode_impl(const basic_json_view<J, M>& v, encode_tag<0> /*view*/)
|
||||
template<typename J, bool E>
|
||||
encoded encode_impl(const basic_json_view<J, E>& v, encode_tag<0> /*view*/)
|
||||
{
|
||||
if (NLOHMANN_VIEW_UNLIKELY(v.m_node == nullptr))
|
||||
{
|
||||
@@ -432,8 +434,8 @@ class editor
|
||||
r.scalar = copy_scalar(*v.m_doc, *v.m_node);
|
||||
return r;
|
||||
}
|
||||
r.region = alloc_nodes(m_doc, count_nodes<M == view_mode::editable>(*v.m_doc, v.m_node));
|
||||
fill_nodes<M == view_mode::editable>(*v.m_doc, v.m_node, r.region);
|
||||
r.region = alloc_nodes(m_doc, count_nodes<E>(*v.m_doc, v.m_node));
|
||||
fill_nodes<E>(*v.m_doc, v.m_node, r.region);
|
||||
edit_state_of(m_doc).regions.emplace(r.region, nullptr);
|
||||
return r;
|
||||
}
|
||||
@@ -455,14 +457,14 @@ class editor
|
||||
encoded encode_impl(std::nullptr_t /*unused*/, encode_tag<2> /*null*/)
|
||||
{
|
||||
encoded r;
|
||||
r.scalar = plain_node(node_kind::null);
|
||||
r.scalar = plain_node(value_t::null);
|
||||
return r;
|
||||
}
|
||||
|
||||
encoded encode_impl(bool b, encode_tag<3> /*boolean*/)
|
||||
{
|
||||
encoded r;
|
||||
r.scalar = plain_node(node_kind::boolean);
|
||||
r.scalar = plain_node(value_t::boolean);
|
||||
r.scalar.flags = static_cast<std::uint8_t>(r.scalar.flags | (b ? node_flags::is_true : 0));
|
||||
return r;
|
||||
}
|
||||
@@ -491,10 +493,10 @@ class editor
|
||||
return encode_impl(BasicJsonType(std::forward<T>(x)), encode_tag<1> {});
|
||||
}
|
||||
|
||||
static node plain_node(node_kind k) noexcept
|
||||
static node plain_node(value_t k) noexcept
|
||||
{
|
||||
node n{};
|
||||
n.kind = k;
|
||||
n.kind = static_cast<std::uint8_t>(k);
|
||||
n.flags = node_flags::is_new;
|
||||
return n;
|
||||
}
|
||||
@@ -508,19 +510,19 @@ class editor
|
||||
template<typename T>
|
||||
node number_node(T x, std::integral_constant<int, 1> /*signed*/)
|
||||
{
|
||||
return integer_node(static_cast<std::uint64_t>(static_cast<std::int64_t>(x)), node_kind::number_integer);
|
||||
return integer_node(static_cast<std::uint64_t>(static_cast<std::int64_t>(x)), value_t::number_integer);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
node number_node(T x, std::integral_constant<int, 2> /*unsigned*/)
|
||||
{
|
||||
return integer_node(static_cast<std::uint64_t>(x), node_kind::number_unsigned);
|
||||
return integer_node(static_cast<std::uint64_t>(x), value_t::number_unsigned);
|
||||
}
|
||||
|
||||
/// an integer with its canonical token in the edit arena
|
||||
node integer_node(std::uint64_t bits, node_kind k)
|
||||
node integer_node(std::uint64_t bits, value_t k)
|
||||
{
|
||||
const bool negative = k == node_kind::number_integer && static_cast<std::int64_t>(bits) < 0;
|
||||
const bool negative = k == value_t::number_integer && static_cast<std::int64_t>(bits) < 0;
|
||||
std::uint64_t magnitude = negative ? 0 - bits : bits;
|
||||
std::array<char, 24> buf{};
|
||||
char* p = buf.data() + buf.size(); // NOLINT(misc-const-correctness): digits are written through p
|
||||
@@ -539,7 +541,7 @@ class editor
|
||||
n.flags = static_cast<std::uint8_t>(n.flags | node_flags::edited);
|
||||
n.off = append_text(m_doc, p, len);
|
||||
// number_length() adds one for the sign of number_integer nodes
|
||||
n.extra = static_cast<std::uint16_t>(k == node_kind::number_integer ? len - 1 : len);
|
||||
n.extra = static_cast<std::uint16_t>(k == value_t::number_integer ? len - 1 : len);
|
||||
set_integer_bits(n, bits);
|
||||
return n;
|
||||
}
|
||||
@@ -561,7 +563,7 @@ class editor
|
||||
{
|
||||
text = BasicJsonType(x).dump();
|
||||
}
|
||||
node n = plain_node(node_kind::number_float);
|
||||
node n = plain_node(value_t::number_float);
|
||||
n.flags = static_cast<std::uint8_t>(n.flags | node_flags::edited);
|
||||
n.extra = 0xFFFFu; // (the digit layout is not recorded)
|
||||
n.off = append_text(m_doc, text.data(), text.size());
|
||||
@@ -576,7 +578,7 @@ class editor
|
||||
{
|
||||
throw_out_of_range(exception_id::document_too_large, "strings of 4 GiB or more are not supported by json_document"); // LCOV_EXCL_LINE
|
||||
}
|
||||
node n = plain_node(node_kind::string);
|
||||
node n = plain_node(value_t::string);
|
||||
n.flags = static_cast<std::uint8_t>(n.flags | node_flags::edited);
|
||||
n.off = append_text(m_doc, s, len);
|
||||
n.len = static_cast<std::uint32_t>(len);
|
||||
@@ -598,10 +600,10 @@ class editor
|
||||
return string_node(from.str(n), n.len);
|
||||
case value_t::number_integer:
|
||||
case value_t::number_unsigned:
|
||||
return integer_node(integer_bits(n), n.kind);
|
||||
return integer_node(integer_bits(n), static_cast<value_t>(n.kind));
|
||||
case value_t::number_float:
|
||||
{
|
||||
node r = plain_node(node_kind::number_float);
|
||||
node r = plain_node(value_t::number_float);
|
||||
r.flags = static_cast<std::uint8_t>(r.flags | node_flags::edited);
|
||||
r.off = append_text(m_doc, from.str(n), n.len);
|
||||
r.len = n.len;
|
||||
@@ -610,7 +612,7 @@ class editor
|
||||
}
|
||||
case value_t::boolean:
|
||||
{
|
||||
node r = plain_node(node_kind::boolean);
|
||||
node r = plain_node(value_t::boolean);
|
||||
r.flags = static_cast<std::uint8_t>(r.flags | (n.flags & node_flags::is_true));
|
||||
return r;
|
||||
}
|
||||
@@ -620,7 +622,7 @@ class editor
|
||||
case value_t::binary:
|
||||
case value_t::discarded:
|
||||
default:
|
||||
return plain_node(node_kind::null);
|
||||
return plain_node(value_t::null);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -629,17 +631,17 @@ class editor
|
||||
switch (j.type())
|
||||
{
|
||||
case value_t::null:
|
||||
return plain_node(node_kind::null);
|
||||
return plain_node(value_t::null);
|
||||
case value_t::boolean:
|
||||
{
|
||||
node r = plain_node(node_kind::boolean);
|
||||
node r = plain_node(value_t::boolean);
|
||||
r.flags = static_cast<std::uint8_t>(r.flags | (j.template get<bool>() ? node_flags::is_true : 0));
|
||||
return r;
|
||||
}
|
||||
case value_t::number_integer:
|
||||
return integer_node(static_cast<std::uint64_t>(static_cast<std::int64_t>(j.template get<number_integer_t>())), node_kind::number_integer);
|
||||
return integer_node(static_cast<std::uint64_t>(static_cast<std::int64_t>(j.template get<number_integer_t>())), value_t::number_integer);
|
||||
case value_t::number_unsigned:
|
||||
return integer_node(static_cast<std::uint64_t>(j.template get<number_unsigned_t>()), node_kind::number_unsigned);
|
||||
return integer_node(static_cast<std::uint64_t>(j.template get<number_unsigned_t>()), value_t::number_unsigned);
|
||||
case value_t::number_float:
|
||||
return float_node(j.template get<number_float_t>());
|
||||
case value_t::string:
|
||||
@@ -679,7 +681,7 @@ class editor
|
||||
++r;
|
||||
if (is_container(*n))
|
||||
{
|
||||
open.push_back(frame{walk::first(d, n), walk::end(d, n), n->kind == node_kind::object});
|
||||
open.push_back(frame{walk::first(d, n), walk::end(d, n), n->kind == static_cast<std::uint8_t>(value_t::object)});
|
||||
}
|
||||
// the next value: close finished containers, then step over the key
|
||||
for (;;)
|
||||
@@ -726,9 +728,9 @@ class editor
|
||||
if (is_container(*n))
|
||||
{
|
||||
node* const self = out++;
|
||||
*self = plain_node(n->kind);
|
||||
*self = plain_node(static_cast<value_t>(n->kind));
|
||||
self->len = n->len;
|
||||
open.push_back(frame{walk::first(d, n), walk::end(d, n), n->kind == node_kind::object, self});
|
||||
open.push_back(frame{walk::first(d, n), walk::end(d, n), n->kind == static_cast<std::uint8_t>(value_t::object), self});
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -817,7 +819,7 @@ class editor
|
||||
if (n->is_structured())
|
||||
{
|
||||
node* const self = out++;
|
||||
*self = plain_node(static_cast<node_kind>(n->type()));
|
||||
*self = plain_node(n->type());
|
||||
self->len = static_cast<std::uint32_t>(n->size());
|
||||
open.push_back(frame{n->cbegin(), n->cend(), n->is_object(), self});
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
// live in chunks that never move; strings and number tokens written by edits
|
||||
// live in the edit arena. An array/object whose elements change gets
|
||||
// node_flags::moved: its elements then live in a separate sequence (a header
|
||||
// node, then the entries), whose entries link to the values (node_kind::link).
|
||||
// node, then the entries), whose entries link to the values (kind_link).
|
||||
|
||||
NLOHMANN_JSON_NAMESPACE_BEGIN
|
||||
namespace detail
|
||||
@@ -185,7 +185,7 @@ inline node* block_of(document_data& d, node* n, std::size_t extra)
|
||||
return nh;
|
||||
}
|
||||
reserve_moved(d); // (so that set_moved() below cannot throw: the links are marked before)
|
||||
const bool object = n->kind == node_kind::object;
|
||||
const bool object = n->kind == static_cast<std::uint8_t>(value_t::object);
|
||||
const std::size_t used = 1 + (static_cast<std::size_t>(n->len) * (object ? 2 : 1));
|
||||
const std::size_t cap = used + extra;
|
||||
node* const h = alloc_nodes(d, cap);
|
||||
@@ -251,7 +251,7 @@ inline node* find_parent(const document_data& d, const node* target)
|
||||
{
|
||||
return nullptr; // LCOV_EXCL_LINE (the value is inside c)
|
||||
}
|
||||
const bool object = c->kind == node_kind::object;
|
||||
const bool object = c->kind == static_cast<std::uint8_t>(value_t::object);
|
||||
const node* down = nullptr;
|
||||
for (const node* p = d.first_child_edited(c), *e = d.child_end_edited(c); p != e;)
|
||||
{
|
||||
|
||||
@@ -117,7 +117,7 @@ inline void compact_nodes(const document_data& d, std::size_t arena_size, std::v
|
||||
r.off = (v->flags & (node_flags::moved | node_flags::is_new)) != 0 ? 0 : v->off;
|
||||
r.len = 0; // counted below
|
||||
r.next = 0; // set when the container is complete
|
||||
stack.push_back(frame{d.first_child_edited(v), d.child_end_edited(v), out.size(), 0, v->kind == node_kind::object});
|
||||
stack.push_back(frame{d.first_child_edited(v), d.child_end_edited(v), out.size(), 0, v->kind == static_cast<std::uint8_t>(value_t::object)});
|
||||
break;
|
||||
case value_t::string:
|
||||
r = string_node(*v);
|
||||
@@ -138,7 +138,7 @@ inline void compact_nodes(const document_data& d, std::size_t arena_size, std::v
|
||||
if (t[0] == 'n' || t[0] == 'i' || (v->len > 1 && t[1] == 'i'))
|
||||
{
|
||||
r = node{}; // nan and infinity: null, as dump() writes them
|
||||
r.kind = node_kind::null;
|
||||
r.kind = static_cast<std::uint8_t>(value_t::null);
|
||||
break;
|
||||
}
|
||||
r.off = static_cast<std::uint32_t>(d.size + text_tail.size());
|
||||
@@ -182,10 +182,12 @@ inline void compact_nodes(const document_data& d, std::size_t arena_size, std::v
|
||||
}
|
||||
}
|
||||
|
||||
#if NLOHMANN_VIEW_LITTLE_ENDIAN // (the image format is little-endian: no save() elsewhere)
|
||||
/// the document as an image
|
||||
inline std::vector<std::uint8_t> save_image(const document_data& d)
|
||||
{
|
||||
#if !NLOHMANN_VIEW_LITTLE_ENDIAN
|
||||
throw_type_error(exception_id::document_image_unsupported, "json_document images need a little-endian target"); // LCOV_EXCL_LINE
|
||||
#endif
|
||||
const std::size_t arena_size = d.arena_size;
|
||||
std::vector<node> compacted;
|
||||
std::string text_tail;
|
||||
@@ -219,7 +221,7 @@ inline std::vector<std::uint8_t> save_image(const document_data& d)
|
||||
// extra of an object, and the same document saves to the same bytes
|
||||
for (std::size_t i = 0; i < count; ++i)
|
||||
{
|
||||
if (nodes[i].kind == node_kind::object && nodes[i].extra != 0)
|
||||
if (nodes[i].kind == static_cast<std::uint8_t>(value_t::object) && nodes[i].extra != 0)
|
||||
{
|
||||
std::memset(o + (i * sizeof(node)) + offsetof(node, extra), 0, sizeof(nodes[i].extra));
|
||||
}
|
||||
@@ -241,7 +243,6 @@ inline std::vector<std::uint8_t> save_image(const document_data& d)
|
||||
*o = 0;
|
||||
return image;
|
||||
}
|
||||
#endif
|
||||
|
||||
/// the parts of a number token that the checks need
|
||||
struct number_token
|
||||
@@ -336,7 +337,7 @@ inline bool float_token_finite(const unsigned char* s, std::size_t len, const nu
|
||||
if (static_cast<std::int64_t>(t.int_digits) + t.exponent > 300)
|
||||
{
|
||||
node n{};
|
||||
n.kind = node_kind::number_float;
|
||||
n.kind = static_cast<std::uint8_t>(value_t::number_float);
|
||||
n.len = static_cast<std::uint32_t>(len);
|
||||
const auto v = float_value<double>(reinterpret_cast<const char*>(s), n); // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast)
|
||||
return v <= (std::numeric_limits<double>::max)() && v >= -(std::numeric_limits<double>::max)();
|
||||
@@ -357,7 +358,7 @@ inline bool check_integer(const node& n, const unsigned char* text)
|
||||
}
|
||||
// the token's value is the stored one; number_integer nodes of edits can
|
||||
// be non-negative (as basic_json keeps the type of a value)
|
||||
const bool integer = n.kind == node_kind::number_integer;
|
||||
const bool integer = n.kind == static_cast<std::uint8_t>(value_t::number_integer);
|
||||
if (t.is_float || t.int_digits > 20 || (t.negative && !integer))
|
||||
{
|
||||
return false;
|
||||
@@ -539,7 +540,7 @@ inline bool check_image(const node* nodes, std::size_t count, const unsigned cha
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (n.kind != node_kind::number_float)
|
||||
if (n.kind != static_cast<std::uint8_t>(value_t::number_float))
|
||||
{
|
||||
return (n.extra >> 8u) == 0;
|
||||
}
|
||||
@@ -580,7 +581,7 @@ inline bool check_image(const node* nodes, std::size_t count, const unsigned cha
|
||||
const node& n = nodes[i];
|
||||
if (!stack.empty() && stack.back().object && stack.back().expect_key)
|
||||
{
|
||||
if (n.kind != node_kind::string || !check_string(n))
|
||||
if (n.kind != static_cast<std::uint8_t>(value_t::string) || !check_string(n))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -621,7 +622,7 @@ inline bool check_image(const node* nodes, std::size_t count, const unsigned cha
|
||||
{
|
||||
// (the contents of float tokens are checked later; the token of an
|
||||
// integer has at most 256 characters)
|
||||
if (n.kind == node_kind::number_float)
|
||||
if (n.kind == static_cast<std::uint8_t>(value_t::number_float))
|
||||
{
|
||||
floats.push_back(float_range{n.off, n.len, n.extra});
|
||||
}
|
||||
@@ -639,7 +640,7 @@ inline bool check_image(const node* nodes, std::size_t count, const unsigned cha
|
||||
{
|
||||
return false;
|
||||
}
|
||||
stack.push_back(frame{i + n.next, n.len, 0, n.kind == node_kind::object, true});
|
||||
stack.push_back(frame{i + n.next, n.len, 0, n.kind == static_cast<std::uint8_t>(value_t::object), true});
|
||||
complete = false;
|
||||
break;
|
||||
}
|
||||
@@ -662,11 +663,13 @@ inline bool check_image(const node* nodes, std::size_t count, const unsigned cha
|
||||
throw_parse_error(exception_id::invalid_document_image, concat("invalid json_document image: ", what));
|
||||
}
|
||||
|
||||
#if NLOHMANN_VIEW_LITTLE_ENDIAN // (the image format is little-endian: no load() elsewhere)
|
||||
/// Read an image into d. The text and the decoded strings stay in the image;
|
||||
/// the nodes are copied (so that they are aligned, and edits can change them).
|
||||
inline void load_image(document_data& d, const std::uint8_t* image, std::size_t size, image_check check)
|
||||
{
|
||||
#if !NLOHMANN_VIEW_LITTLE_ENDIAN
|
||||
throw_type_error(exception_id::document_image_unsupported, "json_document images need a little-endian target"); // LCOV_EXCL_LINE
|
||||
#endif
|
||||
if (image == nullptr || size < sizeof(image_header))
|
||||
{
|
||||
throw_invalid_image("too short");
|
||||
@@ -726,7 +729,7 @@ inline void load_image(document_data& d, const std::uint8_t* image, std::size_t
|
||||
for (std::size_t i = 0; i < count; ++i)
|
||||
{
|
||||
const node& n = d.nodes[i];
|
||||
if (n.kind == node_kind::object && n.len >= document_data::index_min_members)
|
||||
if (n.kind == static_cast<std::uint8_t>(value_t::object) && n.len >= document_data::index_min_members)
|
||||
{
|
||||
d.large_objects.push_back(static_cast<std::uint32_t>(i));
|
||||
}
|
||||
@@ -735,7 +738,6 @@ inline void load_image(document_data& d, const std::uint8_t* image, std::size_t
|
||||
std::vector<std::uint32_t>().swap(d.large_objects); // (only needed while building)
|
||||
d.discarded = false;
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace view
|
||||
} // namespace detail
|
||||
|
||||
@@ -182,7 +182,7 @@ const node* element_at(const document_data& d, const node* array, std::size_t id
|
||||
template<bool Editable>
|
||||
const node* last_child(const document_data& d, const node* container) noexcept
|
||||
{
|
||||
const std::size_t value_offset = container->kind == node_kind::object ? 1 : 0;
|
||||
const std::size_t value_offset = container->kind == static_cast<std::uint8_t>(value_t::object) ? 1 : 0;
|
||||
const node* const end = navigation<Editable>::end(d, container);
|
||||
const node* last = navigation<Editable>::first(d, container);
|
||||
if (value_offset == 0 && container->next == container->len + 1u && (!navigation<Editable>::editable() || (container->flags & node_flags::moved) == 0))
|
||||
|
||||
@@ -101,7 +101,7 @@ BasicJsonType materialize(const document_data& d, const node* n)
|
||||
case value_t::object:
|
||||
case value_t::array:
|
||||
{
|
||||
const bool object = n->kind == node_kind::object;
|
||||
const bool object = n->kind == static_cast<std::uint8_t>(value_t::object);
|
||||
if (object)
|
||||
{
|
||||
sax.start_object(n->len);
|
||||
|
||||
@@ -41,22 +41,9 @@ struct node_flags
|
||||
static constexpr std::uint8_t linked = 32; ///< an entry of a moved sequence links to this value (editable documents): its extent in the parsed layout no longer matters
|
||||
};
|
||||
|
||||
/// the kind of a node: the value_t of its value, or link
|
||||
enum class node_kind : std::uint8_t
|
||||
{
|
||||
null = static_cast<std::uint8_t>(value_t::null),
|
||||
object = static_cast<std::uint8_t>(value_t::object),
|
||||
array = static_cast<std::uint8_t>(value_t::array),
|
||||
string = static_cast<std::uint8_t>(value_t::string), // NOLINT(build/include_what_you_use): an enumerator, not std::string
|
||||
boolean = static_cast<std::uint8_t>(value_t::boolean),
|
||||
number_integer = static_cast<std::uint8_t>(value_t::number_integer),
|
||||
number_unsigned = static_cast<std::uint8_t>(value_t::number_unsigned),
|
||||
number_float = static_cast<std::uint8_t>(value_t::number_float),
|
||||
/// an entry of an edited sequence that stands for a value stored elsewhere
|
||||
/// (the address of the value's node is kept in the len/next bytes); placed
|
||||
/// after value_t::discarded, which no node ever has
|
||||
link = static_cast<std::uint8_t>(value_t::discarded) + 1,
|
||||
};
|
||||
/// kind of an entry of an edited sequence that stands for a value stored
|
||||
/// elsewhere (the address of the value's node is kept in the len/next bytes)
|
||||
constexpr std::uint8_t kind_link = 10;
|
||||
|
||||
/// One entry of the flat index, in document order. An object's members are
|
||||
/// stored as key node followed by the value's subtree. Integers keep their
|
||||
@@ -64,7 +51,7 @@ enum class node_kind : std::uint8_t
|
||||
/// always the next one, and the token length follows from `extra`).
|
||||
struct node
|
||||
{
|
||||
node_kind kind; ///< the kind of the value, or link
|
||||
std::uint8_t kind; ///< value_t, or kind_link
|
||||
std::uint8_t flags; ///< node_flags
|
||||
std::uint16_t extra; ///< numbers: integer digits (low byte) and fraction digits (high byte), 255 = "many"; objects: number of the object's key hash index (1-based, 0 = none); otherwise 0
|
||||
std::uint32_t off; ///< source offset (string content, number token, literal, bracket); arena offset if escaped/edited; number of the element sequence if moved
|
||||
@@ -73,13 +60,13 @@ struct node
|
||||
};
|
||||
static_assert(sizeof(node) == 16, "node must stay 16 bytes");
|
||||
|
||||
// images store the node kinds as bytes, and the test below (object and array
|
||||
// are 1 and 2) and those of the number kinds depend on this numbering
|
||||
static_assert(static_cast<std::uint8_t>(node_kind::null) == 0 && static_cast<std::uint8_t>(node_kind::object) == 1
|
||||
&& static_cast<std::uint8_t>(node_kind::array) == 2 && static_cast<std::uint8_t>(node_kind::string) == 3
|
||||
&& static_cast<std::uint8_t>(node_kind::boolean) == 4 && static_cast<std::uint8_t>(node_kind::number_integer) == 5
|
||||
&& static_cast<std::uint8_t>(node_kind::number_unsigned) == 6 && static_cast<std::uint8_t>(node_kind::number_float) == 7,
|
||||
"the node format depends on the numbering of node_kind");
|
||||
// the node kinds are value_t values; the test below (object and array are 1
|
||||
// and 2) and those of the number kinds depend on this numbering
|
||||
static_assert(static_cast<std::uint8_t>(value_t::null) == 0 && static_cast<std::uint8_t>(value_t::object) == 1
|
||||
&& static_cast<std::uint8_t>(value_t::array) == 2 && static_cast<std::uint8_t>(value_t::string) == 3
|
||||
&& static_cast<std::uint8_t>(value_t::boolean) == 4 && static_cast<std::uint8_t>(value_t::number_integer) == 5
|
||||
&& static_cast<std::uint8_t>(value_t::number_unsigned) == 6 && static_cast<std::uint8_t>(value_t::number_float) == 7,
|
||||
"the node format depends on the numbering of value_t");
|
||||
|
||||
NLOHMANN_VIEW_ALWAYS_INLINE bool is_container(const node& n) noexcept
|
||||
{
|
||||
@@ -99,7 +86,7 @@ inline void make_link(node& n, node* target) noexcept
|
||||
{
|
||||
target->flags = static_cast<std::uint8_t>(target->flags | node_flags::linked);
|
||||
n = node{};
|
||||
n.kind = node_kind::link;
|
||||
n.kind = kind_link;
|
||||
std::memcpy(reinterpret_cast<unsigned char*>(&n) + 8, static_cast<const void*>(&target), sizeof(const node*)); // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast)
|
||||
}
|
||||
|
||||
@@ -129,8 +116,8 @@ NLOHMANN_VIEW_ALWAYS_INLINE void set_integer_bits(node& n, std::uint64_t v) noex
|
||||
/// token length of a number node
|
||||
NLOHMANN_VIEW_ALWAYS_INLINE std::uint32_t number_length(const node& n) noexcept
|
||||
{
|
||||
return n.kind == node_kind::number_float ? n.len
|
||||
: (n.extra & 0xFFu) + (n.kind == node_kind::number_integer ? 1u : 0u);
|
||||
return n.kind == static_cast<std::uint8_t>(value_t::number_float) ? n.len
|
||||
: (n.extra & 0xFFu) + (n.kind == static_cast<std::uint8_t>(value_t::number_integer) ? 1u : 0u);
|
||||
}
|
||||
|
||||
/// estimated number of nodes for an input of `size` bytes (one node per ~12
|
||||
|
||||
@@ -874,7 +874,7 @@ class view_serializer
|
||||
case value_t::object:
|
||||
case value_t::array:
|
||||
{
|
||||
const bool object = n->kind == node_kind::object;
|
||||
const bool object = n->kind == static_cast<std::uint8_t>(value_t::object);
|
||||
room(8);
|
||||
if (n->len == 0)
|
||||
{
|
||||
|
||||
@@ -24,25 +24,25 @@
|
||||
// with different flags would have different definitions of the same inline
|
||||
// functions): the check is compiled for SSSE3 with a function attribute and
|
||||
// used where the CPU has SSSE3 (all x86-64 CPUs since about 2011), else the
|
||||
// portable check. Code compiled for SSSE3 anyway (-mssse3 or more) skips the
|
||||
// CPU check. JSON_NO_SIMD selects the portable code, as in the lexer.
|
||||
// portable check. JSON_VIEW_USE_SSSE3 skips the CPU check (for code compiled
|
||||
// for SSSE3 anyway); JSON_VIEW_NO_SIMD selects the portable code.
|
||||
// NLOHMANN_VIEW_NO_TARGET_ATTRIBUTE (set by the GCC module interface, where GCC
|
||||
// ignores the target attribute and then rejects the SSSE3 intrinsics) keeps the
|
||||
// check portable without disabling the SSE2 code.
|
||||
#if !defined(JSON_NO_SIMD) && defined(__aarch64__) && (defined(__GNUC__) || defined(__clang__)) && NLOHMANN_VIEW_LITTLE_ENDIAN
|
||||
#if !defined(JSON_VIEW_NO_SIMD) && defined(__aarch64__) && (defined(__GNUC__) || defined(__clang__)) && NLOHMANN_VIEW_LITTLE_ENDIAN
|
||||
#include <arm_neon.h>
|
||||
#define NLOHMANN_VIEW_NEON 1
|
||||
#else
|
||||
#define NLOHMANN_VIEW_NEON 0
|
||||
#endif
|
||||
// (x86 only: other targets can define __SSE2__ as well, e.g., WebAssembly with -msse2, but have no <cpuid.h>)
|
||||
#if !defined(JSON_NO_SIMD) && !NLOHMANN_VIEW_NEON && (defined(__x86_64__) || defined(__i386__) || defined(_M_X64) || defined(_M_IX86)) && (defined(__SSE2__) || defined(_M_X64) || (defined(_M_IX86_FP) && _M_IX86_FP >= 2))
|
||||
#if !defined(JSON_VIEW_NO_SIMD) && !NLOHMANN_VIEW_NEON && (defined(__x86_64__) || defined(__i386__) || defined(_M_X64) || defined(_M_IX86)) && (defined(__SSE2__) || defined(_M_X64) || (defined(_M_IX86_FP) && _M_IX86_FP >= 2))
|
||||
#include <emmintrin.h>
|
||||
#define NLOHMANN_VIEW_SSE2 1
|
||||
#else
|
||||
#define NLOHMANN_VIEW_SSE2 0
|
||||
#endif
|
||||
#if NLOHMANN_VIEW_SSE2 && defined(__SSSE3__)
|
||||
#if NLOHMANN_VIEW_SSE2 && defined(JSON_VIEW_USE_SSSE3)
|
||||
#include <tmmintrin.h>
|
||||
#define NLOHMANN_VIEW_SSSE3 1 // NOLINT(cppcoreguidelines-macro-to-enum,modernize-macro-to-enum)
|
||||
#else
|
||||
|
||||
@@ -130,16 +130,14 @@ struct is_direct_value : std::integral_constant < bool,
|
||||
template<typename Traits, typename Alloc, typename BasicJsonType, typename View>
|
||||
struct is_direct_value<std::basic_string<char, Traits, Alloc>, BasicJsonType, View> : std::true_type {};
|
||||
|
||||
// (vectors of these, which are faster than through from_json(), and containers
|
||||
// of views; other containers are read by the library's from_json())
|
||||
template<typename U, typename A, typename BasicJsonType, typename View>
|
||||
struct is_direct_value<std::vector<U, A>, BasicJsonType, View> : is_direct_value<U, BasicJsonType, View> {};
|
||||
struct is_direct_value<std::vector<U, A>, BasicJsonType, View> : std::true_type {};
|
||||
|
||||
template<typename K, typename C, typename A, typename BasicJsonType, typename View>
|
||||
struct is_direct_value<std::map<K, View, C, A>, BasicJsonType, View> : is_string_key<K> {};
|
||||
template<typename K, typename V, typename C, typename A, typename BasicJsonType, typename View>
|
||||
struct is_direct_value<std::map<K, V, C, A>, BasicJsonType, View> : is_string_key<K> {};
|
||||
|
||||
template<typename K, typename H, typename E, typename A, typename BasicJsonType, typename View>
|
||||
struct is_direct_value<std::unordered_map<K, View, H, E, A>, BasicJsonType, View> : is_string_key<K> {};
|
||||
template<typename K, typename V, typename H, typename E, typename A, typename BasicJsonType, typename View>
|
||||
struct is_direct_value<std::unordered_map<K, V, H, E, A>, BasicJsonType, View> : is_string_key<K> {};
|
||||
|
||||
} // namespace view
|
||||
} // namespace detail
|
||||
|
||||
@@ -1,52 +0,0 @@
|
||||
// __ _____ _____ _____
|
||||
// __| | __| | | | JSON for Modern C++
|
||||
// | | |__ | | | | | | version 3.12.0
|
||||
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2013-2026 Niels Lohmann <https://nlohmann.me>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint> // uint8_t
|
||||
#include <type_traits> // false_type, true_type
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
NLOHMANN_JSON_NAMESPACE_BEGIN
|
||||
|
||||
/// whether a basic_json_document and its views can be edited
|
||||
enum class view_mode : std::uint8_t
|
||||
{
|
||||
read_only, ///< parsed once, then only read (the default)
|
||||
editable, ///< also has set(), push_back(), insert(), and erase()
|
||||
};
|
||||
|
||||
template<typename BasicJsonType, view_mode Mode>
|
||||
class basic_json_view;
|
||||
|
||||
namespace detail
|
||||
{
|
||||
namespace view
|
||||
{
|
||||
|
||||
/// whether two view modes differ
|
||||
template<view_mode A, view_mode B>
|
||||
struct is_other_mode : std::true_type {};
|
||||
|
||||
template<view_mode A>
|
||||
struct is_other_mode<A, A> : std::false_type {};
|
||||
|
||||
/// whether a view of mode From converts implicitly to one of mode To: a
|
||||
/// read-only document has no edits, so a view of it is read correctly as a
|
||||
/// view of an editable document that has not been edited yet
|
||||
template<view_mode From, view_mode To>
|
||||
struct is_widening_mode : std::false_type {};
|
||||
|
||||
template<>
|
||||
struct is_widening_mode<view_mode::read_only, view_mode::editable> : std::true_type {};
|
||||
|
||||
} // namespace view
|
||||
} // namespace detail
|
||||
|
||||
NLOHMANN_JSON_NAMESPACE_END
|
||||
+42
-106
@@ -84,7 +84,6 @@
|
||||
#include <nlohmann/detail/view/serializer.hpp>
|
||||
#include <nlohmann/detail/view/string_ref.hpp>
|
||||
#include <nlohmann/detail/view/value.hpp>
|
||||
#include <nlohmann/detail/view/view_mode.hpp>
|
||||
|
||||
NLOHMANN_JSON_NAMESPACE_BEGIN
|
||||
|
||||
@@ -94,20 +93,15 @@ NLOHMANN_JSON_NAMESPACE_BEGIN
|
||||
Trivially copyable (two pointers). Valid as long as the document is alive and
|
||||
has not been re-parsed, and as long as a borrowed source text is alive.
|
||||
*/
|
||||
template<typename BasicJsonType, view_mode Mode = view_mode::read_only>
|
||||
template<typename BasicJsonType, bool Editable = false>
|
||||
class basic_json_view
|
||||
{
|
||||
/// whether this is a view of an editable document
|
||||
static constexpr bool is_editable = Mode == view_mode::editable;
|
||||
|
||||
using node = detail::view::node;
|
||||
using document_data = detail::view::document_data;
|
||||
/// how the index is walked (with edits only for editable documents)
|
||||
using navigation = detail::view::navigation<is_editable>;
|
||||
using navigation = detail::view::navigation<Editable>;
|
||||
|
||||
public:
|
||||
/// the basic_json type of the document (it also marks views for is_json_view)
|
||||
using basic_json_type = BasicJsonType;
|
||||
using value_t = detail::value_t;
|
||||
using string_t = typename BasicJsonType::string_t;
|
||||
using number_integer_t = typename BasicJsonType::number_integer_t;
|
||||
@@ -126,15 +120,6 @@ class basic_json_view
|
||||
/// an invalid view (type() == value_t::discarded)
|
||||
basic_json_view() noexcept = default;
|
||||
|
||||
/// a view of a read-only document as a view of an editable one, so that a
|
||||
/// function taking an editable view accepts both (a read-only document has
|
||||
/// no edits; the view reads it as an editable document before its first
|
||||
/// edit, at the cost of one check per access)
|
||||
template<view_mode M, detail::enable_if_t<detail::view::is_widening_mode<M, Mode>::value, int> = 0>
|
||||
basic_json_view(const basic_json_view<BasicJsonType, M>& other) noexcept // NOLINT(google-explicit-constructor,hicpp-explicit-conversions)
|
||||
: m_doc(other.m_doc), m_node(other.m_node)
|
||||
{}
|
||||
|
||||
//////////
|
||||
// type //
|
||||
//////////
|
||||
@@ -461,7 +446,7 @@ class basic_json_view
|
||||
if (is_structured() && m_node->len != 0)
|
||||
{
|
||||
return unedited() ? basic_json_view(m_doc, detail::view::last_child<false>(*m_doc, m_node) + (is_object() ? 1 : 0))
|
||||
: basic_json_view(m_doc, navigation::value(detail::view::last_child<is_editable>(*m_doc, m_node) + (is_object() ? 1 : 0)));
|
||||
: basic_json_view(m_doc, navigation::value(detail::view::last_child<Editable>(*m_doc, m_node) + (is_object() ? 1 : 0)));
|
||||
}
|
||||
return front();
|
||||
}
|
||||
@@ -519,7 +504,7 @@ class basic_json_view
|
||||
/// more than once); 0 if this is not an object
|
||||
size_type count(string_view_t key) const
|
||||
{
|
||||
return is_object() ? detail::view::count_members<is_editable>(*m_doc, m_node, key.data(), key.size()) : 0;
|
||||
return is_object() ? detail::view::count_members<Editable>(*m_doc, m_node, key.data(), key.size()) : 0;
|
||||
}
|
||||
|
||||
size_type count(const char* key) const
|
||||
@@ -578,10 +563,8 @@ class basic_json_view
|
||||
|
||||
/// the value converted to T, as BasicJsonType::get<T>(): arithmetic types,
|
||||
/// strings (string_view_t without a copy), std::nullptr_t, std::vector,
|
||||
/// maps with string keys, and views are converted directly; types whose
|
||||
/// from_json() accepts views (those of the NLOHMANN_DEFINE_TYPE_* and
|
||||
/// NLOHMANN_JSON_SERIALIZE_ENUM macros, say) read the view; other types
|
||||
/// go through materialize().get<T>()
|
||||
/// maps with string keys, and views are converted directly; other types
|
||||
/// through materialize().get<T>()
|
||||
template<typename T>
|
||||
NLOHMANN_VIEW_ALWAYS_INLINE T get() const
|
||||
{
|
||||
@@ -589,12 +572,11 @@ class basic_json_view
|
||||
}
|
||||
|
||||
/// as BasicJsonType::get_to(): the types get<T>() converts directly are
|
||||
/// assigned, all others are passed to from_json with v as it is (with
|
||||
/// the view if from_json() accepts views, else with materialize())
|
||||
/// assigned, all others are passed to from_json with v as it is
|
||||
template<typename T>
|
||||
T& get_to(T& v) const
|
||||
{
|
||||
get_to_impl(v, get_to_kind<T> {});
|
||||
get_to_impl(v, detail::view::is_direct_value<T, BasicJsonType, basic_json_view> {});
|
||||
return v;
|
||||
}
|
||||
|
||||
@@ -664,7 +646,7 @@ class basic_json_view
|
||||
}
|
||||
else
|
||||
{
|
||||
detail::view::view_serializer<BasicJsonType, is_editable>(*m_doc, out, estimate, style).dump(m_node);
|
||||
detail::view::view_serializer<BasicJsonType, Editable>(*m_doc, out, estimate, style).dump(m_node);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
@@ -700,14 +682,14 @@ class basic_json_view
|
||||
}
|
||||
|
||||
/// a view of an editable document compares with one of a read-only document
|
||||
template<view_mode M, detail::enable_if_t<detail::view::is_other_mode<M, Mode>::value, int> = 0>
|
||||
friend bool operator==(const basic_json_view& a, const basic_json_view<BasicJsonType, M>& b)
|
||||
template < bool E, typename std::enable_if < E != Editable, int >::type = 0 >
|
||||
friend bool operator==(const basic_json_view& a, const basic_json_view<BasicJsonType, E>& b)
|
||||
{
|
||||
return detail::view::equal<BasicJsonType>(side(a), detail::view::view_side<BasicJsonType, basic_json_view<BasicJsonType, M>>(b));
|
||||
return detail::view::equal<BasicJsonType>(side(a), detail::view::view_side<BasicJsonType, basic_json_view<BasicJsonType, E>>(b));
|
||||
}
|
||||
|
||||
template<view_mode M, detail::enable_if_t<detail::view::is_other_mode<M, Mode>::value, int> = 0>
|
||||
friend bool operator!=(const basic_json_view& a, const basic_json_view<BasicJsonType, M>& b)
|
||||
template < bool E, typename std::enable_if < E != Editable, int >::type = 0 >
|
||||
friend bool operator!=(const basic_json_view& a, const basic_json_view<BasicJsonType, E>& b)
|
||||
{
|
||||
return !(a == b);
|
||||
}
|
||||
@@ -745,7 +727,7 @@ class basic_json_view
|
||||
{
|
||||
return BasicJsonType(value_t::discarded);
|
||||
}
|
||||
return unedited() ? detail::view::materialize<BasicJsonType, false>(*m_doc, m_node) : detail::view::materialize<BasicJsonType, is_editable>(*m_doc, m_node);
|
||||
return unedited() ? detail::view::materialize<BasicJsonType, false>(*m_doc, m_node) : detail::view::materialize<BasicJsonType, Editable>(*m_doc, m_node);
|
||||
}
|
||||
|
||||
/// byte offset of this value in the source text (for strings: of the
|
||||
@@ -758,8 +740,8 @@ class basic_json_view
|
||||
}
|
||||
|
||||
private:
|
||||
template<typename, view_mode> friend class basic_json_document;
|
||||
template<typename, view_mode> friend class basic_json_view;
|
||||
template<typename, bool> friend class basic_json_document;
|
||||
template<typename, bool> friend class basic_json_view;
|
||||
template<typename, typename> friend class detail::view::editor;
|
||||
friend iterator;
|
||||
|
||||
@@ -775,11 +757,11 @@ class basic_json_view
|
||||
}
|
||||
|
||||
/// the template argument as a runtime condition: testing it directly in
|
||||
/// `is_editable && ...` makes the condition constant, which MSVC reports as
|
||||
/// `Editable && ...` makes the condition constant, which MSVC reports as
|
||||
/// C4127
|
||||
static bool editable() noexcept
|
||||
{
|
||||
return is_editable;
|
||||
return Editable;
|
||||
}
|
||||
|
||||
/// the number of source bytes of this value (estimated for values with
|
||||
@@ -828,7 +810,7 @@ class basic_json_view
|
||||
const node* const k = detail::view::find_member<false>(*m_doc, m_node, key.data(), key.size());
|
||||
return k != nullptr ? basic_json_view(m_doc, k + 1) : basic_json_view();
|
||||
}
|
||||
const node* const k = detail::view::find_member<is_editable>(*m_doc, m_node, key.data(), key.size());
|
||||
const node* const k = detail::view::find_member<Editable>(*m_doc, m_node, key.data(), key.size());
|
||||
return k != nullptr ? basic_json_view(m_doc, navigation::value(k + 1)) : basic_json_view();
|
||||
}
|
||||
|
||||
@@ -842,7 +824,7 @@ class basic_json_view
|
||||
/// the member of this object with @a key (the last one if the key occurs more than once), or nullptr
|
||||
NLOHMANN_VIEW_ALWAYS_INLINE const node* find_key(string_view_t key) const
|
||||
{
|
||||
return find_key(key, std::integral_constant<bool, is_editable> {});
|
||||
return find_key(key, std::integral_constant<bool, Editable> {});
|
||||
}
|
||||
|
||||
NLOHMANN_VIEW_ALWAYS_INLINE const node* find_key(string_view_t key, std::true_type /*editable*/) const
|
||||
@@ -864,7 +846,7 @@ class basic_json_view
|
||||
{
|
||||
return basic_json_view(m_doc, detail::view::element_at<false>(*m_doc, m_node, idx));
|
||||
}
|
||||
return basic_json_view(m_doc, navigation::value(detail::view::element_at<is_editable>(*m_doc, m_node, idx)));
|
||||
return basic_json_view(m_doc, navigation::value(detail::view::element_at<Editable>(*m_doc, m_node, idx)));
|
||||
}
|
||||
|
||||
// --- get() dispatch ---
|
||||
@@ -919,45 +901,22 @@ class basic_json_view
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// vectors of the types converted directly (faster than the library's
|
||||
/// from_json()) and containers of views (no from_json() reads them: a view
|
||||
/// is no value of BasicJsonType); other containers are read by from_json()
|
||||
template<typename U, typename A, detail::enable_if_t<detail::view::is_direct_value<U, BasicJsonType, basic_json_view>::value, int> = 0>
|
||||
template<typename U, typename A>
|
||||
std::vector<U, A> get_impl(detail::view::value_tag<std::vector<U, A>> /*unused*/, detail::priority_tag<2> /*unused*/) const
|
||||
{
|
||||
return detail::view::vector_value<basic_json_view, U, A>(*this);
|
||||
}
|
||||
|
||||
template<typename K, typename C, typename A, typename std::enable_if<detail::view::is_string_key<K>::value, int>::type = 0>
|
||||
std::map<K, basic_json_view, C, A> get_impl(detail::view::value_tag<std::map<K, basic_json_view, C, A>> /*unused*/, detail::priority_tag<2> /*unused*/) const
|
||||
template<typename K, typename V, typename C, typename A, typename std::enable_if<detail::view::is_string_key<K>::value, int>::type = 0>
|
||||
std::map<K, V, C, A> get_impl(detail::view::value_tag<std::map<K, V, C, A>> /*unused*/, detail::priority_tag<2> /*unused*/) const
|
||||
{
|
||||
return detail::view::map_value<std::map<K, basic_json_view, C, A>>(*this);
|
||||
return detail::view::map_value<std::map<K, V, C, A>>(*this);
|
||||
}
|
||||
|
||||
template<typename K, typename H, typename E, typename A, typename std::enable_if<detail::view::is_string_key<K>::value, int>::type = 0>
|
||||
std::unordered_map<K, basic_json_view, H, E, A> get_impl(detail::view::value_tag<std::unordered_map<K, basic_json_view, H, E, A>> /*unused*/, detail::priority_tag<2> /*unused*/) const
|
||||
template<typename K, typename V, typename H, typename E, typename A, typename std::enable_if<detail::view::is_string_key<K>::value, int>::type = 0>
|
||||
std::unordered_map<K, V, H, E, A> get_impl(detail::view::value_tag<std::unordered_map<K, V, H, E, A>> /*unused*/, detail::priority_tag<2> /*unused*/) const
|
||||
{
|
||||
return detail::view::map_value<std::unordered_map<K, basic_json_view, H, E, A>>(*this);
|
||||
}
|
||||
|
||||
/// whether the from_json() of T's serializer reads views (see
|
||||
/// detail::has_view_from_json)
|
||||
template<typename T>
|
||||
using reads_view = detail::has_view_from_json<typename BasicJsonType::template json_serializer<T, void>, basic_json_view, T>;
|
||||
|
||||
/// how get_to() converts: 2 directly, 1 with a from_json() that reads
|
||||
/// views, 0 through materialize()
|
||||
template<typename T>
|
||||
using get_to_kind = std::integral_constant < int, detail::view::is_direct_value<T, BasicJsonType, basic_json_view>::value
|
||||
? 2 : static_cast<int>(reads_view<T>::value) >;
|
||||
|
||||
/// types whose from_json() reads views, without materialize()
|
||||
template<typename T, detail::enable_if_t<detail::conjunction<reads_view<T>, std::is_default_constructible<T>>::value, int> = 0>
|
||||
T get_impl(detail::view::value_tag<T> /*unused*/, detail::priority_tag<1> /*unused*/) const
|
||||
{
|
||||
auto v = T();
|
||||
BasicJsonType::template json_serializer<T, void>::from_json(*this, v);
|
||||
return v;
|
||||
return detail::view::map_value<std::unordered_map<K, V, H, E, A>>(*this);
|
||||
}
|
||||
|
||||
/// everything else through the BasicJsonType value (from_json included)
|
||||
@@ -970,20 +929,14 @@ class basic_json_view
|
||||
// --- get_to() dispatch ---
|
||||
|
||||
template<typename T>
|
||||
void get_to_impl(T& v, std::integral_constant<int, 2> /*direct*/) const
|
||||
void get_to_impl(T& v, std::true_type /*direct*/) const
|
||||
{
|
||||
v = get<T>();
|
||||
}
|
||||
|
||||
/// from_json may keep parts of v (members a JSON object lacks, say)
|
||||
template<typename T>
|
||||
void get_to_impl(T& v, std::integral_constant<int, 1> /*from_json reads views*/) const
|
||||
{
|
||||
BasicJsonType::template json_serializer<T, void>::from_json(*this, v);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void get_to_impl(T& v, std::integral_constant<int, 0> /*through materialize()*/) const
|
||||
void get_to_impl(T& v, std::false_type /*direct*/) const
|
||||
{
|
||||
materialize().get_to(v);
|
||||
}
|
||||
@@ -999,19 +952,16 @@ Borrowed parses keep a pointer to the caller's text, which must outlive the
|
||||
document. Owned parses (parse_copy, rvalue std::string, streams, and inputs
|
||||
that are not contiguous byte ranges) keep their own copy.
|
||||
*/
|
||||
template<typename BasicJsonType, view_mode Mode = view_mode::read_only>
|
||||
template<typename BasicJsonType, bool Editable = false>
|
||||
class basic_json_document
|
||||
{
|
||||
/// whether the document can be edited
|
||||
static constexpr bool is_editable = Mode == view_mode::editable;
|
||||
|
||||
using document_data = detail::view::document_data;
|
||||
|
||||
static_assert(sizeof(typename BasicJsonType::number_integer_t) == 8 && sizeof(typename BasicJsonType::number_unsigned_t) == 8,
|
||||
"json_view supports 64-bit integer types only");
|
||||
|
||||
public:
|
||||
using view_type = basic_json_view<BasicJsonType, Mode>;
|
||||
using view_type = basic_json_view<BasicJsonType, Editable>;
|
||||
using value_t = detail::value_t;
|
||||
|
||||
/// an empty (discarded) document
|
||||
@@ -1225,10 +1175,6 @@ class basic_json_document
|
||||
/// how load() checks an image (full, bounds, or none)
|
||||
using image_check = detail::view::image_check;
|
||||
|
||||
#if NLOHMANN_VIEW_LITTLE_ENDIAN
|
||||
// (the image format is little-endian: big-endian targets have no save()
|
||||
// and load(), so that a call fails to compile instead of always throwing)
|
||||
|
||||
/// The document as an image that load() reads without parsing: the node
|
||||
/// index, the text, and the decoded strings. An edited document is
|
||||
/// written in its current state (floats that are not finite become null,
|
||||
@@ -1270,7 +1216,6 @@ class basic_json_document
|
||||
detail::view::load_image(*d.m_data, d.m_data->owned_image.data(), d.m_data->owned_image.size(), check);
|
||||
return d;
|
||||
}
|
||||
#endif
|
||||
|
||||
///////////
|
||||
// edits //
|
||||
@@ -1412,7 +1357,7 @@ class basic_json_document
|
||||
|
||||
detail::view::editor<BasicJsonType, view_type> editor()
|
||||
{
|
||||
static_assert(is_editable, "only an editable document can be edited: use basic_json_document<BasicJsonType, view_mode::editable> (json_editable_document)");
|
||||
static_assert(Editable, "only an editable document can be edited: use basic_json_document<BasicJsonType, true> (json_editable_document)");
|
||||
if (NLOHMANN_VIEW_UNLIKELY(!m_data || m_data->discarded))
|
||||
{
|
||||
detail::view::throw_invalid_iterator(detail::exception_id::iterator_from_other_value, "view does not belong to this document");
|
||||
@@ -1688,31 +1633,22 @@ class basic_json_document
|
||||
std::unique_ptr<document_data, document_data::deleter> m_data{}; // NOLINT(readability-redundant-member-init)
|
||||
};
|
||||
|
||||
/*!
|
||||
@brief whether T is a basic_json_view (of any BasicJsonType and view_mode)
|
||||
|
||||
For constraining templates that accept views, e.g. a from_json() written for
|
||||
both basic_json values and views.
|
||||
*/
|
||||
template<typename T>
|
||||
struct is_json_view : detail::is_json_view<T> {};
|
||||
|
||||
/// a parsed JSON text for json
|
||||
using json_document = basic_json_document<json, view_mode::read_only>;
|
||||
using json_document = basic_json_document<json>;
|
||||
/// a value of a json_document
|
||||
using json_view = basic_json_view<json, view_mode::read_only>;
|
||||
using json_view = basic_json_view<json>;
|
||||
/// a parsed JSON text for ordered_json
|
||||
using ordered_json_document = basic_json_document<ordered_json, view_mode::read_only>;
|
||||
using ordered_json_document = basic_json_document<ordered_json>;
|
||||
/// a value of an ordered_json_document
|
||||
using ordered_json_view = basic_json_view<ordered_json, view_mode::read_only>;
|
||||
using ordered_json_view = basic_json_view<ordered_json>;
|
||||
/// an editable parsed JSON text for json
|
||||
using json_editable_document = basic_json_document<json, view_mode::editable>;
|
||||
using json_editable_document = basic_json_document<json, true>;
|
||||
/// a value of a json_editable_document
|
||||
using json_editable_view = basic_json_view<json, view_mode::editable>;
|
||||
using json_editable_view = basic_json_view<json, true>;
|
||||
/// an editable parsed JSON text for ordered_json
|
||||
using ordered_json_editable_document = basic_json_document<ordered_json, view_mode::editable>;
|
||||
using ordered_json_editable_document = basic_json_document<ordered_json, true>;
|
||||
/// a value of an ordered_json_editable_document
|
||||
using ordered_json_editable_view = basic_json_view<ordered_json, view_mode::editable>;
|
||||
using ordered_json_editable_view = basic_json_view<ordered_json, true>;
|
||||
|
||||
NLOHMANN_JSON_NAMESPACE_END
|
||||
|
||||
|
||||
Generated
+3700
File diff suppressed because it is too large.
Load diff
Generated
+663
-705
File diff suppressed because it is too large.
Load diff
Generated
+18
-4
@@ -145,14 +145,26 @@
|
||||
#define NLOHMANN_JSON_ABI_TAG_NO_SIMD
|
||||
#endif
|
||||
|
||||
#ifdef JSON_VIEW_NO_SIMD
|
||||
#define NLOHMANN_JSON_ABI_TAG_VIEW_NO_SIMD _vns
|
||||
#else
|
||||
#define NLOHMANN_JSON_ABI_TAG_VIEW_NO_SIMD
|
||||
#endif
|
||||
|
||||
#ifdef JSON_VIEW_USE_SSSE3
|
||||
#define NLOHMANN_JSON_ABI_TAG_VIEW_USE_SSSE3 _vssse3
|
||||
#else
|
||||
#define NLOHMANN_JSON_ABI_TAG_VIEW_USE_SSSE3
|
||||
#endif
|
||||
|
||||
#ifndef NLOHMANN_JSON_NAMESPACE_NO_VERSION
|
||||
#define NLOHMANN_JSON_NAMESPACE_NO_VERSION 0
|
||||
#endif
|
||||
|
||||
// Construct the namespace ABI tags component
|
||||
#define NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b, c, d, e, f, g, h, i, j, k) json_abi ## a ## b ## c ## d ## e ## f ## g ## h ## i ## j ## k
|
||||
#define NLOHMANN_JSON_ABI_TAGS_CONCAT(a, b, c, d, e, f, g, h, i, j, k) \
|
||||
NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b, c, d, e, f, g, h, i, j, k)
|
||||
#define NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b, c, d, e, f, g, h, i, j, k, l, m) json_abi ## a ## b ## c ## d ## e ## f ## g ## h ## i ## j ## k ## l ## m
|
||||
#define NLOHMANN_JSON_ABI_TAGS_CONCAT(a, b, c, d, e, f, g, h, i, j, k, l, m) \
|
||||
NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b, c, d, e, f, g, h, i, j, k, l, m)
|
||||
|
||||
#define NLOHMANN_JSON_ABI_TAGS \
|
||||
NLOHMANN_JSON_ABI_TAGS_CONCAT( \
|
||||
@@ -166,7 +178,9 @@
|
||||
NLOHMANN_JSON_ABI_TAG_OBJECTS_FOR_ENUM_KEYED_MAPS, \
|
||||
NLOHMANN_JSON_ABI_TAG_DISABLE_STREAM_BULK_SCAN, \
|
||||
NLOHMANN_JSON_ABI_TAG_DISABLE_UNLOCKED_FILE_IO, \
|
||||
NLOHMANN_JSON_ABI_TAG_NO_SIMD)
|
||||
NLOHMANN_JSON_ABI_TAG_NO_SIMD, \
|
||||
NLOHMANN_JSON_ABI_TAG_VIEW_NO_SIMD, \
|
||||
NLOHMANN_JSON_ABI_TAG_VIEW_USE_SSSE3)
|
||||
|
||||
// Construct the namespace version component
|
||||
#define NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT_EX(major, minor, patch) \
|
||||
|
||||
Generated
+150
-279
File diff suppressed because it is too large.
Load diff
@@ -420,9 +420,9 @@ json_test_add_test_for(src/unit-file_input.cpp
|
||||
)
|
||||
|
||||
# the json_view parser again with the portable string scanning instead of
|
||||
# NEON/SSE2 (JSON_NO_SIMD), and on x86-64 compiled for SSSE3 (no CPU check)
|
||||
# NEON/SSE2, and on x86-64 with the SSSE3 UTF-8 check (JSON_VIEW_USE_SSSE3)
|
||||
json_test_set_test_options(test-json_view_builder_portable
|
||||
COMPILE_DEFINITIONS JSON_NO_SIMD
|
||||
COMPILE_DEFINITIONS JSON_VIEW_NO_SIMD
|
||||
)
|
||||
json_test_add_test_for(src/unit-json_view_builder.cpp
|
||||
NAME test-json_view_builder_portable
|
||||
@@ -430,6 +430,7 @@ json_test_add_test_for(src/unit-json_view_builder.cpp
|
||||
)
|
||||
if(CMAKE_SYSTEM_PROCESSOR MATCHES "^(x86_64|AMD64|amd64)$" AND NOT MSVC)
|
||||
json_test_set_test_options(test-json_view_builder_ssse3
|
||||
COMPILE_DEFINITIONS JSON_VIEW_USE_SSSE3
|
||||
COMPILE_OPTIONS -mssse3
|
||||
)
|
||||
json_test_add_test_for(src/unit-json_view_builder.cpp
|
||||
|
||||
Loaded 100 of 119 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user