mirror of
https://github.com/nlohmann/json.git
synced 2026-10-27 08:18:55 +00:00
Compare commits
52
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
52e9f098eb | ||
|
|
a6c5d970f3 | ||
|
|
d9c0fda829 | ||
|
|
a763c9eb83 | ||
|
|
5c2aba70f9 | ||
|
|
510ee0ab4f | ||
|
|
5da0e9181f | ||
|
|
0aff24ca37 | ||
|
|
c25aad3ca5 | ||
|
|
6a0cf2ba2f | ||
|
|
24de5b2f5c | ||
|
|
fb729028ba | ||
|
|
c9fdfc39db | ||
|
|
870bdec01f | ||
|
|
effa51d528 | ||
|
|
545477ffa8 | ||
|
|
aeba637593 | ||
|
|
466e56d92d | ||
|
|
b7b75aac8a | ||
|
|
516b9b516a | ||
|
|
1d2dea7769 | ||
|
|
f8ff0942b2 | ||
|
|
d1e6439187 | ||
|
|
dcf7e2222c | ||
|
|
d99932fb3f | ||
|
|
1d2cb49ff3 | ||
|
|
a2766df787 | ||
|
|
2ea5bed0e3 | ||
|
|
632f5369fe | ||
|
|
c2619bf460 | ||
|
|
351aeb7440 | ||
|
|
7b0af0072e | ||
|
|
650886d126 | ||
|
|
a759afc99f | ||
|
|
1143da4faa | ||
|
|
8de151f928 | ||
|
|
ab52c98f71 | ||
|
|
5e93415d91 | ||
|
|
7e8e8e219b | ||
|
|
5f1727cef2 | ||
|
|
c16dd7e4f5 | ||
|
|
792853d725 | ||
|
|
4bdf1b7e74 | ||
|
|
b1e9d98e41 | ||
|
|
f855d257df | ||
|
|
3e683e9c04 | ||
|
|
d1d84ed9af | ||
|
|
de8529f99b | ||
|
|
677794f076 | ||
|
|
437a95cfdb | ||
|
|
c8735246d0 | ||
|
|
9adb510a0d |
No files matched your search
@@ -111,6 +111,8 @@ context which existing file needs to be extended, and only very few cases requir
|
|||||||
When fixing a bug, edit `unit-regression3.cpp` and add a section referencing the fixed issue.
|
When fixing a bug, edit `unit-regression3.cpp` and add a section referencing the fixed issue.
|
||||||
`unit-regression2.cpp` holds the older tests; the two files exist because a single one grew large enough for the
|
`unit-regression2.cpp` holds the older tests; the two files exist because a single one grew large enough for the
|
||||||
MinGW linker to fail relocating it, so please keep adding to the smaller file rather than growing the larger one.
|
MinGW linker to fail relocating it, so please keep adding to the smaller file rather than growing the larger one.
|
||||||
|
Tests that call `sax_parse` go into `unit-sax_parse.cpp` rather than into a large test file: every call instantiates
|
||||||
|
the parser and the binary reader that recover from errors, which grows a test file considerably.
|
||||||
|
|
||||||
#### Exceptions
|
#### Exceptions
|
||||||
|
|
||||||
|
|||||||
@@ -163,9 +163,9 @@ jobs:
|
|||||||
python3 $GENERATOR --list-tags
|
python3 $GENERATOR --list-tags
|
||||||
TAG_COUNT=$(python3 $GENERATOR --list-tags | wc -l)
|
TAG_COUNT=$(python3 $GENERATOR --list-tags | wc -l)
|
||||||
|
|
||||||
python3 $GENERATOR --abi-tags diag,_dp,_ns --abi-tags _diag --output $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_ns -->' $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_ns_v[0-9_]* -->' $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 ))
|
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
|
python3 $GENERATOR --all --output $RUNNER_TEMP/all.natvis
|
||||||
|
|||||||
@@ -43,8 +43,8 @@ jobs:
|
|||||||
- name: flawfinder_scan
|
- name: flawfinder_scan
|
||||||
uses: david-a-wheeler/flawfinder@c4216b74cf2639ffa98503768bd6e4299b5440c9 # v2.0.20
|
uses: david-a-wheeler/flawfinder@c4216b74cf2639ffa98503768bd6e4299b5440c9 # v2.0.20
|
||||||
with:
|
with:
|
||||||
# single_include/ is generated from include/ and would report every finding twice
|
# single_include/ is omitted: it is generated from include/ and would report every finding twice
|
||||||
arguments: "--sarif --exclude '*/single_include/*' ./"
|
arguments: '--sarif ./cmake ./docs ./include ./src ./tests ./tools'
|
||||||
output: 'flawfinder_results.sarif'
|
output: 'flawfinder_results.sarif'
|
||||||
|
|
||||||
- name: Upload analysis results to GitHub Security tab
|
- name: Upload analysis results to GitHub Security tab
|
||||||
|
|||||||
@@ -90,7 +90,6 @@ cc_library(
|
|||||||
"include/nlohmann/detail/view/simd.hpp",
|
"include/nlohmann/detail/view/simd.hpp",
|
||||||
"include/nlohmann/detail/view/string_ref.hpp",
|
"include/nlohmann/detail/view/string_ref.hpp",
|
||||||
"include/nlohmann/detail/view/value.hpp",
|
"include/nlohmann/detail/view/value.hpp",
|
||||||
"include/nlohmann/detail/view/view_mode.hpp",
|
|
||||||
"include/nlohmann/json.hpp",
|
"include/nlohmann/json.hpp",
|
||||||
"include/nlohmann/json_fwd.hpp",
|
"include/nlohmann/json_fwd.hpp",
|
||||||
"include/nlohmann/json_literals.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
|
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
|
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`
|
[`tools/generate_natvis`](tools/generate_natvis/README.md). With MSVC, CMake adds the file to the `nlohmann_json`
|
||||||
target and installs it.
|
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
|
tools/amalgamate/amalgamate.py -c tools/amalgamate/config_json_view.json -s . --verbose=yes
|
||||||
|
|
||||||
NATVIS_VENV=tools/generate_natvis/venv
|
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=
|
NATVIS_ARGS=
|
||||||
|
|
||||||
# regenerate nlohmann_json.natvis from the ABI tags and version in include/nlohmann/detail/abi_macros.hpp
|
# regenerate nlohmann_json.natvis from the ABI tags and version in include/nlohmann/detail/abi_macros.hpp
|
||||||
|
|||||||
@@ -495,7 +495,7 @@ bool key(string_t& val);
|
|||||||
bool parse_error(std::size_t position, const std::string& last_token, const detail::exception& ex);
|
bool parse_error(std::size_t position, const std::string& last_token, const detail::exception& ex);
|
||||||
```
|
```
|
||||||
|
|
||||||
The return value of each function determines whether parsing should proceed.
|
The return value of each function determines whether parsing should proceed. For `parse_error`, returning `true` [recovers from the error](https://json.nlohmann.me/features/parsing/error_recovery/): the parser repairs the input and continues.
|
||||||
|
|
||||||
To implement your own SAX handler, proceed as follows:
|
To implement your own SAX handler, proceed as follows:
|
||||||
|
|
||||||
@@ -503,7 +503,7 @@ To implement your own SAX handler, proceed as follows:
|
|||||||
2. Create an object of your SAX interface class, e.g. `my_sax`.
|
2. Create an object of your SAX interface class, e.g. `my_sax`.
|
||||||
3. Call `bool json::sax_parse(input, &my_sax)`; where the first parameter can be any input like a string or an input stream and the second parameter is a pointer to your SAX interface.
|
3. Call `bool json::sax_parse(input, &my_sax)`; where the first parameter can be any input like a string or an input stream and the second parameter is a pointer to your SAX interface.
|
||||||
|
|
||||||
Note the `sax_parse` function only returns a `bool` indicating the result of the last executed SAX event. It does not return a `json` value - it is up to you to decide what to do with the SAX events. Furthermore, no exceptions are thrown in case of a parse error -- it is up to you what to do with the exception object passed to your `parse_error` implementation. Internally, the SAX interface is used for the DOM parser (class `json_sax_dom_parser`) as well as the acceptor (`json_sax_acceptor`), see file [`json_sax.hpp`](https://github.com/nlohmann/json/blob/develop/include/nlohmann/detail/input/json_sax.hpp).
|
Note the `sax_parse` function only returns a `bool` indicating whether the input was parsed without errors and no SAX event returned `false`. It does not return a `json` value - it is up to you to decide what to do with the SAX events. Furthermore, no exceptions are thrown in case of a parse error -- it is up to you what to do with the exception object passed to your `parse_error` implementation. Internally, the SAX interface is used for the DOM parser (class `json_sax_dom_parser`) as well as the acceptor (`json_sax_acceptor`), see file [`json_sax.hpp`](https://github.com/nlohmann/json/blob/develop/include/nlohmann/detail/input/json_sax.hpp).
|
||||||
|
|
||||||
### STL-like access
|
### STL-like access
|
||||||
|
|
||||||
|
|||||||
@@ -90,9 +90,8 @@ type `#!cpp binary_t*` must be dereferenced.
|
|||||||
|
|
||||||
- MessagePack
|
- MessagePack
|
||||||
- If a subtype is given and the binary array contains exactly 1, 2, 4, 8, or 16 elements, the fixext family (fixext1,
|
- 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
|
fixext2, fixext4, fixext8) is used. For other sizes, the ext family (ext8, ext16, ext32) is used. The subtype is
|
||||||
subtype is then written as the signed 8-bit ext type: subtypes 128 to 255 map to the negative (reserved) ext
|
then added as a signed 8-bit integer.
|
||||||
types, and on reading the ext type is exposed as an unsigned subtype from 0 to 255.
|
|
||||||
- If no subtype is given, the bin family (bin8, bin16, bin32) is used.
|
- If no subtype is given, the bin family (bin8, bin16, bin32) is used.
|
||||||
|
|
||||||
- BSON
|
- 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)
|
: report a parse error in case of a tag (the `from_cbor` overloads throw a `parse_error` exception by default)
|
||||||
|
|
||||||
ignore
|
ignore
|
||||||
: ignore tags (also in front of a text string map key)
|
: ignore tags
|
||||||
|
|
||||||
store
|
store
|
||||||
: store tagged byte strings (for bytes 0xd8..0xdb) as binary values with the tag as subtype; other tagged values are
|
: 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
|
read as if the tag were ignored. If several tags precede a byte string, only the innermost one is stored.
|
||||||
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.
|
|
||||||
|
|
||||||
## Examples
|
## Examples
|
||||||
|
|
||||||
|
|||||||
@@ -61,18 +61,11 @@ Strong exception safety: if an exception occurs, the original value stays intact
|
|||||||
|
|
||||||
## Complexity
|
## Complexity
|
||||||
|
|
||||||
1. Logarithmic in the size of the JSON object.
|
Logarithmic in the size of the JSON object.
|
||||||
2. Logarithmic in the size of the JSON object.
|
|
||||||
3. At most one lookup per reference token of `ptr`, each logarithmic in the size of the container at that level:
|
|
||||||
O(*n* log *m*) for *n* reference tokens and containers of size at most *m*.
|
|
||||||
4. Deleted; a call with an integral argument does not compile.
|
|
||||||
|
|
||||||
## Notes
|
## Notes
|
||||||
|
|
||||||
- Overloads (1) and (2) always return `#!cpp false` when executed on a JSON type that is not an object. Overload (3)
|
- This method always returns `#!cpp false` when executed on a JSON type that is not an object.
|
||||||
also works on arrays and on primitive values: the empty JSON pointer resolves in every JSON value (so
|
|
||||||
`#!cpp json(1).contains(""_json_pointer)` returns `#!cpp true`), and `#!cpp json({1, 2}).contains("/1"_json_pointer)`
|
|
||||||
returns `#!cpp true`.
|
|
||||||
- This method can be executed on any JSON value type.
|
- This method can be executed on any JSON value type.
|
||||||
- Calling this function with an integer argument (for example, `#!cpp contains(0)`) does not compile: such an argument
|
- Calling this function with an integer argument (for example, `#!cpp contains(0)`) does not compile: such an argument
|
||||||
would otherwise implicitly convert to a null `#!cpp const char*` and, from there, cause undefined behavior when
|
would otherwise implicitly convert to a null `#!cpp const char*` and, from there, cause undefined behavior when
|
||||||
|
|||||||
@@ -2,27 +2,17 @@
|
|||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
static basic_json diff(const basic_json& source,
|
static basic_json diff(const basic_json& source,
|
||||||
const basic_json& target,
|
const basic_json& target);
|
||||||
const string_t& path = "");
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Creates a [JSON Patch](http://jsonpatch.com) so that value `source` can be changed into the value `target` by calling
|
Creates a [JSON Patch](http://jsonpatch.com) so that value `source` can be changed into the value `target` by calling
|
||||||
[`patch`](patch.md) function.
|
[`patch`](patch.md) function.
|
||||||
|
|
||||||
For two JSON values `source` and `target`, the following code yields `#!cpp true`:
|
For two JSON values `source` and `target`, the following code always yields `#!cpp true`:
|
||||||
```cpp
|
```cpp
|
||||||
source.patch(diff(source, target)) == target;
|
source.patch(diff(source, target)) == target;
|
||||||
```
|
```
|
||||||
|
|
||||||
The equality holds up to [`operator==`](operator_eq.md), so it has the following exceptions:
|
|
||||||
|
|
||||||
- A value that is not equal to itself cannot round-trip. This applies to `NaN` (also nested in an array or object) and
|
|
||||||
to [discarded](is_discarded.md) values: `diff` emits a `replace` operation for them. A `NaN` in the patch is
|
|
||||||
serialized as `#!json null`, so a patch that was dumped and parsed again would set `#!json null`.
|
|
||||||
- Numbers that compare equal produce no operation, even if their types or signs differ: `diff(1, 1.0)`,
|
|
||||||
`diff(1u, 1)` (unsigned and signed integer) and `diff(0.0, -0.0)` all return `#!json []`. The patched value is then
|
|
||||||
the `source` and keeps its number type.
|
|
||||||
|
|
||||||
## Parameters
|
## Parameters
|
||||||
|
|
||||||
`source` (in)
|
`source` (in)
|
||||||
@@ -31,12 +21,6 @@ The equality holds up to [`operator==`](operator_eq.md), so it has the following
|
|||||||
`target` (in)
|
`target` (in)
|
||||||
: JSON value to compare against
|
: JSON value to compare against
|
||||||
|
|
||||||
`path` (in)
|
|
||||||
: a prefix that is put verbatim in front of the `path` member of every operation (default: `""`, which addresses the
|
|
||||||
root of the value). The prefix is neither escaped nor validated: `#!cpp diff(1, 2, "abc")` yields an operation with
|
|
||||||
the `path` `abc`, which is not a valid JSON Pointer. Use it with a valid JSON Pointer such as `/root` and escape
|
|
||||||
`~` and `/` in its reference tokens (see [JSON Pointer](../../features/json_pointer.md)).
|
|
||||||
|
|
||||||
## Return value
|
## Return value
|
||||||
|
|
||||||
a JSON patch to convert the `source` to `target`
|
a JSON patch to convert the `source` to `target`
|
||||||
@@ -47,32 +31,11 @@ Strong guarantee: `source` and `target` are never modified.
|
|||||||
|
|
||||||
## Complexity
|
## Complexity
|
||||||
|
|
||||||
Linear in the total number of values (including nested ones) in `source` and `target`, times the cost of a key-based
|
Linear in the lengths of `source` and `target`.
|
||||||
object operation (looking up a key in an object): logarithmic for [`json`](../json.md), and linear for
|
|
||||||
[`ordered_json`](../ordered_json.md) (see [`ordered_map` complexity](../ordered_map.md#complexity)). For
|
|
||||||
`ordered_json`, diffing two objects with `n` and `m` members therefore takes O((n+m)²) when their keys do not line up
|
|
||||||
(e.g., a key was added or the keys are in a different order). The size of the patch is proportional to the number of
|
|
||||||
operations times the length of their paths, so a small change deep inside a value yields a long `path`.
|
|
||||||
|
|
||||||
## Notes
|
## Notes
|
||||||
|
|
||||||
- Currently, only `remove`, `add`, and `replace` operations are generated.
|
Currently, only `remove`, `add`, and `replace` operations are generated.
|
||||||
- The patch is correct, but not guaranteed to be minimal. For instance, `diff([1,2,3], [0,1,2,3])` yields three
|
|
||||||
`replace` operations and one `add` operation instead of a single insertion.
|
|
||||||
- Differences between two arrays are reported index by index. Elements that were added at the end of the array are added
|
|
||||||
with `add` operations on the path `/-` (appended in order), and elements that were removed are removed with `remove`
|
|
||||||
operations from the highest index down to the lowest, so that the remaining indices stay valid.
|
|
||||||
- For objects, the operations for the members of `source` come first (`replace`, `remove`, or the operations for nested
|
|
||||||
values, in the iteration order of `source`), followed by `add` operations for the members that only `target` has.
|
|
||||||
- For [`ordered_json`](../ordered_json.md), objects with the same keys in a different order are different. As a patch
|
|
||||||
cannot reorder members, `diff` removes all keys of the `source` object and adds them again in the order of the
|
|
||||||
`target`.
|
|
||||||
- If `source` and `target` differ as a whole (e.g., different types), the patch consists of a single `replace`
|
|
||||||
operation for the root of the value, i.e., with the `path` `""` (or the given `path` prefix).
|
|
||||||
- The `value` members of the patch hold copies of values of `target`. A [binary](../../features/binary_values.md) value
|
|
||||||
has no JSON representation: when a patch that contains one is serialized, it becomes an object such as
|
|
||||||
`#!json {"bytes":[1,3],"subtype":null}`, so a parsed patch no longer holds a binary value (and would set that object
|
|
||||||
instead).
|
|
||||||
|
|
||||||
## Examples
|
## 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.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
|
- 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`
|
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
|
- 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
|
or n-dimensional array cannot be represented by `std::size_t`
|
||||||
an n-dimensional array overflows
|
|
||||||
|
|
||||||
## Complexity
|
## 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
|
- 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
|
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
|
## Complexity
|
||||||
|
|
||||||
Linear in the size of the input.
|
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
|
- 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
|
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
|
- 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
|
invalid string or byte array length)
|
||||||
that does not match the content; `strict` does not affect the document size checks)
|
|
||||||
- Throws [`parse_error.114`](../../home/exceptions.md#jsonexceptionparse_error114) if an unsupported BSON record type is
|
- Throws [`parse_error.114`](../../home/exceptions.md#jsonexceptionparse_error114) if an unsupported BSON record type is
|
||||||
encountered
|
encountered
|
||||||
- Throws [`parse_error.113`](../../home/exceptions.md#jsonexceptionparse_error113) if a string value or object key is
|
- 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
|
- an `std::istream` object
|
||||||
- a `FILE` pointer
|
- a `FILE` pointer
|
||||||
- a C-style array of characters (its terminating NUL is read as trailing data: `parse_error.110` unless `strict` is
|
- a C-style array of characters
|
||||||
`false`)
|
- a pointer to a null-terminated string of single byte characters
|
||||||
- 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 container `obj` for which `begin(obj)` and `end(obj)` produce a valid pair of iterators
|
- 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`)
|
(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
|
- 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
|
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
|
- 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
|
other types are not supported, as JSON object keys are always strings), or if a string value or object key is not
|
||||||
malformed (including a chunk of the wrong type or an indefinite-length string nested inside an indefinite-length
|
valid UTF-8 and `error_handler` is `strict`
|
||||||
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`
|
|
||||||
|
|
||||||
## Complexity
|
## 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
|
- 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
|
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
|
- Throws [parse_error.112](../../home/exceptions.md#jsonexceptionparse_error112) if a parse error occurs
|
||||||
(including a type marker after `$` of an optimized container, even if its count is 0), or if `$` is not followed by `#`
|
|
||||||
- Throws [parse_error.113](../../home/exceptions.md#jsonexceptionparse_error113) if a string could not be parsed
|
- 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
|
successfully, or if a string value or object key is not valid UTF-8 and `error_handler` is `strict`
|
||||||
container is negative, 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
|
||||||
- Throws [parse_error.115](../../home/exceptions.md#jsonexceptionparse_error115) if the text of a high-precision number
|
or n-dimensional array cannot be represented by `std::size_t`
|
||||||
(`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
|
|
||||||
|
|
||||||
## Complexity
|
## Complexity
|
||||||
|
|
||||||
|
|||||||
@@ -121,7 +121,6 @@ The class satisfies the following concept requirements:
|
|||||||
- [**json_pointer**](../json_pointer/index.md) - JSON Pointer implementation
|
- [**json_pointer**](../json_pointer/index.md) - JSON Pointer implementation
|
||||||
- [**json_serializer**](json_serializer.md) - type of the serializer to for conversions from/to JSON
|
- [**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
|
- [**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
|
- [**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
|
- **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
|
- [**input_format_t**](input_format_t.md) - type to choose the format to parse
|
||||||
|
|||||||
@@ -39,33 +39,13 @@ Basic guarantee: if an exception is thrown during the operation, the JSON value
|
|||||||
|
|
||||||
## Complexity
|
## Complexity
|
||||||
|
|
||||||
Linear in the total number of values (including nested ones) in `apply_patch`, times the cost of a key-based object
|
Linear in the lengths of `apply_patch`.
|
||||||
operation (looking up, adding, or erasing a member): logarithmic for [`json`](../json.md), and linear for
|
|
||||||
[`ordered_json`](../ordered_json.md) (see [`ordered_map` complexity](../ordered_map.md#complexity)). For
|
|
||||||
`ordered_json`, patching an object that has `n` members with a patch that has `m` members therefore takes O(n·m). The
|
|
||||||
cost also includes one copy of `apply_patch` (see the notes below).
|
|
||||||
|
|
||||||
## Notes
|
## Notes
|
||||||
|
|
||||||
- `apply_patch` may be `#!cpp *this` itself or refer to a value contained in `#!cpp *this` (for example, a subobject
|
`apply_patch` may be `#!cpp *this` itself or refer to a value contained in `#!cpp *this` (for example, a subobject
|
||||||
returned by `#!cpp (*this)[key]`); it is read as it was when `merge_patch()` was called, before any modification of
|
returned by `#!cpp (*this)[key]`); it is read as it was when `merge_patch()` was called, before any modification of
|
||||||
`#!cpp *this`. To make this possible, the function copies `apply_patch` before it modifies `#!cpp *this`, so the cost
|
`#!cpp *this`.
|
||||||
includes one copy of the patch.
|
|
||||||
- A merge patch uses `#!json null` to remove a member, so it cannot set a member to `#!json null`: applying
|
|
||||||
`#!json {"a":null}` to `#!json {"a":1}` gives `#!json {}`.
|
|
||||||
- Arrays are not merged: an array in the patch replaces the target value as a whole, and a `#!json null` inside an
|
|
||||||
array is kept as an element. `#!json null` members of the target that the patch does not mention are preserved.
|
|
||||||
- A `#!json null` in the patch only removes a member; it does not prevent the creation of the enclosing objects.
|
|
||||||
Applying `#!json {"a":{"b":null}}` to `#!json {}` gives `#!json {"a":{}}` (see example 15 in Appendix A of the RFC).
|
|
||||||
- If `apply_patch` is not an object, it replaces the target as a whole. In particular, a `#!json null` patch turns the
|
|
||||||
target into `#!json null`. If `apply_patch` is an object and the target is not, the target is first replaced by an
|
|
||||||
empty object, so applying `#!json {}` to `#!json 1` gives `#!json {}`.
|
|
||||||
- A merge patch cannot express every change; for example, it cannot reorder array elements or remove a specific array
|
|
||||||
element. Use [JSON Patch](../../features/json_patch.md) ([RFC 6902](https://tools.ietf.org/html/rfc6902)) for that.
|
|
||||||
[`merge_diff`](merge_diff.md) has a matching limitation, see its notes.
|
|
||||||
- A [discarded](is_discarded.md) value is treated like any other non-object value: a discarded
|
|
||||||
`apply_patch` turns the target into a discarded value, and an object patch replaces a discarded target by an object
|
|
||||||
as described above.
|
|
||||||
|
|
||||||
## Examples
|
## Examples
|
||||||
|
|
||||||
|
|||||||
@@ -137,13 +137,10 @@ Strong exception safety: if an exception occurs, the original value stays intact
|
|||||||
|
|
||||||
When the JSON pointer traverses intermediate levels that don't exist at all yet (not just a missing
|
When the JSON pointer traverses intermediate levels that don't exist at all yet (not just a missing
|
||||||
leaf), each missing level is created as an array or an object depending on whether the corresponding
|
leaf), each missing level is created as an array or an object depending on whether the corresponding
|
||||||
pointer token is a valid array index: the token `0`, a sequence of digits that does not begin with `0`,
|
pointer token parses as a non-negative integer: a numeric token creates an array, a non-numeric token
|
||||||
or the token `-` creates an array, and every other token creates an object. For example, on an
|
creates an object. For example, on an initially `#!json null` value, `/foo/0/0/0` creates nested arrays,
|
||||||
initially `#!json null` value, `/foo/0/0/0` creates nested arrays, while `/foo/one/one/one` creates
|
while `/foo/one/one/one` creates nested objects. This is not specified by the JSON Pointer RFC; it is
|
||||||
nested objects. Tokens such as `01` or the empty token cannot be array indices (cf. RFC 6901, Sect. 4)
|
this library's own, intentional disambiguation rule. See also [JSON Pointer](../../features/json_pointer.md).
|
||||||
and therefore create objects, just as they would if the level already existed as an object. This is not
|
|
||||||
specified by the JSON Pointer RFC; it is this library's own, intentional disambiguation rule. See also
|
|
||||||
[JSON Pointer](../../features/json_pointer.md).
|
|
||||||
|
|
||||||
!!! warning "Deprecation"
|
!!! warning "Deprecation"
|
||||||
|
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ Strong guarantee: if an exception is thrown, there are no changes in the JSON va
|
|||||||
where an existing element is required (the "path" of "replace", the "from" of "move" and "copy"); example:
|
where an existing element is required (the "path" of "replace", the "from" of "move" and "copy"); example:
|
||||||
`"array index '-' (3) is out of range"`.
|
`"array index '-' (3) is out of range"`.
|
||||||
- Throws [`out_of_range.403`](../../home/exceptions.md#jsonexceptionout_of_range403) if a JSON pointer inside the patch
|
- Throws [`out_of_range.403`](../../home/exceptions.md#jsonexceptionout_of_range403) if a JSON pointer inside the patch
|
||||||
could not be resolved successfully in the current JSON value; example: `"key 'baz' not found"`.
|
could not be resolved successfully in the current JSON value; example: `"key baz not found"`.
|
||||||
- Throws [`out_of_range.404`](../../home/exceptions.md#jsonexceptionout_of_range404) if a reference token of a JSON
|
- Throws [`out_of_range.404`](../../home/exceptions.md#jsonexceptionout_of_range404) if a reference token of a JSON
|
||||||
pointer inside the patch cannot be resolved, e.g., `-` in a "remove" operation or `1a` for an array; example:
|
pointer inside the patch cannot be resolved, e.g., `-` in a "remove" operation or `1a` for an array; example:
|
||||||
`"unresolved reference token '-'"`.
|
`"unresolved reference token '-'"`.
|
||||||
@@ -53,10 +53,7 @@ Strong guarantee: if an exception is thrown, there are no changes in the JSON va
|
|||||||
- Throws [`out_of_range.414`](../../home/exceptions.md#jsonexceptionout_of_range414) if a "move" operation's "from"
|
- Throws [`out_of_range.414`](../../home/exceptions.md#jsonexceptionout_of_range414) if a "move" operation's "from"
|
||||||
location is a proper prefix of its "path" location.
|
location is a proper prefix of its "path" location.
|
||||||
- Throws [`other_error.501`](../../home/exceptions.md#jsonexceptionother_error501) if "test" operation was
|
- Throws [`other_error.501`](../../home/exceptions.md#jsonexceptionother_error501) if "test" operation was
|
||||||
unsuccessful. A "test" operation whose "path" does not exist is unsuccessful, too: the failed lookup is reported as a
|
unsuccessful.
|
||||||
failed test, even if the operation has no "value" member (which would otherwise be
|
|
||||||
[`parse_error.105`](../../home/exceptions.md#jsonexceptionparse_error105)). Which of the two errors is reported for
|
|
||||||
this combination depends on the order in which the operands of a comparison are evaluated, so do not rely on it.
|
|
||||||
|
|
||||||
## Complexity
|
## Complexity
|
||||||
|
|
||||||
@@ -68,10 +65,6 @@ the JSON value, the complexity can usually be neglected.
|
|||||||
The application of a patch is atomic: Either all operations succeed and the patched document is returned or an exception
|
The application of a patch is atomic: Either all operations succeed and the patched document is returned or an exception
|
||||||
is thrown. In any case, the original value is not changed: the patch is applied to a copy of the value.
|
is thrown. In any case, the original value is not changed: the patch is applied to a copy of the value.
|
||||||
|
|
||||||
Duplicate member names inside an operation object are resolved by the parser before the patch is applied (the last one
|
|
||||||
is kept, see [`object_t`](object_t.md#behavior)), so `#!json {"op": "add", "op": "remove", "path": "/a"}` is a
|
|
||||||
`remove` operation.
|
|
||||||
|
|
||||||
## Examples
|
## Examples
|
||||||
|
|
||||||
??? example "Example: apply a JSON patch"
|
??? example "Example: apply a JSON patch"
|
||||||
@@ -115,7 +108,6 @@ is kept, see [`object_t`](object_t.md#behavior)), so `#!json {"op": "add", "op":
|
|||||||
- Added in version 2.0.0.
|
- Added in version 2.0.0.
|
||||||
- Added [`out_of_range.411`](../../home/exceptions.md#jsonexceptionout_of_range411) and stopped relying on an internal assertion when an "add" operation's
|
- Added [`out_of_range.411`](../../home/exceptions.md#jsonexceptionout_of_range411) and stopped relying on an internal assertion when an "add" operation's
|
||||||
target location has a non-object/non-array parent in version 3.13.0.
|
target location has a non-object/non-array parent in version 3.13.0.
|
||||||
This includes a `null` parent, which was previously silently converted to an object, in version 3.13.0.
|
|
||||||
- Added [`out_of_range.413`](../../home/exceptions.md#jsonexceptionout_of_range413) and stopped silently ignoring a "remove" operation whose target
|
- Added [`out_of_range.413`](../../home/exceptions.md#jsonexceptionout_of_range413) and stopped silently ignoring a "remove" operation whose target
|
||||||
location has a non-object/non-array parent in version 3.13.0.
|
location has a non-object/non-array parent in version 3.13.0.
|
||||||
- Added [`out_of_range.414`](../../home/exceptions.md#jsonexceptionout_of_range414) and rejected a "move" operation whose "from" location is a proper
|
- Added [`out_of_range.414`](../../home/exceptions.md#jsonexceptionout_of_range414) and rejected a "move" operation whose "from" location is a proper
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ No guarantees, value may be corrupted by an unsuccessful patch operation.
|
|||||||
where an existing element is required (the "path" of "replace", the "from" of "move" and "copy"); example:
|
where an existing element is required (the "path" of "replace", the "from" of "move" and "copy"); example:
|
||||||
`"array index '-' (3) is out of range"`.
|
`"array index '-' (3) is out of range"`.
|
||||||
- Throws [`out_of_range.403`](../../home/exceptions.md#jsonexceptionout_of_range403) if a JSON pointer inside the patch
|
- Throws [`out_of_range.403`](../../home/exceptions.md#jsonexceptionout_of_range403) if a JSON pointer inside the patch
|
||||||
could not be resolved successfully in the current JSON value; example: `"key 'baz' not found"`.
|
could not be resolved successfully in the current JSON value; example: `"key baz not found"`.
|
||||||
- Throws [`out_of_range.404`](../../home/exceptions.md#jsonexceptionout_of_range404) if a reference token of a JSON
|
- Throws [`out_of_range.404`](../../home/exceptions.md#jsonexceptionout_of_range404) if a reference token of a JSON
|
||||||
pointer inside the patch cannot be resolved, e.g., `-` in a "remove" operation or `1a` for an array; example:
|
pointer inside the patch cannot be resolved, e.g., `-` in a "remove" operation or `1a` for an array; example:
|
||||||
`"unresolved reference token '-'"`.
|
`"unresolved reference token '-'"`.
|
||||||
@@ -49,10 +49,7 @@ No guarantees, value may be corrupted by an unsuccessful patch operation.
|
|||||||
- Throws [`out_of_range.414`](../../home/exceptions.md#jsonexceptionout_of_range414) if a "move" operation's "from"
|
- Throws [`out_of_range.414`](../../home/exceptions.md#jsonexceptionout_of_range414) if a "move" operation's "from"
|
||||||
location is a proper prefix of its "path" location.
|
location is a proper prefix of its "path" location.
|
||||||
- Throws [`other_error.501`](../../home/exceptions.md#jsonexceptionother_error501) if "test" operation was
|
- Throws [`other_error.501`](../../home/exceptions.md#jsonexceptionother_error501) if "test" operation was
|
||||||
unsuccessful. A "test" operation whose "path" does not exist is unsuccessful, too: the failed lookup is reported as a
|
unsuccessful.
|
||||||
failed test, even if the operation has no "value" member (which would otherwise be
|
|
||||||
[`parse_error.105`](../../home/exceptions.md#jsonexceptionparse_error105)). Which of the two errors is reported for
|
|
||||||
this combination depends on the order in which the operands of a comparison are evaluated, so do not rely on it.
|
|
||||||
|
|
||||||
## Complexity
|
## Complexity
|
||||||
|
|
||||||
@@ -65,20 +62,6 @@ Unlike [`patch`](patch.md), `patch_inplace` applies the operation "in place" and
|
|||||||
That makes it faster for large documents by avoiding the copy. However, the JSON value might be corrupted if the
|
That makes it faster for large documents by avoiding the copy. However, the JSON value might be corrupted if the
|
||||||
function throws an exception.
|
function throws an exception.
|
||||||
|
|
||||||
Duplicate member names inside an operation object are resolved by the parser before the patch is applied (the last one
|
|
||||||
is kept, see [`object_t`](object_t.md#behavior)), so `#!json {"op": "add", "op": "remove", "path": "/a"}` is a
|
|
||||||
`remove` operation.
|
|
||||||
|
|
||||||
The JSON patch may be the JSON value itself (`#!cpp j.patch_inplace(j)`): the operations are then read from a copy of
|
|
||||||
the patch made before the first operation is applied, so the result is the same as that of
|
|
||||||
`#!cpp j = j.patch(j)`, and the exception safety is the same as above.
|
|
||||||
|
|
||||||
!!! danger "Undefined behavior"
|
|
||||||
|
|
||||||
The JSON patch must not be a value stored inside the JSON value (e.g., `#!cpp j.patch_inplace(j["patch"])`), as the
|
|
||||||
operations may change or destroy it while it is read. Pass a copy (`#!cpp j.patch_inplace(json(j["patch"]))`) or use
|
|
||||||
[`patch`](patch.md) instead.
|
|
||||||
|
|
||||||
## Examples
|
## Examples
|
||||||
|
|
||||||
??? example "Example: apply a JSON patch in place"
|
??? example "Example: apply a JSON patch in place"
|
||||||
@@ -123,7 +106,6 @@ the patch made before the first operation is applied, so the result is the same
|
|||||||
- Added in version 3.11.0.
|
- Added in version 3.11.0.
|
||||||
- Added [`out_of_range.411`](../../home/exceptions.md#jsonexceptionout_of_range411) and stopped relying on an internal assertion when an "add" operation's
|
- Added [`out_of_range.411`](../../home/exceptions.md#jsonexceptionout_of_range411) and stopped relying on an internal assertion when an "add" operation's
|
||||||
target location has a non-object/non-array parent in version 3.13.0.
|
target location has a non-object/non-array parent in version 3.13.0.
|
||||||
This includes a `null` parent, which was previously silently converted to an object, in version 3.13.0.
|
|
||||||
- Added [`out_of_range.413`](../../home/exceptions.md#jsonexceptionout_of_range413) and stopped silently ignoring a "remove" operation whose target
|
- Added [`out_of_range.413`](../../home/exceptions.md#jsonexceptionout_of_range413) and stopped silently ignoring a "remove" operation whose target
|
||||||
location has a non-object/non-array parent in version 3.13.0.
|
location has a non-object/non-array parent in version 3.13.0.
|
||||||
- Added [`out_of_range.414`](../../home/exceptions.md#jsonexceptionout_of_range414) and rejected a "move" operation whose "from" location is a proper
|
- Added [`out_of_range.414`](../../home/exceptions.md#jsonexceptionout_of_range414) and rejected a "move" operation whose "from" location is a proper
|
||||||
@@ -131,4 +113,3 @@ the patch made before the first operation is applied, so the result is the same
|
|||||||
- Throws [`parse_error.109`](../../home/exceptions.md#jsonexceptionparse_error109) instead of
|
- 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
|
[`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.
|
not a digit (e.g., `/x`) in version 3.13.0, as it already did for longer ones.
|
||||||
- Applying a JSON value as patch to itself no longer results in undefined behavior in version 3.13.0.
|
|
||||||
@@ -104,7 +104,9 @@ The SAX event lister must follow the interface of [`json_sax`](../json_sax/index
|
|||||||
|
|
||||||
## Return value
|
## Return value
|
||||||
|
|
||||||
return value of the last processed SAX event
|
`#!cpp true` if the input was parsed without errors and no SAX event returned `#!cpp false`; `#!cpp false` otherwise.
|
||||||
|
In particular, the result is `#!cpp false` for input with errors, even if the SAX parser recovered from all of them
|
||||||
|
(see [error recovery](../../features/parsing/error_recovery.md)).
|
||||||
|
|
||||||
## Exception safety
|
## Exception safety
|
||||||
|
|
||||||
@@ -161,6 +163,7 @@ use the same file with stdio functions, but it must not wait for another thread
|
|||||||
- Added `ignore_trailing_commas` in version 3.13.0.
|
- Added `ignore_trailing_commas` in version 3.13.0.
|
||||||
- Added `tag_handler` in version 3.13.0.
|
- Added `tag_handler` in version 3.13.0.
|
||||||
- Extended container support (1) to include types with lvalue-only ADL `begin`/`end` (matching `std::begin`/`std::end` semantics) in version 3.13.0.
|
- Extended container support (1) to include types with lvalue-only ADL `begin`/`end` (matching `std::begin`/`std::end` semantics) in version 3.13.0.
|
||||||
|
- Recovering from parse errors (see [`parse_error`](../json_sax/parse_error.md)) added in version 3.13.0.
|
||||||
- Extended overload (2) to accept heterogeneous iterator+sentinel pairs (C++20 ranges support) in version 3.13.0.
|
- Extended overload (2) to accept heterogeneous iterator+sentinel pairs (C++20 ranges support) in version 3.13.0.
|
||||||
- `JSON_PRECISE_STREAM_POSITION` added in version 3.13.0 to optionally leave a `#!cpp std::istream` positioned right
|
- `JSON_PRECISE_STREAM_POSITION` added in version 3.13.0 to optionally leave a `#!cpp std::istream` positioned right
|
||||||
after the parsed value when `strict` is `#!cpp false`.
|
after the parsed value when `strict` is `#!cpp false`.
|
||||||
|
|||||||
@@ -43,8 +43,7 @@ The exact mapping and its limitations are described on a [dedicated page](../../
|
|||||||
`#!cpp false` by default.
|
`#!cpp false` by default.
|
||||||
|
|
||||||
`version` (in)
|
`version` (in)
|
||||||
: which version of BJData to use, see [`bjdata_version_t`](bjdata_version_t.md) and the note on "Binary values" on
|
: which version of BJData to use (see note on "Binary values" on [BJData](../../features/binary_formats/bjdata.md));
|
||||||
[BJData](../../features/binary_formats/bjdata.md);
|
|
||||||
optional, `#!cpp bjdata_version_t::draft2` by default.
|
optional, `#!cpp bjdata_version_t::draft2` by default.
|
||||||
|
|
||||||
`error_handler` (in)
|
`error_handler` (in)
|
||||||
@@ -65,9 +64,7 @@ Strong guarantee: if an exception is thrown, there are no changes in the JSON va
|
|||||||
## Exceptions
|
## Exceptions
|
||||||
|
|
||||||
- Throws [`other_error.502`](../../home/exceptions.md#jsonexceptionother_error502) if `use_type` is true and `use_size`
|
- 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
|
is false, and `j` contains a non-empty array, object, or binary value.
|
||||||
`version = bjdata_version_t::draft3`, any binary value, including an empty one).
|
|
||||||
Scalars, empty arrays, and empty objects do not throw.
|
|
||||||
- Throws [type_error.316](../../home/exceptions.md#jsonexceptiontype_error316) if a string or object key in `j` is
|
- 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
|
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)
|
[`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
|
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.
|
1. Returns a byte vector containing the BSON serialization.
|
||||||
2. Writes the BSON serialization to an output adapter.
|
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
|
## Exception safety
|
||||||
|
|
||||||
Strong guarantee: if an exception is thrown, there are no changes in the JSON value. Bytes that were already written to
|
Strong guarantee: if an exception is thrown, there are no changes in the JSON value.
|
||||||
the output adapter are not taken back.
|
|
||||||
|
|
||||||
## Exceptions
|
## 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:
|
value, array, or object exceeds 4294967295, the maximum MessagePack can store; example:
|
||||||
`"MessagePack length 4294967296 exceeds maximum of 4294967295"`
|
`"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
|
- 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)"`
|
`"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
|
- 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`
|
not valid UTF-8 and `error_handler` is `strict`
|
||||||
|
|||||||
@@ -36,9 +36,9 @@ The function can throw the following exceptions:
|
|||||||
- Throws [`parse_error.109`](../../home/exceptions.md#jsonexceptionparse_error109) if an array index in a key is not a
|
- Throws [`parse_error.109`](../../home/exceptions.md#jsonexceptionparse_error109) if an array index in a key is not a
|
||||||
number; example: `"array index 'one' is not a number"`
|
number; example: `"array index 'one' is not a number"`
|
||||||
- Throws [`out_of_range.404`](../../home/exceptions.md#jsonexceptionout_of_range404) if a level becomes an array
|
- Throws [`out_of_range.404`](../../home/exceptions.md#jsonexceptionout_of_range404) if a level becomes an array
|
||||||
(because one of its keys is `0`) and another key at that level is empty (as in `/a/`), is `-`, or begins with a digit
|
(because one of its keys is `0`) and another key at that level begins with a digit but is not a valid array index
|
||||||
but is not a valid array index (such as `1a`); examples: `"unresolved reference token '-'"`,
|
(such as `1a`), or is `-`; example:
|
||||||
`"unresolved reference token ''"`
|
`"unresolved reference token '-'"`
|
||||||
|
|
||||||
## Complexity
|
## Complexity
|
||||||
|
|
||||||
@@ -46,7 +46,7 @@ Linear in the size of the JSON value.
|
|||||||
|
|
||||||
## Notes
|
## Notes
|
||||||
|
|
||||||
Empty objects and arrays are flattened by [`flatten()`](flatten.md) to `#!json null` values and cannot be unflattened to
|
Empty objects and arrays are flattened by [`flatten()`](flatten.md) to `#!json null` values and cannot unflattened to
|
||||||
their original type.
|
their original type.
|
||||||
|
|
||||||
A flattened array and a flattened object whose keys are array indices are indistinguishable, because both are
|
A flattened array and a flattened object whose keys are array indices are indistinguishable, because both are
|
||||||
@@ -54,12 +54,7 @@ described by the same JSON pointers. A value is therefore restored as an array i
|
|||||||
reference token `0`, and as an object otherwise: `#!json {"2": 1}` is restored unchanged, whereas `#!json {"0": 1}` is
|
reference token `0`, and as an object otherwise: `#!json {"2": 1}` is restored unchanged, whereas `#!json {"0": 1}` is
|
||||||
restored as `#!json [1]`. This decision does not depend on the order in which the flattened object is iterated.
|
restored as `#!json [1]`. This decision does not depend on the order in which the flattened object is iterated.
|
||||||
|
|
||||||
A third case is an object that has the key `0` next to a key that is not a valid array index: `#!json {"0": 1, "b": 2}`
|
Apart from these two cases, for a JSON value `j`, the following is always true:
|
||||||
is flattened to `#!json {"/0": 1, "/b": 2}`, and unflatten treats the level as an array and throws
|
|
||||||
[`parse_error.109`](../../home/exceptions.md#jsonexceptionparse_error109) because `b` is not a number. (For the keys
|
|
||||||
`-`, `1a`, or the empty key instead of `b`, it throws [`out_of_range.404`](../../home/exceptions.md#jsonexceptionout_of_range404).)
|
|
||||||
|
|
||||||
Apart from these three cases, for a JSON value `j`, the following is always true:
|
|
||||||
`#!cpp j == j.flatten().unflatten()`.
|
`#!cpp j == j.flatten().unflatten()`.
|
||||||
|
|
||||||
## Examples
|
## Examples
|
||||||
|
|||||||
@@ -45,9 +45,6 @@ This is equivalent to Python's `dict.get(key, default)`.
|
|||||||
return default_value;
|
return default_value;
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
with one exception: if the JSON value is neither an array nor an object, the function throws
|
|
||||||
[`type_error.306`](../../home/exceptions.md#jsonexceptiontype_error306) before looking at `ptr`, even for the empty
|
|
||||||
pointer, whereas `at` returns the value itself for the empty pointer.
|
|
||||||
|
|
||||||
!!! note "Differences to `at` and `operator[]`"
|
!!! note "Differences to `at` and `operator[]`"
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ void erase(view_type array, I idx);
|
|||||||
std::size_t erase(const json_pointer& ptr);
|
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`).
|
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
|
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>
|
<small>Defined in header `<nlohmann/json_view.hpp>`</small>
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
template<typename BasicJsonType, view_mode Mode = view_mode::read_only>
|
template<typename BasicJsonType, bool Editable = false>
|
||||||
class basic_json_document;
|
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
|
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.
|
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
|
[`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`).
|
bookkeeping edits need, and calling any of them on one fails to compile (`#!cpp static_assert`).
|
||||||
|
|
||||||
## Template parameters
|
## 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
|
[`ordered_json`](../ordered_json.md). Only 64-bit `number_integer_t`/`number_unsigned_t` types are supported; this
|
||||||
is checked with a `static_assert`.
|
is checked with a `static_assert`.
|
||||||
|
|
||||||
`Mode`
|
`Editable`
|
||||||
: a [`view_mode`](../view_mode.md): `#!cpp view_mode::editable` if the document supports [`set`](set.md),
|
: whether the document supports [`set`](set.md), [`push_back`](push_back.md), [`insert`](insert.md), and
|
||||||
[`push_back`](push_back.md), [`insert`](insert.md), and [`erase`](erase.md) (optional, `#!cpp view_mode::read_only`
|
[`erase`](erase.md) (optional, `#!cpp false` by default). See [Edits](#edits) below.
|
||||||
by default). See [Edits](#edits) below.
|
|
||||||
|
|
||||||
## Specializations
|
## Specializations
|
||||||
|
|
||||||
@@ -48,7 +47,7 @@ bookkeeping edits need, and calling any of them on one fails to compile (`#!cpp
|
|||||||
|
|
||||||
## Member types
|
## 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)
|
- **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)
|
- **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
|
### Edits
|
||||||
|
|
||||||
- [**set**](set.md) - replace a value, or set an object member, an array element, or the value a JSON pointer refers
|
- [**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)
|
to (`#!cpp Editable` documents only)
|
||||||
- [**push_back**](push_back.md) - append to an array (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 (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
|
- [**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
|
## 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);
|
[`push_back`](push_back.md), [`insert`](insert.md), and [`erase`](erase.md);
|
||||||
[`json_editable_document`](../json_editable_document.md) and
|
[`json_editable_document`](../json_editable_document.md) and
|
||||||
[`ordered_json_editable_document`](../ordered_json_editable_document.md) are the corresponding specializations. A few
|
[`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);
|
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`).
|
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
|
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
|
## 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`:
|
`save()` could have written, or fails the requested `check`:
|
||||||
|
|
||||||
| message | when |
|
| message | when |
|
||||||
@@ -92,9 +95,6 @@ are checked once, however many nodes refer to it.
|
|||||||
|
|
||||||
## Notes
|
## 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 }
|
### `image_check` { #image_check }
|
||||||
|
|
||||||
```cpp
|
```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,
|
source document afterward; a `BasicJsonType` value; or anything `BasicJsonType` can be constructed from (numbers,
|
||||||
strings, `#!cpp bool`, `#!cpp nullptr`, containers, ...).
|
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`).
|
has `push_back`; calling it on a read-only `basic_json_document` fails to compile (`#!cpp static_assert`).
|
||||||
|
|
||||||
## Template parameters
|
## 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
|
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)
|
[`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
|
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.
|
values only, not which specialization produced them.
|
||||||
|
|
||||||
## Return value
|
## 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)/
|
[discarded](is_discarded.md) -- a default-constructed document, or one a failed [`parse()`](parse.md)/
|
||||||
[`read()`](read.md) with `allow_exceptions == false` left discarded.
|
[`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
|
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
|
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.
|
[`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] 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
|
[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
|
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.
|
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
|
**Little-endian only.** The image is written as raw little-endian bytes, with no byte-swapping. `save()` (and
|
||||||
big-endian target, `save()` and [`load`](load.md) do not exist: a call fails to compile rather than produce bytes a
|
[`load`](load.md)) throw `type_error.320` on a big-endian target rather than silently produce bytes a big-endian
|
||||||
big-endian reader could not interpret correctly.
|
reader could not interpret correctly.
|
||||||
|
|
||||||
## Examples
|
## Examples
|
||||||
|
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ template<typename V>
|
|||||||
view_type set(const json_pointer& ptr, V&& value);
|
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`).
|
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. Replaces the value `target` refers to with `value`.
|
||||||
|
|||||||
@@ -23,10 +23,6 @@ Linear in [`node_count()`](node_count.md) plus the length of the decoded strings
|
|||||||
|
|
||||||
## Notes
|
## Notes
|
||||||
|
|
||||||
The node index of a small document (an estimate of up to 1024 nodes, which is up to about 4 KiB of minified text) is
|
|
||||||
allocated together with the document's header, so that parsing needs one allocation. That part cannot be released
|
|
||||||
separately: `shrink_to_fit()` only trims a node index that has its own allocation, and the decoded strings.
|
|
||||||
|
|
||||||
!!! warning "Invalidates views"
|
!!! warning "Invalidates views"
|
||||||
|
|
||||||
Unlike moving the document, `shrink_to_fit()` **invalidates every view taken from this document before the
|
Unlike moving the document, `shrink_to_fit()` **invalidates every view taken from this document before the
|
||||||
|
|||||||
@@ -1,32 +1,20 @@
|
|||||||
# <small>nlohmann::basic_json_view::</small>basic_json_view
|
# <small>nlohmann::basic_json_view::</small>basic_json_view
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
// (1)
|
|
||||||
basic_json_view() noexcept = default;
|
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
|
Creates an invalid (discarded) view: [`type()`](type.md) is `#!cpp value_t::discarded` and
|
||||||
[`is_discarded()`](is_discarded.md) is `#!cpp true`.
|
[`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.
|
|
||||||
|
|
||||||
## Parameters
|
This is the only constructor a caller can use directly. Every other view is obtained from a
|
||||||
|
|
||||||
`other` (in)
|
|
||||||
: a view of a read-only document with the same `BasicJsonType`
|
|
||||||
|
|
||||||
Apart from these, a view is obtained from a
|
|
||||||
[`basic_json_document`](../basic_json_document/index.md), via [`root()`](../basic_json_document/root.md) or by
|
[`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),
|
navigating into a container with [`operator[]`](operator[].md), [`at`](at.md), [`front`](front.md), [`back`](back.md),
|
||||||
[`find`](find.md), or iteration.
|
[`find`](find.md), or iteration.
|
||||||
|
|
||||||
## Exception safety
|
## Exception safety
|
||||||
|
|
||||||
No-throw guarantee: these constructors never throw exceptions.
|
No-throw guarantee: this constructor never throws exceptions.
|
||||||
|
|
||||||
## Complexity
|
## 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
|
- [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
|
- [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
|
## 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))
|
document's own buffer of decoded strings (see [`get_string()`](get_string.md))
|
||||||
- `BasicJsonType` -- equivalent to [`materialize()`](materialize.md)
|
- `BasicJsonType` -- equivalent to [`materialize()`](materialize.md)
|
||||||
- `basic_json_view` -- returns `#!cpp *this`
|
- `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 std::vector<U, A>` -- from an array, element by element, each converted with `#!cpp get<U>()`; `#!cpp
|
||||||
`#!cpp get<U>()`; `#!cpp std::vector<basic_json_view>` keeps a view of every element instead of a value
|
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
|
- `#!cpp std::map<K, V, C, A>` and `#!cpp std::unordered_map<K, V, H, E, A>`, if `K` is constructible from a `#!cpp
|
||||||
constructible from a `#!cpp (const char*, std::size_t)` pair -- views of the members of an object; with a repeated
|
(const char*, std::size_t)` pair -- from an object, member by member, each value converted with `#!cpp get<V>()`; with a repeated
|
||||||
key, the view of the *last* member is kept, as [`BasicJsonType::parse()`](../basic_json/parse.md) keeps its value
|
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
|
Every other `T` -- `#!cpp std::list`, `#!cpp std::pair`, `#!cpp std::array`, enumerations, user types with a
|
||||||
`BasicJsonType` value. This covers the library's own conversions of the standard library types -- all other
|
`from_json()`, ... -- is converted by `#!cpp materialize().get<T>()`: the subtree is built into a real `BasicJsonType`
|
||||||
`#!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`
|
|
||||||
value first (as [`BasicJsonType::parse()`](../basic_json/parse.md) would), and converted from there exactly as
|
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.
|
[`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`.
|
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
|
- 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.
|
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 `#!cpp std::map`/`#!cpp std::unordered_map`: throws `type_error.302` if the value is not an object; otherwise,
|
||||||
- For a `T` whose `from_json()` reads the view: whatever that `from_json()` throws; for the library's conversions and
|
whatever converting a member to the mapped type throws.
|
||||||
the macros, the same exceptions with the same messages as [`BasicJsonType::get<T>()`](../basic_json/get.md) of the
|
|
||||||
same value.
|
|
||||||
- For every other `T`: whatever [`materialize().get<T>()`](../basic_json/get.md) throws -- typically `type_error.302`,
|
- 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.
|
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
|
None of the exceptions thrown directly by this function (the first three bullets above) carry a
|
||||||
bullets above) carry a
|
|
||||||
[`JSON_DIAGNOSTICS`](../macros/json_diagnostics.md) path: the view has no `BasicJsonType` value to point at. An
|
[`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
|
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.
|
`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
|
- `#!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
|
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.
|
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
|
- 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).
|
afterwards, plus that of [`BasicJsonType::get<T>()`](../basic_json/get.md).
|
||||||
|
|
||||||
|
|||||||
@@ -5,13 +5,12 @@ template<typename T>
|
|||||||
T& get_to(T& v) const;
|
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`,
|
- 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`,
|
`#!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>()`.
|
`basic_json_view`, `#!cpp std::vector`, and `#!cpp std::map`/`#!cpp std::unordered_map` with string keys -- `v` is
|
||||||
- For a type whose `from_json()` accepts views (see [`get<T>()`](get.md)), that `from_json()` is called with the
|
assigned: `#!cpp v = get<T>()`.
|
||||||
view and the existing `v`, without building a `BasicJsonType` value.
|
|
||||||
- For every other type, the subtree is built into a `BasicJsonType` value and `#!cpp materialize().get_to(v)` is
|
- 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
|
called, i.e. `from_json()` is invoked with the existing `v`, exactly as
|
||||||
[`BasicJsonType::get_to()`](../basic_json/get_to.md) does.
|
[`BasicJsonType::get_to()`](../basic_json/get_to.md) does.
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
<small>Defined in header `<nlohmann/json_view.hpp>`</small>
|
<small>Defined in header `<nlohmann/json_view.hpp>`</small>
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
template<typename BasicJsonType, view_mode Mode = view_mode::read_only>
|
template<typename BasicJsonType, bool Editable = false>
|
||||||
class basic_json_view;
|
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).
|
`#!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
|
`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::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
|
[`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
|
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
|
: a specialization of [`basic_json`](../basic_json/index.md), matching the
|
||||||
[`basic_json_document`](../basic_json_document/index.md) the view was taken from.
|
[`basic_json_document`](../basic_json_document/index.md) the view was taken from.
|
||||||
|
|
||||||
`Mode`
|
`Editable`
|
||||||
: a [`view_mode`](../view_mode.md): whether the view is of an editable document, matching the
|
: whether the view is of an editable document, matching the [`basic_json_document`](../basic_json_document/index.md)
|
||||||
[`basic_json_document`](../basic_json_document/index.md) it was taken from (optional, `#!cpp view_mode::read_only` by
|
it was taken from (optional, `#!cpp false` by default). See [Edits](../basic_json_document/index.md#edits).
|
||||||
default). See [Edits](../basic_json_document/index.md#edits).
|
|
||||||
|
|
||||||
## Specializations
|
## Specializations
|
||||||
|
|
||||||
@@ -64,7 +63,6 @@ still refers to it -- including ones taken before the change -- reads the new va
|
|||||||
|
|
||||||
## Member types
|
## 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)
|
- **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
|
- **string_t**, **number_integer_t**, **number_unsigned_t**, **number_float_t**, **json_pointer** - the corresponding
|
||||||
member types of `BasicJsonType`
|
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
|
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.
|
specific naming scheme in order to override the binary type.
|
||||||
|
|
||||||
## Template parameters
|
## 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>
|
<small>Defined in header `<nlohmann/json_view.hpp>`</small>
|
||||||
|
|
||||||
```cpp
|
```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)
|
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>
|
<small>Defined in header `<nlohmann/json_view.hpp>`</small>
|
||||||
|
|
||||||
```cpp
|
```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
|
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>
|
<small>Defined in header `<nlohmann/json_view.hpp>`</small>
|
||||||
|
|
||||||
```cpp
|
```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
|
This type is a [`basic_json_view`](basic_json_view/index.md) of a value of a
|
||||||
|
|||||||
@@ -18,8 +18,7 @@ json_pointer& operator/=(std::size_t array_idx)
|
|||||||
## Parameters
|
## Parameters
|
||||||
|
|
||||||
`ptr` (in)
|
`ptr` (in)
|
||||||
: JSON pointer to append; may be the JSON pointer itself (`#!cpp p /= p`), which then appends a copy of its
|
: JSON pointer to append
|
||||||
reference tokens
|
|
||||||
|
|
||||||
`token` (in)
|
`token` (in)
|
||||||
: reference token to append
|
: reference token to append
|
||||||
@@ -69,7 +68,6 @@ json_pointer& operator/=(std::size_t array_idx)
|
|||||||
|
|
||||||
## Version history
|
## Version history
|
||||||
|
|
||||||
1. Added in version 3.6.0. Appending a JSON pointer to itself no longer results in undefined behavior in version
|
1. Added in version 3.6.0.
|
||||||
3.13.0.
|
|
||||||
2. Added in version 3.6.0. Changed type of `token` to `string_t` in version 3.11.0.
|
2. Added in version 3.6.0. Changed type of `token` to `string_t` in version 3.11.0.
|
||||||
3. Added in version 3.6.0.
|
3. Added in version 3.6.0.
|
||||||
@@ -12,8 +12,7 @@ Parent of this JSON pointer; in case this JSON pointer is the root, the root its
|
|||||||
|
|
||||||
## Exception safety
|
## Exception safety
|
||||||
|
|
||||||
Strong exception safety: if an exception occurs, the original value stays intact. The function is not `#!cpp noexcept`
|
No-throw guarantee: this function never throws exceptions.
|
||||||
and allocates a new JSON pointer, so it can throw `#!cpp std::bad_alloc`; it throws no library exceptions.
|
|
||||||
|
|
||||||
## Complexity
|
## Complexity
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,8 @@ struct json_sax;
|
|||||||
|
|
||||||
This class describes the SAX interface used by [sax_parse](../basic_json/sax_parse.md). Each function is called in
|
This class describes the SAX interface used by [sax_parse](../basic_json/sax_parse.md). Each function is called in
|
||||||
different situations while the input is parsed. The boolean return value informs the parser whether to continue
|
different situations while the input is parsed. The boolean return value informs the parser whether to continue
|
||||||
processing the input.
|
processing the input; for [`parse_error`](parse_error.md), it decides whether to
|
||||||
|
[recover from the error](../../features/parsing/error_recovery.md).
|
||||||
|
|
||||||
For instance, parsing the JSON text `{"a": [1, true]}` triggers the following callbacks, in order:
|
For instance, parsing the JSON text `{"a": [1, true]}` triggers the following callbacks, in order:
|
||||||
|
|
||||||
|
|||||||
@@ -21,11 +21,18 @@ A parse error occurred.
|
|||||||
|
|
||||||
## Return value
|
## Return value
|
||||||
|
|
||||||
Whether parsing should proceed (**must return `#!cpp false`**).
|
Whether to recover from the error:
|
||||||
|
|
||||||
|
- `#!cpp false` stops parsing.
|
||||||
|
- `#!cpp true` recovers from the error: the error is repaired and parsing continues. If that is not possible, which
|
||||||
|
happens in the binary formats when the end of the item with the error is unknown, the value read so far is completed
|
||||||
|
and parsing stops. See [error recovery](../../features/parsing/error_recovery.md) for how errors are repaired.
|
||||||
|
|
||||||
|
Either way, [`sax_parse`](../basic_json/sax_parse.md) returns `#!cpp false`.
|
||||||
|
|
||||||
## Examples
|
## Examples
|
||||||
|
|
||||||
??? example
|
??? example "Example: (1) the SAX interface"
|
||||||
|
|
||||||
The example below shows how the SAX interface is used.
|
The example below shows how the SAX interface is used.
|
||||||
|
|
||||||
@@ -39,12 +46,29 @@ Whether parsing should proceed (**must return `#!cpp false`**).
|
|||||||
--8<-- "examples/sax_parse.output"
|
--8<-- "examples/sax_parse.output"
|
||||||
```
|
```
|
||||||
|
|
||||||
|
??? example "Example: (2) recovering from errors"
|
||||||
|
|
||||||
|
The example below shows how a SAX parser recovers from errors.
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
--8<-- "examples/sax_parse__error_recovery.cpp"
|
||||||
|
```
|
||||||
|
|
||||||
|
Output:
|
||||||
|
|
||||||
|
```
|
||||||
|
--8<-- "examples/sax_parse__error_recovery.output"
|
||||||
|
```
|
||||||
|
|
||||||
## See also
|
## See also
|
||||||
|
|
||||||
- [sax_parse](../basic_json/sax_parse.md) - SAX parser
|
- [sax_parse](../basic_json/sax_parse.md) - SAX parser
|
||||||
- [Parsing and Exceptions](../../features/parsing/parse_exceptions.md) - the article on handling parse errors without
|
- [Parsing and Exceptions](../../features/parsing/parse_exceptions.md) - the article on handling parse errors without
|
||||||
exceptions
|
exceptions
|
||||||
|
- [Error Recovery](../../features/parsing/error_recovery.md) - the article on recovering from parse errors
|
||||||
|
|
||||||
## Version history
|
## Version history
|
||||||
|
|
||||||
- Added in version 3.2.0.
|
- Added in version 3.2.0.
|
||||||
|
- Returning `#!cpp true` recovers from the error since version 3.13.0; before, parsing stopped, but the result of
|
||||||
|
[`sax_parse`](../basic_json/sax_parse.md) could be wrong.
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
<small>Defined in header `<nlohmann/json_view.hpp>`</small>
|
<small>Defined in header `<nlohmann/json_view.hpp>`</small>
|
||||||
|
|
||||||
```cpp
|
```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).
|
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_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_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_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
|
## Library version
|
||||||
|
|
||||||
|
|||||||
@@ -5,8 +5,7 @@
|
|||||||
```
|
```
|
||||||
|
|
||||||
When defined, the library uses only portable C++ code where it would otherwise use vector instructions: when scanning
|
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
|
strings during parsing, and when writing floating-point numbers during serialization.
|
||||||
[`basic_json_document`](../basic_json_document/index.md) (`<nlohmann/json_view.hpp>`).
|
|
||||||
|
|
||||||
The macro is an escape hatch, for example for toolchains that cannot compile the vector code, for sanitizers or
|
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,
|
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_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
|
- [**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)
|
- [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
|
## 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
|
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.
|
[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
|
## Examples
|
||||||
|
|
||||||
??? example "Example: (1) NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE"
|
??? 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.
|
6. Added in version 3.12.0.
|
||||||
|
|
||||||
All six macros were changed to allow an empty member list in version 3.13.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
|
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.
|
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
|
## Examples
|
||||||
|
|
||||||
??? example "Example: (1) NLOHMANN_DEFINE_TYPE_INTRUSIVE"
|
??? 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,
|
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.
|
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
|
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.
|
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
|
## Examples
|
||||||
|
|
||||||
??? example "Example: (1) NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE"
|
??? 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,
|
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.
|
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
|
## Version history
|
||||||
|
|
||||||
- Added in version 3.11.0. Changed inline namespace name in version 3.11.2. Added the ABI tag `_dp` in
|
- 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.12.0, and the ABI tags `_bics`, `_psp`, `_snul`, `_sbu8`, `_ekmo`, `_dsbs`, `_dufio`, `_ns`, `_vns`,
|
||||||
version 3.13.0; see
|
and `_vssse3` in version 3.13.0; see
|
||||||
[`nlohmann` Namespace](../../features/namespace.md#structure).
|
[`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
|
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.
|
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
|
## Examples
|
||||||
|
|
||||||
??? example "Example: Basic usage"
|
??? example "Example: Basic usage"
|
||||||
@@ -94,5 +88,3 @@ inline void from_json(const BasicJsonType& j, type& e);
|
|||||||
## Version history
|
## Version history
|
||||||
|
|
||||||
Added in version 3.4.0.
|
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
|
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.
|
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
|
## Examples
|
||||||
|
|
||||||
??? example "Example: Basic usage"
|
??? example "Example: Basic usage"
|
||||||
|
|||||||
@@ -37,8 +37,7 @@ the stream `o`
|
|||||||
1. Throws [`type_error.316`](../home/exceptions.md#jsonexceptiontype_error316) if a string stored inside the JSON
|
1. Throws [`type_error.316`](../home/exceptions.md#jsonexceptiontype_error316) if a string stored inside the JSON
|
||||||
value is not UTF-8 encoded. Note that unlike the [`dump`](basic_json/dump.md) member functions, no `error_handler`
|
value is not UTF-8 encoded. Note that unlike the [`dump`](basic_json/dump.md) member functions, no `error_handler`
|
||||||
can be set.
|
can be set.
|
||||||
2. Throws no library exceptions. As the string representation is built with [`to_string`](json_pointer/to_string.md),
|
2. None.
|
||||||
`#!cpp std::bad_alloc` is possible.
|
|
||||||
|
|
||||||
## Complexity
|
## Complexity
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
<small>Defined in header `<nlohmann/json_view.hpp>`</small>
|
<small>Defined in header `<nlohmann/json_view.hpp>`</small>
|
||||||
|
|
||||||
```cpp
|
```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)
|
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>
|
<small>Defined in header `<nlohmann/json_view.hpp>`</small>
|
||||||
|
|
||||||
```cpp
|
```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
|
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>
|
<small>Defined in header `<nlohmann/json_view.hpp>`</small>
|
||||||
|
|
||||||
```cpp
|
```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
|
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>
|
<small>Defined in header `<nlohmann/json_view.hpp>`</small>
|
||||||
|
|
||||||
```cpp
|
```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
|
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()
|
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})");
|
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
|
doc.set(doc.root(), "b", 4); // set() always appends a new member at the end
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,43 @@
|
|||||||
|
#include <iostream>
|
||||||
|
#include <iomanip>
|
||||||
|
#include <nlohmann/json.hpp>
|
||||||
|
|
||||||
|
using json = nlohmann::json;
|
||||||
|
|
||||||
|
// a SAX parser that creates a JSON value like json::parse does, but that
|
||||||
|
// recovers from parse errors instead of stopping at the first one
|
||||||
|
class recovering_parser : public nlohmann::detail::json_sax_dom_parser<json>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit recovering_parser(json& result)
|
||||||
|
: nlohmann::detail::json_sax_dom_parser<json>(result, false)
|
||||||
|
{}
|
||||||
|
|
||||||
|
bool parse_error(std::size_t position,
|
||||||
|
const std::string& /*last_token*/,
|
||||||
|
const json::exception& ex)
|
||||||
|
{
|
||||||
|
std::cout << "byte " << position << ": " << ex.what() << '\n';
|
||||||
|
|
||||||
|
// repair the input and continue
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
// JSON text with several mistakes that ends too early
|
||||||
|
const std::string text = R"({
|
||||||
|
"name": "Hello World",
|
||||||
|
"tags": ["a" "b",],
|
||||||
|
"valid": tru,
|
||||||
|
"size": 1.,
|
||||||
|
"nested": {"x": 1)";
|
||||||
|
|
||||||
|
json result;
|
||||||
|
recovering_parser sax(result);
|
||||||
|
const bool valid = json::sax_parse(text, &sax);
|
||||||
|
|
||||||
|
std::cout << "\nvalid JSON: " << std::boolalpha << valid << '\n'
|
||||||
|
<< std::setw(4) << result << std::endl;
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
byte 49: [json.exception.parse_error.101] parse error at line 3, column 20: syntax error while parsing array - unexpected string literal; expected ']'
|
||||||
|
byte 51: [json.exception.parse_error.101] parse error at line 3, column 22: syntax error while parsing value - unexpected ']'; expected '[', '{', or a literal
|
||||||
|
byte 70: [json.exception.parse_error.101] parse error at line 4, column 17: syntax error while parsing value - invalid literal; last read: '"valid": tru,'
|
||||||
|
byte 86: [json.exception.parse_error.101] parse error at line 5, column 15: syntax error while parsing value - invalid number; expected digit after '.'; last read: '1.,'
|
||||||
|
byte 109: [json.exception.parse_error.101] parse error at line 6, column 22: syntax error while parsing object - unexpected end of input; expected '}'
|
||||||
|
|
||||||
|
valid JSON: false
|
||||||
|
{
|
||||||
|
"name": "Hello World",
|
||||||
|
"nested": {
|
||||||
|
"x": 1
|
||||||
|
},
|
||||||
|
"size": 1,
|
||||||
|
"tags": [
|
||||||
|
"a",
|
||||||
|
"b"
|
||||||
|
],
|
||||||
|
"valid": null
|
||||||
|
}
|
||||||
@@ -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
|
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
|
[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 -
|
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`, and `[h] - float16` - to unambiguously map common binary numeric types
|
`[u] - uint16`, `[m] - uint32`, `[M] - uint64`, `[h] - float16` and `[B] - byte` - to unambiguously map common binary
|
||||||
(Draft 3 adds `[B] - byte`); furthermore, it uses little-endian (LE) to store all numerics instead of big-endian (BE) as in UBJSON to
|
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.
|
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
|
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"
|
!!! abstract "References"
|
||||||
|
|
||||||
- [BJData Specification (Draft 3)](https://neurojson.org/bjdata/draft3)
|
- [BJData Specification](https://neurojson.org/bjdata/draft2)
|
||||||
- [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).
|
|
||||||
|
|
||||||
## Byte layout
|
## 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):
|
Consider the following JSON value (shown formatted for readability):
|
||||||
|
|
||||||
@@ -73,35 +54,35 @@ 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:
|
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 |
|
| JSON value type | value/range | BJData type | marker |
|
||||||
|-----------------|-------------------------------------------|-------------|-------------------------------------------------------------------------|
|
|-----------------|-------------------------------------------|----------------|--------|
|
||||||
| null | `null` | null | `Z` |
|
| null | `null` | null | `Z` |
|
||||||
| boolean | `true` | true | `T` |
|
| boolean | `true` | true | `T` |
|
||||||
| boolean | `false` | false | `F` |
|
| boolean | `false` | false | `F` |
|
||||||
| number_integer | -9223372036854775808..-2147483649 | int64 | `L` |
|
| number_integer | -9223372036854775808..-2147483649 | int64 | `L` |
|
||||||
| number_integer | -2147483648..-32769 | int32 | `l` |
|
| number_integer | -2147483648..-32769 | int32 | `l` |
|
||||||
| number_integer | -32768..-129 | int16 | `I` |
|
| number_integer | -32768..-129 | int16 | `I` |
|
||||||
| number_integer | -128..127 | int8 | `i` |
|
| number_integer | -128..127 | int8 | `i` |
|
||||||
| number_integer | 128..255 | uint8 | `U` |
|
| number_integer | 128..255 | uint8 | `U` |
|
||||||
| number_integer | 256..32767 | int16 | `I` |
|
| number_integer | 256..32767 | int16 | `I` |
|
||||||
| number_integer | 32768..65535 | uint16 | `u` |
|
| number_integer | 32768..65535 | uint16 | `u` |
|
||||||
| number_integer | 65536..2147483647 | int32 | `l` |
|
| number_integer | 65536..2147483647 | int32 | `l` |
|
||||||
| number_integer | 2147483648..4294967295 | uint32 | `m` |
|
| number_integer | 2147483648..4294967295 | uint32 | `m` |
|
||||||
| number_integer | 4294967296..9223372036854775807 | int64 | `L` |
|
| number_integer | 4294967296..9223372036854775807 | int64 | `L` |
|
||||||
| number_integer | 9223372036854775808..18446744073709551615 | uint64 | `M` |
|
| number_integer | 9223372036854775808..18446744073709551615 | uint64 | `M` |
|
||||||
| number_unsigned | 0..127 | int8 | `i` |
|
| number_unsigned | 0..127 | int8 | `i` |
|
||||||
| number_unsigned | 128..255 | uint8 | `U` |
|
| number_unsigned | 128..255 | uint8 | `U` |
|
||||||
| number_unsigned | 256..32767 | int16 | `I` |
|
| number_unsigned | 256..32767 | int16 | `I` |
|
||||||
| number_unsigned | 32768..65535 | uint16 | `u` |
|
| number_unsigned | 32768..65535 | uint16 | `u` |
|
||||||
| number_unsigned | 65536..2147483647 | int32 | `l` |
|
| number_unsigned | 65536..2147483647 | int32 | `l` |
|
||||||
| number_unsigned | 2147483648..4294967295 | uint32 | `m` |
|
| number_unsigned | 2147483648..4294967295 | uint32 | `m` |
|
||||||
| number_unsigned | 4294967296..9223372036854775807 | int64 | `L` |
|
| number_unsigned | 4294967296..9223372036854775807 | int64 | `L` |
|
||||||
| number_unsigned | 9223372036854775808..18446744073709551615 | uint64 | `M` |
|
| number_unsigned | 9223372036854775808..18446744073709551615 | uint64 | `M` |
|
||||||
| number_float | *any value* | float64 | `D` |
|
| number_float | *any value* | float64 | `D` |
|
||||||
| string | *with shortest length indicator* | string | `S` |
|
| string | *with shortest length indicator* | string | `S` |
|
||||||
| array | *see notes on optimized format/ND-array* | array | `[` |
|
| array | *see notes on optimized format/ND-array* | array | `[` |
|
||||||
| object | *see notes on optimized format* | map | `{` |
|
| 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"
|
!!! 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"
|
!!! 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).
|
- `Z`: no-op values are not created.
|
||||||
- `C`: single-character strings are serialized with `S` markers (`C` is read, and written for the elements of
|
- `C`: single-byte strings are serialized with `S` markers.
|
||||||
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`.
|
|
||||||
|
|
||||||
!!! info "NaN/infinity handling"
|
!!! 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
|
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
|
(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
|
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
|
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
|
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
|
```json
|
||||||
{
|
{
|
||||||
"_ArrayType_": "uint8",
|
"_ArrayType_": "uint8",
|
||||||
"_ArraySize_": [3,2],
|
"_ArraySize_": [2,3],
|
||||||
"_ArrayData_": [1,2,3,4,5,6]
|
"_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
|
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.
|
[`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
|
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:
|
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`,
|
- `"_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)
|
`double`, `char`, or `byte`,
|
||||||
`byte`; the names are case-sensitive,
|
|
||||||
- `"_ArraySize_"` is an array, since the dimensions are written as the ND-array header's length,
|
- `"_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
|
- `"_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 (`[1,2,2]` is packed, `[1,4]` is not),
|
parsed back as a regular array,
|
||||||
- every entry of `"_ArraySize_"` is a positive integer, and their product is representable as a `std::size_t`,
|
- 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
|
- `"_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
|
- every element of `"_ArrayData_"` is a number of the kind named by `"_ArrayType_"`: for the integer types, a
|
||||||
integer (a floating-point number such as `1.0` does not qualify) that fits the named width (for `char`, 0..127);
|
value that fits the named width; for `double`, any value; for `single`, a value that survives narrowing to
|
||||||
for `double`, a floating-point number (an integer such as `1` does not qualify); for `single`, a floating-point
|
`float` and back without change (for instance, `0.1` does not, since it is not exactly representable as
|
||||||
number that survives narrowing to `float` and back without change (for instance, `0.1` does not, since it is not
|
`float`).
|
||||||
exactly representable as `float`).
|
|
||||||
|
|
||||||
With `ordered_json`, an annotated object read from BJData has its keys in the order `"_ArrayType_"`,
|
An annotated object is always read back with its keys in the order shown above, `"_ArrayType_"`, `"_ArraySize_"`,
|
||||||
`"_ArraySize_"`, `"_ArrayData_"`; with `json`, they are sorted like those of any other object.
|
`"_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
|
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.
|
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"
|
!!! info "Restrictions in optimized data types for arrays and objects"
|
||||||
|
|
||||||
Due to diminished space saving, hampered readability, and increased security risks, in BJData, the
|
Due to diminished space saving, hampered readability, and increased security risks, in BJData, the allowed data
|
||||||
allowed data types following the `$` marker in an optimized array and object container are restricted to
|
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
|
**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
|
`UiuImlMLhdDCB`. This also means other variable (`[{SH`) or zero-length types (`TFN`) 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
|
optimized array or object in BJData.
|
||||||
[`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 `$`.
|
|
||||||
|
|
||||||
!!! info "Binary values"
|
!!! 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
|
in optimized arrays to designate binary data. This means that, unlike UBJSON, binary data can be both serialized and
|
||||||
deserialized.
|
deserialized.
|
||||||
|
|
||||||
To preserve compatibility with BJData Draft 2, the Draft 3 optimized binary array must be explicitly enabled: pass
|
To preserve compatibility with BJData Draft 2, the Draft 3 optimized binary array must be explicitly enabled using
|
||||||
`version = bjdata_version_t::draft3` together with `use_size = true` and `use_type = true` to
|
the `version` parameter of [`to_bjdata`](../../api/basic_json/to_bjdata.md).
|
||||||
[`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.
|
|
||||||
|
|
||||||
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
|
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.
|
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"
|
??? example "Example: serialize JSON values to BJData, with and without size/type optimization"
|
||||||
|
|
||||||
@@ -263,46 +227,34 @@ 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:
|
The library maps BJData types to JSON value types as follows:
|
||||||
|
|
||||||
| BJData type | JSON value type | marker |
|
| BJData type | JSON value type | marker |
|
||||||
|-----------------------|--------------------------------------------------|----------|
|
|-------------|------------------------------------------|----------|
|
||||||
| no-op | *no value, next value is read* | `N` |
|
| no-op | *no value, next value is read* | `N` |
|
||||||
| null | `null` | `Z` |
|
| null | `null` | `Z` |
|
||||||
| false | `false` | `F` |
|
| false | `false` | `F` |
|
||||||
| true | `true` | `T` |
|
| true | `true` | `T` |
|
||||||
| float16 | number_float | `h` |
|
| float16 | number_float | `h` |
|
||||||
| float32 | number_float | `d` |
|
| float32 | number_float | `d` |
|
||||||
| float64 | number_float | `D` |
|
| float64 | number_float | `D` |
|
||||||
| high-precision number | number_integer, number_unsigned, or number_float | `H` |
|
| uint8 | number_unsigned | `U` |
|
||||||
| uint8 | number_unsigned | `U` |
|
| int8 | number_integer | `i` |
|
||||||
| int8 | number_integer | `i` |
|
| uint16 | number_unsigned | `u` |
|
||||||
| uint16 | number_unsigned | `u` |
|
| int16 | number_integer | `I` |
|
||||||
| int16 | number_integer | `I` |
|
| uint32 | number_unsigned | `m` |
|
||||||
| uint32 | number_unsigned | `m` |
|
| int32 | number_integer | `l` |
|
||||||
| int32 | number_integer | `l` |
|
| uint64 | number_unsigned | `M` |
|
||||||
| uint64 | number_unsigned | `M` |
|
| int64 | number_integer | `L` |
|
||||||
| int64 | number_integer | `L` |
|
| byte | number_unsigned | `B` |
|
||||||
| byte | number_unsigned | `B` |
|
| string | string | `S` |
|
||||||
| string | string | `S` |
|
| char | string | `C` |
|
||||||
| char | string | `C` |
|
| array | array (optimized values are supported) | `[` |
|
||||||
| array | array (optimized values are supported) | `[` |
|
| ND-array | object (in JData annotated array format) | `[$.#[.` |
|
||||||
| ND-array | object (in JData annotated array format) | `[$.#[.` |
|
| object | object (optimized values are supported) | `{` |
|
||||||
| object | object (optimized values are supported) | `{` |
|
| binary | binary (strongly-typed byte array) | `[$B` |
|
||||||
| binary | binary (strongly-typed byte array) | `[$B` |
|
|
||||||
|
|
||||||
!!! success "Complete mapping"
|
!!! success "Complete mapping"
|
||||||
|
|
||||||
The mapping is **complete** for the BJData types of Draft 2 and Draft 3 with one exception: column-major
|
The mapping is **complete** in the sense that any BJData value can be converted to a JSON value.
|
||||||
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.
|
|
||||||
|
|
||||||
!!! warning "Ill-formed UTF-8 in string values and object keys"
|
!!! warning "Ill-formed UTF-8 in string values and object keys"
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# BON8
|
# 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
|
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
|
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.
|
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
|
## 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):
|
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>
|
<div class="byte-layout" markdown="0"><table>
|
||||||
<thead><tr><th>JSON</th><th>Bytes</th><th>Meaning</th></tr></thead><tbody>
|
<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>{</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>"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>"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>
|
<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:
|
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
|
- unsigned integers above 9223372036854775807, because BON8 has no unsigned 64-bit integer type
|
||||||
64 bits, any larger or smaller integer), because BON8 integers are limited to int64
|
|
||||||
([out_of_range.407](../../home/exceptions.md#jsonexceptionout_of_range407))
|
([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
|
- 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))
|
([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.
|
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
|
!!! info
|
||||||
[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"
|
|
||||||
|
|
||||||
Values that do not use the canonical representation, such as integers with a longer encoding than necessary,
|
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
|
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.
|
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).
|
!!! info
|
||||||
The specification does not say how to treat them; the HikoGUI reference decoder keeps the first value.
|
|
||||||
|
|
||||||
!!! info "Round trips"
|
|
||||||
|
|
||||||
Any BON8 output created by `to_bon8` can be successfully parsed by `from_bon8`.
|
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"
|
!!! warning "Incomplete mapping"
|
||||||
|
|
||||||
The mapping is **incomplete**, since only JSON-objects (and things contained therein) can be serialized to BSON.
|
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.
|
Also, keys may not contain U+0000, since they are serialized a 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).
|
|
||||||
|
|
||||||
!!! warning "BSON type 0x11 interoperability"
|
!!! 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,
|
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.
|
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"
|
??? example "Example: serialize a JSON value to BSON"
|
||||||
|
|
||||||
```cpp
|
```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:
|
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`, ...),
|
- 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,
|
- any non-zero byte is accepted as `true` for the boolean type, and
|
||||||
- the payloads of the binary subtypes `0x03` (UUID, old), `0x04` (UUID), and `0x05` (MD5) are not checked to have
|
- the payload for binary subtype `0x02` is returned as-is, including its inner length prefix.
|
||||||
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.
|
|
||||||
|
|
||||||
If BSON input must be validated for strict specification compliance, validate it separately before passing it to
|
If BSON input must be validated for strict specification compliance, validate it separately before passing it to
|
||||||
`from_bson()`.
|
`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"
|
!!! 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
|
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
|
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
|
(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
|
[`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`,
|
instead. Element (key) names are never validated on read, since they are read byte-by-byte as a C string. `binary`
|
||||||
`replace`, or `ignore` they are checked and handled in the same way. `binary` values (type `0x05`) are unaffected,
|
values (type `0x05`) are unaffected, since they are not required to hold text.
|
||||||
since they are not required to hold text.
|
|
||||||
|
|
||||||
??? example "Example: deserialize a JSON value from BSON"
|
??? 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
|
## 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):
|
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 |
|
| null | `null` | Null | 0xF6 |
|
||||||
| boolean | `true` | True | 0xF5 |
|
| boolean | `true` | True | 0xF5 |
|
||||||
| boolean | `false` | False | 0xF4 |
|
| boolean | `false` | False | 0xF4 |
|
||||||
| number_integer | -9223372036854775808..-4294967297 | Negative integer (8 bytes follow) | 0x3B |
|
| number_integer | -9223372036854775808..-2147483649 | Negative integer (8 bytes follow) | 0x3B |
|
||||||
| number_integer | -4294967296..-65537 | Negative integer (4 bytes follow) | 0x3A |
|
| number_integer | -2147483648..-32769 | Negative integer (4 bytes follow) | 0x3A |
|
||||||
| number_integer | -65536..-257 | Negative integer (2 bytes follow) | 0x39 |
|
| number_integer | -32768..-129 | Negative integer (2 bytes follow) | 0x39 |
|
||||||
| number_integer | -256..-25 | Negative integer (1 byte follow) | 0x38 |
|
| number_integer | -128..-25 | Negative integer (1 byte follow) | 0x38 |
|
||||||
| number_integer | -24..-1 | Negative integer | 0x20..0x37 |
|
| number_integer | -24..-1 | Negative integer | 0x20..0x37 |
|
||||||
| number_integer | 0..23 | Integer | 0x00..0x17 |
|
| number_integer | 0..23 | Integer | 0x00..0x17 |
|
||||||
| number_integer | 24..255 | Unsigned integer (1 byte follow) | 0x18 |
|
| number_integer | 24..255 | Unsigned integer (1 byte follow) | 0x18 |
|
||||||
| number_integer | 256..65535 | Unsigned integer (2 bytes follow) | 0x19 |
|
| number_integer | 256..65535 | Unsigned integer (2 bytes follow) | 0x19 |
|
||||||
| number_integer | 65536..4294967295 | Unsigned integer (4 bytes follow) | 0x1A |
|
| 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 | 0..23 | Integer | 0x00..0x17 |
|
||||||
| number_unsigned | 24..255 | Unsigned integer (1 byte follow) | 0x18 |
|
| number_unsigned | 24..255 | Unsigned integer (1 byte follow) | 0x18 |
|
||||||
| number_unsigned | 256..65535 | Unsigned integer (2 bytes follow) | 0x19 |
|
| number_unsigned | 256..65535 | Unsigned integer (2 bytes follow) | 0x19 |
|
||||||
@@ -95,24 +95,7 @@ see "binary" cells in the table above.
|
|||||||
|
|
||||||
!!! success "Complete mapping"
|
!!! success "Complete mapping"
|
||||||
|
|
||||||
The mapping is **complete** in the sense that any JSON value type can be converted to a CBOR value, with one
|
The mapping is **complete** in the sense that any JSON value type can be converted to a CBOR value.
|
||||||
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.
|
|
||||||
|
|
||||||
!!! info "NaN/infinity handling"
|
!!! info "NaN/infinity handling"
|
||||||
|
|
||||||
@@ -122,8 +105,9 @@ see "binary" cells in the table above.
|
|||||||
|
|
||||||
!!! note
|
!!! note
|
||||||
|
|
||||||
Prior to version 3.8.0, NaN and Infinity were instead serialized as a CBOR double-precision float (type 0xFB,
|
Prior to version 3.13.0, NaN and Infinity were instead serialized as a CBOR double-precision float (type 0xFB,
|
||||||
9 bytes total).
|
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"
|
!!! info "Unused CBOR types"
|
||||||
|
|
||||||
@@ -140,6 +124,7 @@ see "binary" cells in the table above.
|
|||||||
- expected conversions (0xD5..0xD7)
|
- expected conversions (0xD5..0xD7)
|
||||||
- simple values (0xE0..0xF3, 0xF8)
|
- simple values (0xE0..0xF3, 0xF8)
|
||||||
- undefined (0xF7)
|
- undefined (0xF7)
|
||||||
|
- half-precision floats (0xF9)
|
||||||
- break (0xFF)
|
- break (0xFF)
|
||||||
|
|
||||||
!!! info "Tagged items"
|
!!! 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
|
([RFC 8392](https://www.rfc-editor.org/rfc/rfc8392.html)), cannot be read with this library and need a
|
||||||
general-purpose CBOR library instead.
|
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"
|
!!! 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
|
[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
|
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
|
||||||
[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
|
|
||||||
[`error_handler`](../../api/basic_json/from_cbor.md) parameter left at `keep` (the default), `from_cbor()` accepts a
|
[`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
|
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
|
`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
|
[`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.
|
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"
|
!!! 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"
|
??? example "Example: deserialize a JSON value from CBOR"
|
||||||
|
|
||||||
|
|||||||
@@ -16,25 +16,25 @@ to efficiently encode JSON values to byte vectors and to decode such vectors.
|
|||||||
|
|
||||||
### Completeness
|
### Completeness
|
||||||
|
|
||||||
| Format | Serialization | Deserialization |
|
| 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 |
|
| BON8 | incomplete: no unsigned integers above int64 | complete |
|
||||||
| BSON | incomplete: top-level value must be an object | incomplete, but all JSON types are supported |
|
| 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 |
|
| CBOR | complete | incomplete, but all JSON types are supported |
|
||||||
| MessagePack | complete | incomplete, but all JSON types are supported |
|
| MessagePack | complete | complete |
|
||||||
| UBJSON | complete | complete |
|
| UBJSON | complete | complete |
|
||||||
|
|
||||||
### Binary values
|
### Binary values
|
||||||
|
|
||||||
| Format | Binary values | Binary subtypes |
|
| Format | Binary values | Binary subtypes |
|
||||||
|-------------|--------------------------|-----------------|
|
|-------------|---------------|-----------------|
|
||||||
| BJData | supported (Draft 3 only) | not supported |
|
| BJData | not supported | not supported |
|
||||||
| BON8 | not supported | not supported |
|
| BON8 | not supported | not supported |
|
||||||
| BSON | supported | supported |
|
| BSON | supported | supported |
|
||||||
| CBOR | supported | supported |
|
| CBOR | supported | supported |
|
||||||
| MessagePack | supported | supported |
|
| MessagePack | supported | supported |
|
||||||
| UBJSON | not supported | not supported |
|
| UBJSON | not supported | not supported |
|
||||||
|
|
||||||
See [binary values](../binary_values.md) for more information.
|
See [binary values](../binary_values.md) for more information.
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ extra byte in addition to the strings themselves.
|
|||||||
|
|
||||||
## Byte layout
|
## 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):
|
Consider the following JSON value (shown formatted for readability):
|
||||||
|
|
||||||
@@ -109,9 +109,8 @@ specification:
|
|||||||
!!! note
|
!!! note
|
||||||
|
|
||||||
Prior to version 3.13.0, NaN and Infinity were instead serialized as a MessagePack float 64 (type 0xCB, 9 bytes
|
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`)
|
total), because the check used to select the smaller float 32 encoding compared magnitudes with NaN, which is
|
||||||
and for Infinity and -Infinity (outside the float range checked against `std::numeric_limits<float>::lowest()` and
|
always `false` and caused the float 32 path to be skipped.
|
||||||
`max()`), so the float 32 path was skipped.
|
|
||||||
|
|
||||||
??? example "Example: serialize a JSON value to MessagePack"
|
??? 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 |
|
| fixarray | array | 0x90..0x9F |
|
||||||
| fixstr | string | 0xA0..0xBF |
|
| fixstr | string | 0xA0..0xBF |
|
||||||
| nil | `null` | 0xC0 |
|
| nil | `null` | 0xC0 |
|
||||||
| (never used) | – | 0xC1 |
|
|
||||||
| false | `false` | 0xC2 |
|
| false | `false` | 0xC2 |
|
||||||
| true | `true` | 0xC3 |
|
| true | `true` | 0xC3 |
|
||||||
| float 32 | number_float | 0xCA |
|
| float 32 | number_float | 0xCA |
|
||||||
@@ -169,30 +167,6 @@ The library maps MessagePack types to JSON value types as follows:
|
|||||||
| fixext 16 | binary | 0xD8 |
|
| fixext 16 | binary | 0xD8 |
|
||||||
| negative fixint | number_integer | 0xE0-0xFF |
|
| 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
|
!!! info
|
||||||
|
|
||||||
Any MessagePack output created by `to_msgpack` can be successfully parsed by `from_msgpack`.
|
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
|
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
|
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
|
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
|
`allow_exceptions` set to `false`, a discarded value) naming the type of the key that was found, for instance:
|
||||||
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
|
[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"
|
!!! 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
|
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
|
This library follows that by default: with its
|
||||||
[`error_handler`](../../api/basic_json/from_msgpack.md) parameter left at `keep` (the default),
|
[`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
|
`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"
|
!!! abstract "References"
|
||||||
|
|
||||||
- [UBJSON Website](https://ubjson.org)
|
- [UBJSON Website](http://ubjson.org)
|
||||||
|
|
||||||
## Byte layout
|
## 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):
|
Consider the following JSON value (shown formatted for readability):
|
||||||
|
|
||||||
@@ -44,29 +44,29 @@ 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:
|
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 |
|
| JSON value type | value/range | UBJSON type | marker |
|
||||||
|-----------------|-------------------------------------------|--------------------------------------------------|-----------|
|
|-----------------|-------------------------------------------|----------------|--------|
|
||||||
| null | `null` | null | `Z` |
|
| null | `null` | null | `Z` |
|
||||||
| boolean | `true` | true | `T` |
|
| boolean | `true` | true | `T` |
|
||||||
| boolean | `false` | false | `F` |
|
| boolean | `false` | false | `F` |
|
||||||
| number_integer | -9223372036854775808..-2147483649 | int64 | `L` |
|
| number_integer | -9223372036854775808..-2147483649 | int64 | `L` |
|
||||||
| number_integer | -2147483648..-32769 | int32 | `l` |
|
| number_integer | -2147483648..-32769 | int32 | `l` |
|
||||||
| number_integer | -32768..-129 | int16 | `I` |
|
| number_integer | -32768..-129 | int16 | `I` |
|
||||||
| number_integer | -128..127 | int8 | `i` |
|
| number_integer | -128..127 | int8 | `i` |
|
||||||
| number_integer | 128..255 | uint8 | `U` |
|
| number_integer | 128..255 | uint8 | `U` |
|
||||||
| number_integer | 256..32767 | int16 | `I` |
|
| number_integer | 256..32767 | int16 | `I` |
|
||||||
| number_integer | 32768..2147483647 | int32 | `l` |
|
| number_integer | 32768..2147483647 | int32 | `l` |
|
||||||
| number_integer | 2147483648..9223372036854775807 | int64 | `L` |
|
| number_integer | 2147483648..9223372036854775807 | int64 | `L` |
|
||||||
| number_unsigned | 0..127 | int8 | `i` |
|
| number_unsigned | 0..127 | int8 | `i` |
|
||||||
| number_unsigned | 128..255 | uint8 | `U` |
|
| number_unsigned | 128..255 | uint8 | `U` |
|
||||||
| number_unsigned | 256..32767 | int16 | `I` |
|
| number_unsigned | 256..32767 | int16 | `I` |
|
||||||
| number_unsigned | 32768..2147483647 | int32 | `l` |
|
| number_unsigned | 32768..2147483647 | int32 | `l` |
|
||||||
| number_unsigned | 2147483648..9223372036854775807 | int64 | `L` |
|
| number_unsigned | 2147483648..9223372036854775807 | int64 | `L` |
|
||||||
| number_unsigned | 9223372036854775808..18446744073709551615 | high-precision | `H` |
|
| 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` |
|
| string | *with shortest length indicator* | string | `S` |
|
||||||
| array | *see notes on optimized format* | array | `[` |
|
| array | *see notes on optimized format* | array | `[` |
|
||||||
| object | *see notes on optimized format* | object | `{` |
|
| object | *see notes on optimized format* | map | `{` |
|
||||||
|
|
||||||
!!! success "Complete mapping"
|
!!! 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:
|
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.
|
- `C`: single-byte strings are serialized with `S` markers.
|
||||||
|
|
||||||
!!! info "NaN/infinity handling"
|
!!! info "NaN/infinity handling"
|
||||||
|
|
||||||
NaN and infinity are written as IEEE 754 float64 values (`D`) and read back unchanged. This differs from
|
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), which serializes them to `null`, and from the UBJSON specification, which
|
[`dump()`](../../api/basic_json/dump.md) function which serializes NaN or Infinity to `null`.
|
||||||
encodes infinity as `null` (it does not mention NaN); other UBJSON readers may therefore not accept these values.
|
|
||||||
|
|
||||||
!!! info "Optimized formats"
|
!!! info "Optimized formats"
|
||||||
|
|
||||||
The optimized formats for containers are supported: Parameter `use_size` adds size information to the beginning of a
|
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
|
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
|
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
|
used together with `use_size = true`.
|
||||||
[`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 `[`).
|
|
||||||
|
|
||||||
Note that `use_size = true` alone may result in larger representations - the benefit of this parameter is that the
|
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.
|
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
|
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
|
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
|
[`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
|
(`1 << 20`), and `to_ubjson` writes longer arrays of these types without the annotation, so any value it produces
|
||||||
dropped, the `#` count is kept, and every element is written with its own marker (`[#l 1048577 Z Z ...`), so any value
|
can be read back.
|
||||||
it produces can be read back. Objects and untyped counted arrays are not subject to this limit.
|
|
||||||
|
|
||||||
!!! info "Binary values"
|
!!! info "Binary values"
|
||||||
|
|
||||||
@@ -148,54 +140,27 @@ 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:
|
The library maps UBJSON types to JSON value types as follows:
|
||||||
|
|
||||||
| UBJSON type | JSON value type | marker |
|
| UBJSON type | JSON value type | marker |
|
||||||
|----------------|--------------------------------------------------|--------|
|
|-------------|-----------------------------------------|--------|
|
||||||
| no-op | *no value, next value is read* | `N` |
|
| no-op | *no value, next value is read* | `N` |
|
||||||
| null | `null` | `Z` |
|
| null | `null` | `Z` |
|
||||||
| false | `false` | `F` |
|
| false | `false` | `F` |
|
||||||
| true | `true` | `T` |
|
| true | `true` | `T` |
|
||||||
| float32 | number_float | `d` |
|
| float32 | number_float | `d` |
|
||||||
| float64 | number_float | `D` |
|
| float64 | number_float | `D` |
|
||||||
| uint8 | number_unsigned | `U` |
|
| uint8 | number_unsigned | `U` |
|
||||||
| int8 | number_integer | `i` |
|
| int8 | number_integer | `i` |
|
||||||
| int16 | number_integer | `I` |
|
| int16 | number_integer | `I` |
|
||||||
| int32 | number_integer | `l` |
|
| int32 | number_integer | `l` |
|
||||||
| int64 | number_integer | `L` |
|
| int64 | number_integer | `L` |
|
||||||
| string | string | `S` |
|
| string | string | `S` |
|
||||||
| char | string | `C` |
|
| char | string | `C` |
|
||||||
| high-precision | number_unsigned, number_integer, or number_float | `H` |
|
| array | array (optimized values are supported) | `[` |
|
||||||
| array | array (optimized values are supported) | `[` |
|
| object | object (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"
|
!!! success "Complete mapping"
|
||||||
|
|
||||||
Every well-formed UBJSON value can be converted to a JSON value, with these exceptions: a high-precision number
|
The mapping is **complete** in the sense that any UBJSON value can be converted to a JSON value.
|
||||||
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.
|
|
||||||
|
|
||||||
!!! warning "Ill-formed UTF-8 in string values and object keys"
|
!!! warning "Ill-formed UTF-8 in string values and object keys"
|
||||||
|
|
||||||
|
|||||||
@@ -132,11 +132,8 @@ is an integer or `null`.
|
|||||||
|
|
||||||
### BJData
|
### BJData
|
||||||
|
|
||||||
[BJData](binary_formats/bjdata.md) Draft 3 supports binary values as optimized arrays of `B` (byte) elements, but no
|
[BJData](binary_formats/bjdata.md) neither supports binary values nor subtypes and proposes to serialize binary values
|
||||||
subtypes. With `version = bjdata_version_t::draft3` and both `use_size` and `use_type` set, `to_bjdata` writes a binary
|
as an array of uint8 values. The library implements this translation.
|
||||||
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.
|
|
||||||
|
|
||||||
??? example "Example: serialize a binary value to BJData"
|
??? example "Example: serialize a binary value to BJData"
|
||||||
|
|
||||||
@@ -174,7 +171,7 @@ in Draft 3), which is read back as an array.
|
|||||||
|
|
||||||
```c
|
```c
|
||||||
0x7B // '{'
|
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)
|
0x69 0x06 // i 6 (length of the key)
|
||||||
0x62 0x69 0x6E 0x61 0x72 0x79 // "binary"
|
0x62 0x69 0x6E 0x61 0x72 0x79 // "binary"
|
||||||
0x5B // '[' array
|
0x5B // '[' array
|
||||||
@@ -183,7 +180,7 @@ in Draft 3), which is read back as an array.
|
|||||||
0xCA 0xFE 0xBA 0xBE // content
|
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:
|
yield the following value:
|
||||||
|
|
||||||
```json
|
```json
|
||||||
@@ -216,7 +213,7 @@ array of integers.
|
|||||||
0x87 // object with 1 member
|
0x87 // object with 1 member
|
||||||
0x62 0x69 0x6E 0x61 0x72 0x79 // "binary"
|
0x62 0x69 0x6E 0x61 0x72 0x79 // "binary"
|
||||||
0x84 // array with 4 elements
|
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:
|
Note that the subtype is lost, and deserializing `v` would yield the following value:
|
||||||
@@ -230,10 +227,7 @@ array of integers.
|
|||||||
### BSON
|
### BSON
|
||||||
|
|
||||||
[BSON](binary_formats/bson.md) supports binary values and subtypes. If a subtype is given, it is used and added as an
|
[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
|
unsigned 8-bit integer. If no subtype is given, the generic binary subtype 0x00 is used.
|
||||||
[`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.
|
|
||||||
|
|
||||||
??? example "Example: serialize a binary value to BSON"
|
??? 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
|
[`json::from_cbor`](../api/basic_json/from_cbor.md) (see
|
||||||
[`cbor_tag_handler_t`](../api/basic_json/cbor_tag_handler_t.md)).
|
[`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
|
```json
|
||||||
{
|
{
|
||||||
"binary": {
|
"binary": {
|
||||||
@@ -318,21 +310,11 @@ representation using the length of the byte array.
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"binary": {
|
|
||||||
"bytes": [202, 254, 186, 190],
|
|
||||||
"subtype": 42
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### MessagePack
|
### MessagePack
|
||||||
|
|
||||||
[MessagePack](binary_formats/messagepack.md) supports binary values and subtypes. If a subtype is given, the ext family
|
[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,
|
is used. The library will choose the smallest representation among fixext1, fixext2, fixext4, fixext8, ext8, ext16, and
|
||||||
ext16, and ext32. The subtype is then written as the signed 8-bit ext type: subtypes 128 to 255 map to the negative
|
ext32. The subtype is then added as a signed 8-bit integer.
|
||||||
(reserved) ext types, and on reading the ext type is exposed as an unsigned subtype from 0 to 255.
|
|
||||||
|
|
||||||
If no subtype is given, the bin family (bin8, bin16, bin32) is used.
|
If no subtype is given, the bin family (bin8, bin16, bin32) is used.
|
||||||
|
|
||||||
|
|||||||
@@ -13,12 +13,6 @@ to the current JSON value by executing all operations from the patch, yielding t
|
|||||||
If the document is large and the original value is no longer needed,
|
If the document is large and the original value is no longer needed,
|
||||||
[`patch_inplace`](../api/basic_json/patch_inplace.md) applies the same operations in place instead.
|
[`patch_inplace`](../api/basic_json/patch_inplace.md) applies the same operations in place instead.
|
||||||
|
|
||||||
!!! note "Duplicate member names"
|
|
||||||
|
|
||||||
Duplicate member names inside an operation object are resolved by the parser before the patch is applied (the last
|
|
||||||
one is kept, see [`object_t`](../api/basic_json/object_t.md#behavior)), so
|
|
||||||
`#!json {"op": "add", "op": "remove", "path": "/a"}` is a `remove` operation.
|
|
||||||
|
|
||||||
??? example "Example: apply a JSON Patch"
|
??? example "Example: apply a JSON Patch"
|
||||||
|
|
||||||
The following code shows how a JSON patch is applied to a value.
|
The following code shows how a JSON patch is applied to a value.
|
||||||
@@ -47,23 +41,12 @@ flowchart LR
|
|||||||
|
|
||||||
!!! success "Invariant"
|
!!! success "Invariant"
|
||||||
|
|
||||||
For two JSON values *source* and *target*, the following code yields true:
|
For two JSON values *source* and *target*, the following code yields always true:
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
source.patch(diff(source, target)) == target;
|
source.patch(diff(source, target)) == target;
|
||||||
```
|
```
|
||||||
|
|
||||||
The equality holds up to [`operator==`](../api/basic_json/operator_eq.md), with these exceptions:
|
|
||||||
|
|
||||||
- `NaN` and [discarded](../api/basic_json/is_discarded.md) values are not equal to themselves, so the invariant
|
|
||||||
cannot hold for them. `diff` emits a `replace` operation for such a value, and a `NaN` in a patch is serialized
|
|
||||||
as `#!json null`.
|
|
||||||
- Numbers that compare equal produce no operation even if their types differ: `diff(1, 1.0)`, `diff(1u, 1)`, and
|
|
||||||
`diff(0.0, -0.0)` return `#!json []`, so the patched value keeps the number type of *source*.
|
|
||||||
- A [binary value](binary_values.md) in a patch is serialized as an object
|
|
||||||
(`#!json {"bytes":[...],"subtype":null}`), so a patch that was dumped and parsed again no longer holds a binary
|
|
||||||
value.
|
|
||||||
|
|
||||||
??? example "Example: create a JSON Patch from the difference of two values"
|
??? example "Example: create a JSON Patch from the difference of two values"
|
||||||
|
|
||||||
The following code shows how a JSON patch is created as a diff for two JSON values.
|
The following code shows how a JSON patch is created as a diff for two JSON values.
|
||||||
|
|||||||
@@ -37,10 +37,6 @@ Then every value inside the JSON document can be identified as follows:
|
|||||||
Note `/` does not identify the root (i.e., the whole document), but an object entry with empty key `""`. See
|
Note `/` does not identify the root (i.e., the whole document), but an object entry with empty key `""`. See
|
||||||
[RFC 6901](https://tools.ietf.org/html/rfc6901) for more information.
|
[RFC 6901](https://tools.ietf.org/html/rfc6901) for more information.
|
||||||
|
|
||||||
[RFC 6901, section 4](https://tools.ietf.org/html/rfc6901#section-4) states that evaluation fails if an object has
|
|
||||||
non-unique member names. A `basic_json` object holds one value per key (see [`object_t`](../api/basic_json/object_t.md)
|
|
||||||
for how duplicate keys are handled while parsing), so evaluating a JSON Pointer never encounters duplicates.
|
|
||||||
|
|
||||||
## JSON Pointer creation
|
## JSON Pointer creation
|
||||||
|
|
||||||
JSON Pointers can be created from a string:
|
JSON Pointers can be created from a string:
|
||||||
@@ -58,13 +54,6 @@ auto p = "/nested/one"_json_pointer;
|
|||||||
The escaping rules of [RFC 6901](https://tools.ietf.org/html/rfc6901) are implemented. See the
|
The escaping rules of [RFC 6901](https://tools.ietf.org/html/rfc6901) are implemented. See the
|
||||||
[constructor documentation](../api/json_pointer/json_pointer.md) for more information.
|
[constructor documentation](../api/json_pointer/json_pointer.md) for more information.
|
||||||
|
|
||||||
!!! note "URI fragment representation"
|
|
||||||
|
|
||||||
[RFC 6901, section 6](https://tools.ietf.org/html/rfc6901#section-6) also defines a URI fragment identifier
|
|
||||||
representation (`#/a%20b`). It is not supported: `#!cpp json::json_pointer("#/a")` throws
|
|
||||||
[`parse_error.107`](../home/exceptions.md#jsonexceptionparse_error107). Strip the leading `#` and
|
|
||||||
percent-decode the remainder before creating the JSON pointer.
|
|
||||||
|
|
||||||
## Value access
|
## Value access
|
||||||
|
|
||||||
JSON Pointers can be used in the [`at`](../api/basic_json/at.md), [`operator[]`](../api/basic_json/operator%5B%5D.md),
|
JSON Pointers can be used in the [`at`](../api/basic_json/at.md), [`operator[]`](../api/basic_json/operator%5B%5D.md),
|
||||||
|
|||||||
@@ -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
|
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.
|
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
|
**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
|
[`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
|
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
|
## 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`,
|
`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
|
`#!cpp std::string`/other `#!cpp std::basic_string`s (copied once), `basic_json`/`ordered_json` (via
|
||||||
and other types the library converts (`#!cpp std::vector`, `#!cpp std::map`, `#!cpp std::list`, `#!cpp std::array`,
|
[`materialize()`](../api/basic_json_view/materialize.md)), `basic_json_view` itself, `#!cpp std::vector<U>`, and
|
||||||
`#!cpp std::pair`, `#!cpp std::tuple`, `#!cpp std::optional`, ...), and the types of the `NLOHMANN_DEFINE_TYPE_*` and
|
`#!cpp std::map`/`#!cpp std::unordered_map` with string-like keys. Every other type -- `#!cpp std::list`,
|
||||||
`NLOHMANN_JSON_SERIALIZE_ENUM` macros. Types whose `from_json()` is written for `basic_json` only go through
|
`#!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
|
[`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
|
`basic_json` value first, exactly as [`parse()`](../api/basic_json/parse.md) would, and converted from there.
|
||||||
[Writing generic code](#writing-generic-code) for how to write a `from_json()` that reads views.
|
|
||||||
|
|
||||||
Two conversions never copy at all:
|
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.
|
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
|
## Writing a view back
|
||||||
|
|
||||||
[`dump()`](../api/basic_json_view/dump.md) serializes a view directly from the flat index, without ever building a
|
[`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
|
## Editing a document
|
||||||
|
|
||||||
Everything above is read-only: a `json_document`/`json_view` lets you look at a parsed text without copying it, but
|
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
|
spelled [`json_editable_document`](../api/json_editable_document.md) or
|
||||||
[`ordered_json_editable_document`](../api/ordered_json_editable_document.md) -- also lets you
|
[`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
|
[`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)
|
[`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.
|
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
|
none of the bookkeeping edits need, and calling `set`/`push_back`/`insert`/`erase` on one is a compile error, not a
|
||||||
runtime one.
|
runtime one.
|
||||||
|
|
||||||
@@ -446,10 +354,9 @@ validation entirely, for an image trusted as much as the process's own memory. S
|
|||||||
!!! warning "Experimental"
|
!!! warning "Experimental"
|
||||||
|
|
||||||
The image format is versioned but not yet stable, and may change in an incompatible way before it is declared
|
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
|
stable. It is little-endian only, and tied to the library build that wrote it -- use it to cache a document or to
|
||||||
library build that wrote it -- use it to cache a document or to hand one to another process running the *same*
|
hand one to another process running the *same* build, not as a long-term storage format; keep the original JSON
|
||||||
build, not as a long-term storage format; keep the original JSON text if a saved document needs to be readable by
|
text if a saved document needs to be readable by a future library version.
|
||||||
a future library version.
|
|
||||||
|
|
||||||
The idea of a document you can read without parsing comes from zero-copy formats such as
|
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
|
[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).
|
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_*(...)`
|
## `NLOHMANN_DEFINE_TYPE_*(...)`, `NLOHMANN_DEFINE_DERIVED_TYPE_*(...)`
|
||||||
|
|
||||||
The library defines 12 macros to simplify the serialization/deserialization of types. See the page on
|
The library defines 12 macros to simplify the serialization/deserialization of types. See the page on
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
The library supports JSON Merge Patch ([RFC 7396](https://tools.ietf.org/html/rfc7396)) as a patch format.
|
The library supports JSON Merge Patch ([RFC 7396](https://tools.ietf.org/html/rfc7396)) as a patch format.
|
||||||
The merge patch format is primarily intended for use with the HTTP PATCH method as a means of describing a set of
|
The merge patch format is primarily intended for use with the HTTP PATCH method as a means of describing a set of
|
||||||
modifications to a target resource's content. Applying a merge patch changes the JSON value the patch is applied to.
|
modifications to a target resource's content. This function applies a merge patch to the current JSON value.
|
||||||
|
|
||||||
Instead of using [JSON Pointer](json_pointer.md) to specify values to be manipulated, it describes the changes using a
|
Instead of using [JSON Pointer](json_pointer.md) to specify values to be manipulated, it describes the changes using a
|
||||||
syntax that closely mimics the document being modified. Unlike [JSON Patch](json_patch.md), a JSON Merge Patch cannot
|
syntax that closely mimics the document being modified. Unlike [JSON Patch](json_patch.md), a JSON Merge Patch cannot
|
||||||
@@ -19,18 +19,6 @@ another.
|
|||||||
[`update`](../api/basic_json/update.md) with `merge_objects` set to `#!cpp true`; see
|
[`update`](../api/basic_json/update.md) with `merge_objects` set to `#!cpp true`; see
|
||||||
[Merging objects](modifying_values.md#merging-objects).
|
[Merging objects](modifying_values.md#merging-objects).
|
||||||
|
|
||||||
!!! note "Limitations of RFC 7396"
|
|
||||||
|
|
||||||
- A patch cannot set a member to `#!json null`, because `#!json null` removes the member:
|
|
||||||
`#!json {"a":1}` patched with `#!json {"a":null}` gives `#!json {}`.
|
|
||||||
- Arrays are replaced as a whole, never merged, and a `#!json null` inside an array is kept.
|
|
||||||
- `#!json null` members of the target that the patch does not mention are preserved.
|
|
||||||
- A `#!json null` that would remove a member of a not yet existing object still creates that object:
|
|
||||||
`#!json {}` patched with `#!json {"a":{"b":null}}` gives `#!json {"a":{}}`.
|
|
||||||
- A patch that is not an object replaces the whole target (a `#!json null` patch makes the target
|
|
||||||
`#!json null`); an object patch applied to a non-object target starts from an empty object.
|
|
||||||
- [`merge_diff`](../api/basic_json/merge_diff.md#notes) has a matching limitation for `#!json null` members.
|
|
||||||
|
|
||||||
??? example
|
??? example
|
||||||
|
|
||||||
The following code shows how a JSON Merge Patch is applied to a JSON document.
|
The following code shows how a JSON Merge Patch is applied to a JSON document.
|
||||||
|
|||||||
@@ -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
|
- [`JSON_DISABLE_UNLOCKED_FILE_IO`](../api/macros/json_disable_unlocked_file_io.md) defined non-zero appends
|
||||||
`_dufio`.
|
`_dufio`.
|
||||||
- [`JSON_NO_SIMD`](../api/macros/json_no_simd.md) defined appends `_ns`.
|
- [`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
|
- 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)
|
underscores. To omit the version component, see [Disabling the version component](#disabling-the-version-component)
|
||||||
below.
|
below.
|
||||||
@@ -113,5 +115,7 @@ follows:
|
|||||||
([`JSON_STRICT_BINARY_UTF8`](../api/macros/json_strict_binary_utf8.md)), `_ekmo`
|
([`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_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_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_DISABLE_UNLOCKED_FILE_IO`](../api/macros/json_disable_unlocked_file_io.md)), `_ns`
|
||||||
([`JSON_NO_SIMD`](../api/macros/json_no_simd.md)) in version 3.13.0.
|
([`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.
|
||||||
@@ -0,0 +1,122 @@
|
|||||||
|
# Error Recovery
|
||||||
|
|
||||||
|
By default, parsing stops at the first error. With the [SAX interface](sax_interface.md), you can instead ask the
|
||||||
|
parser to *recover*: to repair the error and continue, so that you get as much as possible out of malformed input, for
|
||||||
|
instance a file that was cut off, JSON edited by hand, or the output of a language model.
|
||||||
|
|
||||||
|
## Recovering from errors
|
||||||
|
|
||||||
|
The SAX parser's [`parse_error`](../../api/json_sax/parse_error.md) function is called for every error. Its return value
|
||||||
|
decides what happens next:
|
||||||
|
|
||||||
|
- `#!cpp false` stops parsing. This is what the SAX parsers of the library do, so [`parse`](../../api/basic_json/parse.md)
|
||||||
|
and [`accept`](../../api/basic_json/accept.md) never recover.
|
||||||
|
- `#!cpp true` repairs the error and continues parsing.
|
||||||
|
|
||||||
|
When recovering, the SAX parser still receives well-formed events: every `start_object` or `start_array` is followed by
|
||||||
|
the matching `end_object` or `end_array`, and every `key` is followed by exactly one value. A SAX parser that creates a
|
||||||
|
JSON value, such as the one in the example below, therefore gets a complete value. Parsing always ends, and
|
||||||
|
[`sax_parse`](../../api/basic_json/sax_parse.md) returns `#!cpp false` for input that is not valid JSON, even if every
|
||||||
|
error was repaired. Each token is reported at most once, and the SAX parser can stop at any error by returning
|
||||||
|
`#!cpp false`.
|
||||||
|
|
||||||
|
!!! example
|
||||||
|
|
||||||
|
The example below derives a SAX parser from the library's parser for `json` values (`json_sax_dom_parser`),
|
||||||
|
and recovers from all errors.
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
--8<-- "examples/sax_parse__error_recovery.cpp"
|
||||||
|
```
|
||||||
|
|
||||||
|
Output:
|
||||||
|
|
||||||
|
```
|
||||||
|
--8<-- "examples/sax_parse__error_recovery.output"
|
||||||
|
```
|
||||||
|
|
||||||
|
## How errors are repaired
|
||||||
|
|
||||||
|
Each error is repaired with the smallest local edit: a missing separator is inserted, a stray token is removed, what can
|
||||||
|
be read of a broken string or number is kept, and a value that cannot be read at all becomes `#!json null`.
|
||||||
|
|
||||||
|
| Mistake | Repair | Example | Result |
|
||||||
|
|---------------------------|--------------------------------------------------------------------------------|------------------------------------------|----------------------------|
|
||||||
|
| missing `,` or `:` | inserted | `#!json [1 2]`, `#!json {"a" 1}` | `[1,2]`, `{"a":1}` |
|
||||||
|
| missing value | `#!json null` for an object key or between commas in an array | `#!json {"a":}`, `#!json [1,,2]` | `{"a":null}`, `[1,null,2]` |
|
||||||
|
| trailing comma | removed | `#!json [1,2,]` | `[1,2]` |
|
||||||
|
| broken string | invalid escapes and bytes are replaced (see below); a line break ends the string | `#!json ["a\qb"]` | `["aqb"]` |
|
||||||
|
| broken number | the longest valid beginning is kept | `#!json [1., 2e+]` | `[1,2]` |
|
||||||
|
| unreadable value | `#!json null` | `#!json [1, NaN, tru]` | `[1,null,null]` |
|
||||||
|
| number too large | passed as infinity, together with its text | `#!json [1e999]` | infinity (see below) |
|
||||||
|
| stray `:` | removed | `#!json ["a":1]` | `["a",1]` |
|
||||||
|
| member without a key | skipped up to the next `,` or `}` | `#!json {1:2, "b":3}` | `{"b":3}` |
|
||||||
|
| wrong closing bracket | closes the innermost array or object | `#!json {"a":[1,2}, "b":3}` | `{"a":[1,2],"b":3}` |
|
||||||
|
| input ends too early | all open arrays and objects are closed | `#!json {"a":[1,2` | `{"a":[1,2]}` |
|
||||||
|
| text before the value | skipped | `#!json )]}'{"a":1}` | `{"a":1}` |
|
||||||
|
|
||||||
|
In a string, an unknown escape like `\q` stands for the escaped character (`q`), as in JavaScript. An invalid `\u`
|
||||||
|
escape, a lone surrogate, and ill-formed UTF-8 are each replaced by U+FFFD (REPLACEMENT CHARACTER), and control
|
||||||
|
characters are kept. A string without its closing quote ends at the next line break or at the end of the input.
|
||||||
|
|
||||||
|
The input after the top-level value is not repaired: as without recovery, it is reported as an error, and parsing stops.
|
||||||
|
|
||||||
|
## Binary formats
|
||||||
|
|
||||||
|
The binary formats ([BJData](../binary_formats/bjdata.md), [BON8](../binary_formats/bon8.md),
|
||||||
|
[BSON](../binary_formats/bson.md), [CBOR](../binary_formats/cbor.md), [MessagePack](../binary_formats/messagepack.md),
|
||||||
|
and [UBJSON](../binary_formats/ubjson.md)) have no delimiters to find the next value by. So what can be repaired depends
|
||||||
|
on whether the end of the item with the error is known, a distinction that
|
||||||
|
[RFC 8949, Section 5.3](https://www.rfc-editor.org/rfc/rfc8949.html#section-5.3) makes for CBOR, too.
|
||||||
|
|
||||||
|
If the item is complete, but cannot be passed on as it is, it is replaced, and parsing continues after it:
|
||||||
|
|
||||||
|
| Mistake | Formats | Repair |
|
||||||
|
|---------------------------------------------------------------------|-------------------------|-------------------------------------------------------------------------|
|
||||||
|
| tag, if `tag_handler` is `cbor_tag_handler_t::error` (the default) | CBOR | ignored |
|
||||||
|
| simple value other than `false`, `true`, and `null`, like undefined | CBOR | `#!json null` |
|
||||||
|
| number too large for a custom `number_float_t`, like `float` | all | infinity |
|
||||||
|
| character (`C`) that is not ASCII | BJData, UBJSON | U+FFFD |
|
||||||
|
| invalid high-precision number (`H`) | BJData, UBJSON | the longest valid beginning is kept, as for JSON text, or `#!json null` |
|
||||||
|
| high-precision number too large | BJData, UBJSON | passed as infinity, together with its text |
|
||||||
|
| object key that is not a string | BON8, CBOR, MessagePack | the member is skipped |
|
||||||
|
| element of a type the library does not read, like ObjectId or date | BSON | `#!json null` |
|
||||||
|
| string without its terminator | BSON | kept |
|
||||||
|
| document whose size does not match its content | BSON | kept |
|
||||||
|
|
||||||
|
CBOR tags and simple values are repaired as [RFC 8949, Section 6.1](https://www.rfc-editor.org/rfc/rfc8949.html#section-6.1)
|
||||||
|
suggests for converting CBOR to JSON. By default, [`sax_parse`](../../api/basic_json/sax_parse.md) reports every tag as
|
||||||
|
an error; when recovering, tags are then ignored like with
|
||||||
|
[`cbor_tag_handler_t::ignore`](../../api/basic_json/cbor_tag_handler_t.md). Strings that are not valid UTF-8 are no
|
||||||
|
error: like [`from_cbor`](../../api/basic_json/from_cbor.md) and the other functions by default, `sax_parse` passes
|
||||||
|
them on as they are.
|
||||||
|
|
||||||
|
After any other error, the end of the item is unknown: the input ended, a byte is not a valid type marker, or a size
|
||||||
|
cannot be right. Parsing then stops, and the value read so far is completed: a key that waits for its value gets
|
||||||
|
`#!json null`, and all open arrays and objects are closed. This keeps everything before the error of an input that was
|
||||||
|
cut off. The exception is BSON, which stores the size of every document: an element whose end is unknown gets
|
||||||
|
`#!json null`, the rest of its document is skipped, and parsing continues after the document.
|
||||||
|
|
||||||
|
## Limitations
|
||||||
|
|
||||||
|
- A repair is a guess. For example, `#!json {"a" "b": 1}` could be meant as `#!json {"a": "b"}` or as
|
||||||
|
`#!json {"a": null, "b": 1}`; it is repaired to the former. Treat recovered values as a best effort, and check the
|
||||||
|
reported errors.
|
||||||
|
- A closing bracket always closes the innermost array or object. If a bracket is missing rather than wrong, the
|
||||||
|
repair differs from the intention: `#!json {"a": {"b": [1, 2}, "c": 3}` is repaired to
|
||||||
|
`#!json {"a": {"b": [1, 2], "c": 3}}`, although `#!json {"a": {"b": [1, 2]}, "c": 3}` may have been meant.
|
||||||
|
- Keys without quotes, and strings in single quotes, are not supported; such members are skipped.
|
||||||
|
- In the binary formats, a member that is skipped because its key is not a string is lost, and so are the elements of a
|
||||||
|
BSON document after one whose end is unknown.
|
||||||
|
- A number that is too large for `number_float_t` is passed as positive or negative infinity. The SAX parser's
|
||||||
|
`number_float` also gets the number's text, but a JSON value cannot store it, and
|
||||||
|
[`dump`](../../api/basic_json/dump.md) serializes infinity as `#!json null`.
|
||||||
|
- When parsing is not strict (see [`sax_parse`](../../api/basic_json/sax_parse.md)), a repair may read parts of the
|
||||||
|
input after the value, for instance of the next value in a stream of concatenated values.
|
||||||
|
|
||||||
|
## See also
|
||||||
|
|
||||||
|
- [SAX interface](sax_interface.md) - implement a custom SAX handler
|
||||||
|
- [`parse_error`](../../api/json_sax/parse_error.md) - the SAX event for parse errors
|
||||||
|
- [`sax_parse`](../../api/basic_json/sax_parse.md) - generate SAX events
|
||||||
|
- [parsing and exceptions](parse_exceptions.md) - control error handling
|
||||||
@@ -139,7 +139,7 @@ See [Zero-copy JSON views](../json_view.md) for the concept and the trade-offs.
|
|||||||
When the input is not valid JSON, the `parse` function throws an exception by default. If exceptions are undesired or
|
When the input is not valid JSON, the `parse` function throws an exception by default. If exceptions are undesired or
|
||||||
unavailable, the parser can instead return a discarded value, or [`accept`](../../api/basic_json/accept.md) can be used
|
unavailable, the parser can instead return a discarded value, or [`accept`](../../api/basic_json/accept.md) can be used
|
||||||
to only check whether an input is valid JSON. See [parsing and exceptions](parse_exceptions.md) for the available
|
to only check whether an input is valid JSON. See [parsing and exceptions](parse_exceptions.md) for the available
|
||||||
options.
|
options. To get as much as possible out of malformed input, a SAX parser can [recover from errors](error_recovery.md).
|
||||||
|
|
||||||
## See also
|
## See also
|
||||||
|
|
||||||
@@ -153,5 +153,6 @@ options.
|
|||||||
- [SAX interface](sax_interface.md) - implement a custom SAX handler
|
- [SAX interface](sax_interface.md) - implement a custom SAX handler
|
||||||
- [Zero-copy JSON views](../json_view.md) - parse into a read-only document and read it through views
|
- [Zero-copy JSON views](../json_view.md) - parse into a read-only document and read it through views
|
||||||
- [parsing and exceptions](parse_exceptions.md) - control error handling
|
- [parsing and exceptions](parse_exceptions.md) - control error handling
|
||||||
|
- [error recovery](error_recovery.md) - get as much as possible out of malformed input
|
||||||
- [parsing untrusted input](untrusted_input.md) - what to consider when parsing input from untrusted sources
|
- [parsing untrusted input](untrusted_input.md) - what to consider when parsing input from untrusted sources
|
||||||
- [Zero-copy JSON views](../json_view.md) - parse into a document and read it through a view
|
- [Zero-copy JSON views](../json_view.md) - parse into a document and read it through a view
|
||||||
@@ -68,7 +68,8 @@ bool parse_error(std::size_t position,
|
|||||||
const json::exception& ex);
|
const json::exception& ex);
|
||||||
```
|
```
|
||||||
|
|
||||||
The return value indicates whether the parsing should continue, so the function should usually return `#!cpp false`.
|
The return value decides whether to stop parsing (`#!cpp false`) or to repair the error and continue
|
||||||
|
(`#!cpp true`); see [error recovery](error_recovery.md) for the latter.
|
||||||
|
|
||||||
??? example "Example: report parse errors without exceptions"
|
??? example "Example: report parse errors without exceptions"
|
||||||
|
|
||||||
|
|||||||
@@ -60,7 +60,8 @@ bool key(string_t& val);
|
|||||||
bool parse_error(std::size_t position, const std::string& last_token, const json::exception& ex);
|
bool parse_error(std::size_t position, const std::string& last_token, const json::exception& ex);
|
||||||
```
|
```
|
||||||
|
|
||||||
The return value of each function determines whether parsing should proceed.
|
The return value of each function determines whether parsing should proceed. For `parse_error`, returning
|
||||||
|
`#!cpp true` [recovers from the error](error_recovery.md).
|
||||||
|
|
||||||
To implement your own SAX handler, proceed as follows:
|
To implement your own SAX handler, proceed as follows:
|
||||||
|
|
||||||
@@ -68,7 +69,7 @@ To implement your own SAX handler, proceed as follows:
|
|||||||
2. Create an object of your SAX interface class, e.g. `my_sax`.
|
2. Create an object of your SAX interface class, e.g. `my_sax`.
|
||||||
3. Call `#!cpp bool json::sax_parse(input, &my_sax);` where the first parameter can be any input like a string or an input stream and the second parameter is a pointer to your SAX interface.
|
3. Call `#!cpp bool json::sax_parse(input, &my_sax);` where the first parameter can be any input like a string or an input stream and the second parameter is a pointer to your SAX interface.
|
||||||
|
|
||||||
Note the `sax_parse` function only returns a `#!cpp bool` indicating the result of the last executed SAX event. It does not return `json` value - it is up to you to decide what to do with the SAX events. Furthermore, no exceptions are thrown in case of a parse error - it is up to you what to do with the exception object passed to your `parse_error` implementation. Internally, the SAX interface is used for the DOM parser (class `json_sax_dom_parser`) as well as the acceptor (`json_sax_acceptor`), see file `json_sax.hpp`.
|
Note the `sax_parse` function only returns a `#!cpp bool` indicating whether the input was parsed without errors and no SAX event returned `#!cpp false`. It does not return `json` value - it is up to you to decide what to do with the SAX events. Furthermore, no exceptions are thrown in case of a parse error - it is up to you what to do with the exception object passed to your `parse_error` implementation. Internally, the SAX interface is used for the DOM parser (class `json_sax_dom_parser`) as well as the acceptor (`json_sax_acceptor`), see file `json_sax.hpp`.
|
||||||
|
|
||||||
## See also
|
## See also
|
||||||
|
|
||||||
|
|||||||
@@ -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()`
|
`#!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
|
is not null-terminated does not fail to compile; with such a `NumberFloatType` it can silently misparse
|
||||||
floating-point numbers.
|
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+=`,
|
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)`.
|
`append(first, last)`, and `append(data, size)`.
|
||||||
- The comparison operator `==` against another `StringType`, and `<` for use as a key of the chosen
|
- The comparison operator `==` against another `StringType`, and `<` for use as a key of the chosen
|
||||||
@@ -389,7 +390,6 @@ using array_t = ArrayType<basic_json, AllocatorType<basic_json>>;
|
|||||||
described in RFC 6901. Neither `find(const StringType&, size_type)`, nor `substr(pos, count)`, nor
|
described in RFC 6901. Neither `find(const StringType&, size_type)`, nor `substr(pos, count)`, nor
|
||||||
`replace(pos, count, const StringType&)` is required.
|
`replace(pos, count, const StringType&)` is required.
|
||||||
- `empty()`.
|
- `empty()`.
|
||||||
- `resize(n)` (one argument) -- used by `to_string` to size the result before the reference tokens are copied into it.
|
|
||||||
- `begin()` and `end()` -- used by
|
- `begin()` and `end()` -- used by
|
||||||
[`operator[](const json_pointer&)`](../../api/basic_json/operator%5B%5D.md) to decide whether a reference token
|
[`operator[](const json_pointer&)`](../../api/basic_json/operator%5B%5D.md) to decide whether a reference token
|
||||||
denotes an array index.
|
denotes an array index.
|
||||||
@@ -678,7 +678,8 @@ using binary_t = nlohmann::byte_container_with_subtype<BinaryType>;
|
|||||||
[`StringType`](#stringtype), whose non-`#!cpp const` `data()` is C++17 and later only.
|
[`StringType`](#stringtype), whose non-`#!cpp const` `data()` is C++17 and later only.
|
||||||
- Default-constructible, copy-constructible, and move-constructible.
|
- Default-constructible, copy-constructible, and move-constructible.
|
||||||
- Member functions `size()`, `empty()`, `data()`, `resize()`, `operator[]`, `back()`, `begin()`, `end()`, `cbegin()`,
|
- 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
|
- Comparison operators: `==` is used by
|
||||||
[`byte_container_with_subtype`](../../api/byte_container_with_subtype/index.md), the relational operators 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).
|
[`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`,
|
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
|
```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`.
|
4. Use the generated file instead of `nlohmann_json.natvis`.
|
||||||
|
|||||||
@@ -330,7 +330,7 @@ where they cannot be resolved.
|
|||||||
### json.exception.parse_error.110
|
### json.exception.parse_error.110
|
||||||
|
|
||||||
When parsing a [binary format](../features/binary_formats/index.md), the byte vector ends before the complete value has
|
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"
|
!!! failure "Example messages"
|
||||||
|
|
||||||
@@ -346,7 +346,7 @@ been read, or (with `strict = true`) further bytes follow the value.
|
|||||||
|
|
||||||
### json.exception.parse_error.112
|
### 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"
|
!!! 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 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
|
### 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
|
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
|
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
|
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.
|
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
|
||||||
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`.
|
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
|
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
|
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
|
### 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 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
|
### 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
|
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
|
[`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_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"
|
!!! failure "Example message"
|
||||||
|
|
||||||
@@ -895,12 +883,17 @@ from JSON text.
|
|||||||
|
|
||||||
[`basic_json_document::save()`](../api/basic_json_document/save.md) cannot write an
|
[`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.
|
[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"
|
!!! failure "Example messages"
|
||||||
|
|
||||||
```
|
```
|
||||||
[json.exception.type_error.320] cannot save a discarded json_document
|
[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
|
!!! 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:
|
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
|
- [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
|
[`to_bon8`](../api/basic_json/to_bon8.md) throws for unsigned integers greater than 9223372036854775807.
|
||||||
number type wider than 64 bits, for any integer outside the int64 range.
|
|
||||||
- [CBOR](../features/binary_formats/cbor.md), [MessagePack](../features/binary_formats/messagepack.md), and
|
- [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
|
[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
|
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.
|
- 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
|
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"
|
!!! 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
|
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
|
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.
|
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 `#`
|
[`to_ubjson`](../api/basic_json/to_ubjson.md) writes longer arrays of these types without the size and type annotation,
|
||||||
count and one marker per element are kept), so any value it produces can still be read back.
|
so any value it produces can still be read back.
|
||||||
|
|
||||||
!!! failure "Example messages"
|
!!! failure "Example messages"
|
||||||
|
|
||||||
@@ -1091,14 +1083,9 @@ a JSON pointer exceeds the range of `size_type` (e.g., on 32-bit platforms).
|
|||||||
|
|
||||||
```
|
```
|
||||||
enum value out of range
|
enum value out of range
|
||||||
array index 18446744073709551615 exceeds size_type
|
array index 18446744073709551616 exceeds size_type
|
||||||
```
|
```
|
||||||
|
|
||||||
The second message is thrown, for instance, by `#!cpp json::parse("[1, 2]").at("/18446744073709551615"_json_pointer)`
|
|
||||||
on a 64-bit platform, where `size_type` is `#!cpp std::size_t` and this index is `SIZE_MAX`. An index that does not
|
|
||||||
fit into 64 bits (such as `18446744073709551616`) is not reported as 410 but as
|
|
||||||
[`out_of_range.404`](#jsonexceptionout_of_range404).
|
|
||||||
|
|
||||||
### json.exception.out_of_range.411
|
### json.exception.out_of_range.411
|
||||||
|
|
||||||
A JSON Patch `add` operation cannot be applied because the target location's parent is neither an object nor an array. Per [RFC 6902](https://datatracker.ietf.org/doc/html/rfc6902), an `add` target must reference a member of an existing object or an element of an existing array; a primitive value (string, number, boolean, etc.) cannot receive a new member or element.
|
A JSON Patch `add` operation cannot be applied because the target location's parent is neither an object nor an array. Per [RFC 6902](https://datatracker.ietf.org/doc/html/rfc6902), an `add` target must reference a member of an existing object or an element of an existing array; a primitive value (string, number, boolean, etc.) cannot receive a new member or element.
|
||||||
@@ -1113,8 +1100,6 @@ A JSON Patch `add` operation cannot be applied because the target location's par
|
|||||||
|
|
||||||
This exception was added in version 3.13.0. Before that, this situation hit an internal assertion (aborting the program in debug builds) or was silently ignored when assertions were disabled.
|
This exception was added in version 3.13.0. Before that, this situation hit an internal assertion (aborting the program in debug builds) or was silently ignored when assertions were disabled.
|
||||||
|
|
||||||
A `null` parent is rejected as well. Before version 3.13.0, an `add` into a `null` parent silently converted it to an object (e.g., `add` at `/foo/bar` turned `{"foo":null}` into `{"foo":{"bar":1}}`).
|
|
||||||
|
|
||||||
### json.exception.out_of_range.412
|
### json.exception.out_of_range.412
|
||||||
|
|
||||||
BSON stores the length of documents, arrays, strings, and binary values in a signed 32-bit integer, and MessagePack
|
BSON stores the length of documents, arrays, strings, and binary values in a signed 32-bit integer, and MessagePack
|
||||||
@@ -1168,18 +1153,14 @@ A JSON Patch `move` operation's `"from"` location is a proper prefix of its `"pa
|
|||||||
### json.exception.out_of_range.415
|
### 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
|
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 MessagePack ext type (max 255)
|
||||||
```
|
```
|
||||||
|
|
||||||
```
|
|
||||||
[json.exception.out_of_range.415] subtype 70000 is too large for the BSON binary subtype (max 255)
|
|
||||||
```
|
|
||||||
|
|
||||||
!!! note
|
!!! 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.
|
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 +1229,7 @@ A JSON Patch operation 'test' failed. The unsuccessful operation is also printed
|
|||||||
### json.exception.other_error.502
|
### 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
|
[`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,
|
`use_type = true` but `use_size = false`. UBJSON requires a size marker (`#`) after a type marker (`$`).
|
||||||
any binary value). UBJSON requires a size marker (`#`) after a type marker (`$`); scalars and empty arrays or objects
|
|
||||||
do not throw.
|
|
||||||
|
|
||||||
!!! failure "Example message"
|
!!! failure "Example message"
|
||||||
|
|
||||||
|
|||||||
@@ -136,6 +136,7 @@ nav:
|
|||||||
- features/performance.md
|
- features/performance.md
|
||||||
- Parsing:
|
- Parsing:
|
||||||
- features/parsing/index.md
|
- features/parsing/index.md
|
||||||
|
- features/parsing/error_recovery.md
|
||||||
- features/parsing/json_lines.md
|
- features/parsing/json_lines.md
|
||||||
- features/parsing/large_and_partial_input.md
|
- features/parsing/large_and_partial_input.md
|
||||||
- features/parsing/parse_exceptions.md
|
- features/parsing/parse_exceptions.md
|
||||||
@@ -173,7 +174,6 @@ nav:
|
|||||||
- 'begin': api/basic_json/begin.md
|
- 'begin': api/basic_json/begin.md
|
||||||
- 'binary': api/basic_json/binary.md
|
- 'binary': api/basic_json/binary.md
|
||||||
- 'binary_t': api/basic_json/binary_t.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
|
- 'boolean_t': api/basic_json/boolean_t.md
|
||||||
- 'cbegin': api/basic_json/cbegin.md
|
- 'cbegin': api/basic_json/cbegin.md
|
||||||
- 'cbor_tag_handler_t': api/basic_json/cbor_tag_handler_t.md
|
- 'cbor_tag_handler_t': api/basic_json/cbor_tag_handler_t.md
|
||||||
@@ -362,7 +362,6 @@ nav:
|
|||||||
- 'Overview': api/adl_serializer/index.md
|
- 'Overview': api/adl_serializer/index.md
|
||||||
- 'from_json': api/adl_serializer/from_json.md
|
- 'from_json': api/adl_serializer/from_json.md
|
||||||
- 'to_json': api/adl_serializer/to_json.md
|
- 'to_json': api/adl_serializer/to_json.md
|
||||||
- 'is_json_view': api/is_json_view.md
|
|
||||||
- 'json': api/json.md
|
- 'json': api/json.md
|
||||||
- 'json_document': api/json_document.md
|
- 'json_document': api/json_document.md
|
||||||
- 'json_editable_document': api/json_editable_document.md
|
- 'json_editable_document': api/json_editable_document.md
|
||||||
@@ -412,7 +411,6 @@ nav:
|
|||||||
- 'ordered_json_editable_view': api/ordered_json_editable_view.md
|
- 'ordered_json_editable_view': api/ordered_json_editable_view.md
|
||||||
- 'ordered_json_view': api/ordered_json_view.md
|
- 'ordered_json_view': api/ordered_json_view.md
|
||||||
- 'ordered_map': api/ordered_map.md
|
- 'ordered_map': api/ordered_map.md
|
||||||
- 'view_mode': api/view_mode.md
|
|
||||||
- macros:
|
- macros:
|
||||||
- 'Overview': api/macros/index.md
|
- 'Overview': api/macros/index.md
|
||||||
- 'JSON_ASSERT': api/macros/json_assert.md
|
- 'JSON_ASSERT': api/macros/json_assert.md
|
||||||
@@ -447,6 +445,8 @@ nav:
|
|||||||
- 'JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON': api/macros/json_use_legacy_discarded_value_comparison.md
|
- '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_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_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_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_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
|
- '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
|
#define NLOHMANN_JSON_ABI_TAG_NO_SIMD
|
||||||
#endif
|
#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
|
#ifndef NLOHMANN_JSON_NAMESPACE_NO_VERSION
|
||||||
#define NLOHMANN_JSON_NAMESPACE_NO_VERSION 0
|
#define NLOHMANN_JSON_NAMESPACE_NO_VERSION 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Construct the namespace ABI tags component
|
// 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_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) \
|
#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)
|
NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b, c, d, e, f, g, h, i, j, k, l, m)
|
||||||
|
|
||||||
#define NLOHMANN_JSON_ABI_TAGS \
|
#define NLOHMANN_JSON_ABI_TAGS \
|
||||||
NLOHMANN_JSON_ABI_TAGS_CONCAT( \
|
NLOHMANN_JSON_ABI_TAGS_CONCAT( \
|
||||||
@@ -149,7 +161,9 @@
|
|||||||
NLOHMANN_JSON_ABI_TAG_OBJECTS_FOR_ENUM_KEYED_MAPS, \
|
NLOHMANN_JSON_ABI_TAG_OBJECTS_FOR_ENUM_KEYED_MAPS, \
|
||||||
NLOHMANN_JSON_ABI_TAG_DISABLE_STREAM_BULK_SCAN, \
|
NLOHMANN_JSON_ABI_TAG_DISABLE_STREAM_BULK_SCAN, \
|
||||||
NLOHMANN_JSON_ABI_TAG_DISABLE_UNLOCKED_FILE_IO, \
|
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
|
// Construct the namespace version component
|
||||||
#define NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT_EX(major, minor, patch) \
|
#define NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT_EX(major, minor, patch) \
|
||||||
|
|||||||
@@ -10,7 +10,6 @@
|
|||||||
|
|
||||||
#include <algorithm> // min, transform
|
#include <algorithm> // min, transform
|
||||||
#include <array> // array
|
#include <array> // array
|
||||||
#include <cstddef> // nullptr_t
|
|
||||||
#include <forward_list> // forward_list
|
#include <forward_list> // forward_list
|
||||||
#include <iterator> // inserter, front_inserter, end
|
#include <iterator> // inserter, front_inserter, end
|
||||||
#include <map> // map
|
#include <map> // map
|
||||||
@@ -28,7 +27,6 @@
|
|||||||
#include <nlohmann/detail/meta/identity_tag.hpp>
|
#include <nlohmann/detail/meta/identity_tag.hpp>
|
||||||
#include <nlohmann/detail/meta/std_fs.hpp>
|
#include <nlohmann/detail/meta/std_fs.hpp>
|
||||||
#include <nlohmann/detail/meta/type_traits.hpp>
|
#include <nlohmann/detail/meta/type_traits.hpp>
|
||||||
#include <nlohmann/detail/output/error_handler.hpp>
|
|
||||||
#include <nlohmann/detail/string_concat.hpp>
|
#include <nlohmann/detail/string_concat.hpp>
|
||||||
#include <nlohmann/detail/value_t.hpp>
|
#include <nlohmann/detail/value_t.hpp>
|
||||||
|
|
||||||
@@ -45,70 +43,6 @@ NLOHMANN_JSON_NAMESPACE_BEGIN
|
|||||||
namespace detail
|
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>
|
template<typename BasicJsonType>
|
||||||
inline void from_json(const BasicJsonType& j, typename std::nullptr_t& n)
|
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;
|
// read a number value of any of the three number types into val;
|
||||||
// returns false (leaving val untouched) if j is not a number
|
// 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)
|
bool get_number_value(const BasicJsonType& j, ArithmeticType& val)
|
||||||
{
|
{
|
||||||
switch (static_cast<value_t>(j))
|
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
|
// overloads for basic_json template parameters
|
||||||
template < typename BasicJsonType, typename ArithmeticType,
|
template < typename BasicJsonType, typename ArithmeticType,
|
||||||
enable_if_t < std::is_arithmetic<ArithmeticType>::value&&
|
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 >
|
int > = 0 >
|
||||||
void get_arithmetic_value(const BasicJsonType& j, ArithmeticType& val)
|
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>
|
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()))
|
if (JSON_HEDLEY_UNLIKELY(!j.is_boolean()))
|
||||||
{
|
{
|
||||||
throw_type_must_be("boolean", j);
|
throw_type_must_be("boolean", j);
|
||||||
}
|
}
|
||||||
b = boolean_value(j);
|
b = *j.template get_ptr<const typename BasicJsonType::boolean_t*>();
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename BasicJsonType>
|
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()))
|
if (JSON_HEDLEY_UNLIKELY(!j.is_string()))
|
||||||
{
|
{
|
||||||
throw_type_must_be("string", j);
|
throw_type_must_be("string", j);
|
||||||
}
|
}
|
||||||
s = string_value(j);
|
s = *j.template get_ptr<const typename BasicJsonType::string_t*>();
|
||||||
}
|
}
|
||||||
|
|
||||||
template <
|
template <
|
||||||
typename BasicJsonType, typename StringType,
|
typename BasicJsonType, typename StringType,
|
||||||
enable_if_t <
|
enable_if_t <
|
||||||
std::is_assignable<StringType&, const typename json_type_of_t<BasicJsonType>::string_t>::value
|
std::is_assignable<StringType&, const typename BasicJsonType::string_t>::value
|
||||||
&& is_detected_exact<typename json_type_of_t<BasicJsonType>::string_t::value_type, value_type_t, StringType>::value
|
&& is_detected_exact<typename 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_same<typename BasicJsonType::string_t, StringType>::value
|
||||||
&& !is_json_ref<StringType>::value, int > = 0 >
|
&& !is_json_ref<StringType>::value, int > = 0 >
|
||||||
inline void from_json(const BasicJsonType& j, StringType& s)
|
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);
|
throw_type_must_be("string", j);
|
||||||
}
|
}
|
||||||
|
|
||||||
s = string_value(j);
|
s = *j.template get_ptr<const typename BasicJsonType::string_t*>();
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename BasicJsonType>
|
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);
|
get_arithmetic_value(j, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename BasicJsonType>
|
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);
|
get_arithmetic_value(j, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename BasicJsonType>
|
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);
|
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;
|
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
|
// 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,
|
using value_type = typename std::conditional<std::is_same<underlying_type, typename BasicJsonType::boolean_t>::value,
|
||||||
typename json_type_of_t<BasicJsonType>::number_unsigned_t, underlying_type>::type;
|
typename BasicJsonType::number_unsigned_t, underlying_type>::type;
|
||||||
value_type val;
|
value_type val;
|
||||||
get_arithmetic_value(j, val);
|
get_arithmetic_value(j, val);
|
||||||
e = static_cast<EnumType>(bool_aware_static_cast<underlying_type>(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
|
// forward_list doesn't have an insert method
|
||||||
template<typename BasicJsonType, typename T, typename Allocator,
|
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)
|
inline void from_json(const BasicJsonType& j, std::forward_list<T, Allocator>& l)
|
||||||
{
|
{
|
||||||
if (JSON_HEDLEY_UNLIKELY(!j.is_array()))
|
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);
|
throw_type_must_be("array", j);
|
||||||
}
|
}
|
||||||
l.clear();
|
l.clear();
|
||||||
auto pos = l.before_begin();
|
std::transform(j.rbegin(), j.rend(),
|
||||||
for (const auto& elem : array_elements(j))
|
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
|
// valarray doesn't have an insert method
|
||||||
template<typename BasicJsonType, typename T,
|
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)
|
inline void from_json(const BasicJsonType& j, std::valarray<T>& l)
|
||||||
{
|
{
|
||||||
if (JSON_HEDLEY_UNLIKELY(!j.is_array()))
|
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);
|
throw_type_must_be("array", j);
|
||||||
}
|
}
|
||||||
l.resize(j.size());
|
l.resize(j.size());
|
||||||
std::size_t i = 0;
|
std::transform(j.begin(), j.end(), std::begin(l),
|
||||||
for (const auto& elem : array_elements(j))
|
[](const BasicJsonType & elem)
|
||||||
{
|
{
|
||||||
l[i++] = elem.template get<T>();
|
return elem.template get<T>();
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// element is not itself a C array: read it directly
|
// 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);
|
from_json_c_array_element(j, arr);
|
||||||
}
|
}
|
||||||
|
|
||||||
// (for a view, array_t is read element by element below)
|
template<typename BasicJsonType>
|
||||||
template<typename BasicJsonType, enable_if_not_view_t<BasicJsonType> = 0>
|
|
||||||
inline void from_json_array_impl(const BasicJsonType& j, typename BasicJsonType::array_t& arr, priority_tag<3> /*unused*/)
|
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*>();
|
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
|
// 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
|
// 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
|
// 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)
|
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*>();
|
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>
|
template<typename BasicJsonType, typename T, std::size_t N>
|
||||||
auto from_json_array_impl(const BasicJsonType& j, std::array<T, N>& arr,
|
auto from_json_array_impl(const BasicJsonType& j, std::array<T, N>& arr,
|
||||||
priority_tag<2> /*unused*/)
|
priority_tag<2> /*unused*/)
|
||||||
@@ -416,8 +322,9 @@ auto from_json_array_impl(const BasicJsonType& j, ConstructibleArrayType& arr, p
|
|||||||
void())
|
void())
|
||||||
{
|
{
|
||||||
ConstructibleArrayType ret;
|
ConstructibleArrayType ret;
|
||||||
reserve_if_possible(ret, j.size(), priority_tag<1> {});
|
const auto* inner_array = j.template get_ptr<const typename BasicJsonType::array_t*>();
|
||||||
for (const auto& elem : array_elements(j))
|
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
|
// get<BasicJsonType>() returns *this, this won't call a from_json
|
||||||
// method when value_type is BasicJsonType
|
// 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,
|
template < typename BasicJsonType, typename ConstructibleArrayType,
|
||||||
enable_if_t <
|
enable_if_t <
|
||||||
is_constructible_array_type<json_type_of_t<BasicJsonType>, ConstructibleArrayType>::value&&
|
is_constructible_array_type<BasicJsonType, ConstructibleArrayType>::value&&
|
||||||
!is_constructible_object_type<json_type_of_t<BasicJsonType>, ConstructibleArrayType>::value&&
|
!is_constructible_object_type<BasicJsonType, ConstructibleArrayType>::value&&
|
||||||
!is_constructible_string_type<json_type_of_t<BasicJsonType>, ConstructibleArrayType>::value&&
|
!is_constructible_string_type<BasicJsonType, ConstructibleArrayType>::value&&
|
||||||
!std::is_same<ConstructibleArrayType, typename json_type_of_t<BasicJsonType>::binary_t>::value&&
|
!std::is_same<ConstructibleArrayType, typename BasicJsonType::binary_t>::value&&
|
||||||
!is_compatible_binary_type<json_type_of_t<BasicJsonType>, ConstructibleArrayType>::value&&
|
!is_compatible_binary_type<BasicJsonType, ConstructibleArrayType>::value&&
|
||||||
!is_basic_json<ConstructibleArrayType>::value,
|
!is_basic_json<ConstructibleArrayType>::value,
|
||||||
int > = 0 >
|
int > = 0 >
|
||||||
auto from_json(const BasicJsonType& j, ConstructibleArrayType& arr)
|
auto from_json(const BasicJsonType& j, ConstructibleArrayType& arr)
|
||||||
@@ -499,24 +406,24 @@ auto from_json(const BasicJsonType& j, identity_tag<std::array<T, N>> tag)
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<typename BasicJsonType>
|
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()))
|
if (JSON_HEDLEY_UNLIKELY(!j.is_binary()))
|
||||||
{
|
{
|
||||||
throw_type_must_be("binary", j);
|
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,
|
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 >
|
int > = 0 >
|
||||||
inline void from_json(const BasicJsonType& j, CompatibleArrayType& bin)
|
inline void from_json(const BasicJsonType& j, CompatibleArrayType& bin)
|
||||||
{
|
{
|
||||||
if (j.is_binary())
|
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())
|
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));
|
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,
|
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)
|
inline void from_json(const BasicJsonType& j, ConstructibleObjectType& obj)
|
||||||
{
|
{
|
||||||
if (JSON_HEDLEY_UNLIKELY(!j.is_object()))
|
if (JSON_HEDLEY_UNLIKELY(!j.is_object()))
|
||||||
@@ -594,7 +462,12 @@ inline void from_json(const BasicJsonType& j, ConstructibleObjectType& obj)
|
|||||||
}
|
}
|
||||||
|
|
||||||
ConstructibleObjectType ret;
|
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);
|
obj = std::move(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -603,10 +476,10 @@ inline void from_json(const BasicJsonType& j, ConstructibleObjectType& obj)
|
|||||||
template < typename BasicJsonType, typename ArithmeticType,
|
template < typename BasicJsonType, typename ArithmeticType,
|
||||||
enable_if_t <
|
enable_if_t <
|
||||||
std::is_arithmetic<ArithmeticType>::value&&
|
std::is_arithmetic<ArithmeticType>::value&&
|
||||||
!std::is_same<ArithmeticType, typename json_type_of_t<BasicJsonType>::number_unsigned_t>::value&&
|
!std::is_same<ArithmeticType, typename BasicJsonType::number_unsigned_t>::value&&
|
||||||
!std::is_same<ArithmeticType, typename json_type_of_t<BasicJsonType>::number_integer_t>::value&&
|
!std::is_same<ArithmeticType, typename BasicJsonType::number_integer_t>::value&&
|
||||||
!std::is_same<ArithmeticType, typename json_type_of_t<BasicJsonType>::number_float_t>::value&&
|
!std::is_same<ArithmeticType, typename BasicJsonType::number_float_t>::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 >
|
int > = 0 >
|
||||||
inline void from_json(const BasicJsonType& j, ArithmeticType& val)
|
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);
|
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>
|
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,
|
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*/)
|
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>();
|
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>
|
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*/)
|
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()");
|
"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...> {});
|
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
|
// 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
|
// the keys (e.g., from NLOHMANN_JSON_SERIALIZE_ENUM); this is the form written
|
||||||
// with JSON_USE_OBJECTS_FOR_ENUM_KEYED_MAPS
|
// 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*/)
|
inline bool from_json_enum_keyed_object(const BasicJsonType& j, Map& m, std::true_type /*key is enum*/)
|
||||||
{
|
{
|
||||||
if (!j.is_object())
|
if (!j.is_object())
|
||||||
@@ -735,24 +608,6 @@ inline bool from_json_enum_keyed_object(const BasicJsonType& j, Map& m, std::tru
|
|||||||
return true;
|
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>
|
template<typename BasicJsonType, typename Map>
|
||||||
inline bool from_json_enum_keyed_object(const BasicJsonType& /*j*/, Map& /*m*/, std::false_type /*key is enum*/)
|
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,
|
template < typename BasicJsonType, typename Key, typename Value, typename Compare, typename Allocator,
|
||||||
typename = enable_if_t < !std::is_constructible <
|
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)
|
void from_json(const BasicJsonType& j, std::map<Key, Value, Compare, Allocator>& m)
|
||||||
{
|
{
|
||||||
// NOLINTNEXTLINE(modernize-type-traits) we use C++11
|
// 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,
|
template < typename BasicJsonType, typename Key, typename Value, typename Hash, typename KeyEqual, typename Allocator,
|
||||||
typename = enable_if_t < !std::is_constructible <
|
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)
|
void from_json(const BasicJsonType& j, std::unordered_map<Key, Value, Hash, KeyEqual, Allocator>& m)
|
||||||
{
|
{
|
||||||
// NOLINTNEXTLINE(modernize-type-traits) we use C++11
|
// 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);
|
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
|
// Checking for C++20 standard or later can be insufficient in case the
|
||||||
// library support for char8_t is either incomplete or was disabled
|
// library support for char8_t is either incomplete or was disabled
|
||||||
// altogether. Use the __cpp_lib_char8_t feature test instead.
|
// 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
|
#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
|
struct from_json_fn
|
||||||
{
|
{
|
||||||
template<typename BasicJsonType, typename T,
|
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
|
||||||
auto operator()(const BasicJsonType& j, T && val) const
|
|
||||||
noexcept(noexcept(from_json(j, std::forward<T>(val))))
|
noexcept(noexcept(from_json(j, std::forward<T>(val))))
|
||||||
-> decltype(from_json(j, std::forward<T>(val)))
|
-> decltype(from_json(j, std::forward<T>(val)))
|
||||||
{
|
{
|
||||||
return 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
|
} // namespace detail
|
||||||
|
|
||||||
#ifndef JSON_HAS_CPP_17
|
#ifndef JSON_HAS_CPP_17
|
||||||
|
|||||||
Loaded 100 of 167 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user