mirror of
https://github.com/nlohmann/json.git
synced 2026-03-16 22:15:59 +00:00
Complete documentation for 3.11.0 (#3464)
* 👥 update contributor and sponsor list * 🚧 document BJData format * 🚧 document BJData format * 📝 clarified documentation of [json.exception.parse_error.112] * ✏️ adjust titles * 📝 add more examples * 🚨 adjust warnings for index.md files * 📝 add more examples * 🔥 remove example for deprecated code * 📝 add missing enum entry * 📝 overwork table for binary formats * ✅ add test to create table for binary formats * 📝 fix wording in example * 📝 add more examples * Update iterators.md (#3481) * ✨ add check for overloads to linter #3455 * 👥 update contributor list * 📝 add more examples * 📝 fix documentation * 📝 add more examples * 🎨 fix indentation * 🔥 remove example for destructor * 📝 overwork documentation * Updated BJData documentation, #3464 (#3493) * update bjdata.md for #3464 * Minor edit * Fix URL typo * Add info on demoting ND array to a 1-D optimized array when singleton dimension Co-authored-by: Chaoqi Zhang <prncoprs@163.com> Co-authored-by: Qianqian Fang <fangqq@gmail.com>
This commit is contained in:
209
docs/mkdocs/docs/features/binary_formats/bjdata.md
Normal file
209
docs/mkdocs/docs/features/binary_formats/bjdata.md
Normal file
@@ -0,0 +1,209 @@
|
||||
# BJData
|
||||
|
||||
The [BJData format](https://neurojson.org) was derived from and improved upon
|
||||
[Universal Binary JSON(UBJSON)](https://ubjson.org) specification (Draft 12).
|
||||
Specifically, it introduces an optimized array container for efficient storage
|
||||
of N-dimensional packed arrays (**ND-arrays**); it also adds 4 new type markers -
|
||||
`[u] - uint16`, `[m] - uint32`, `[M] - uint64` and `[h] - float16` - to
|
||||
unambigiously map common binary numeric types; furthermore, it uses little-endian
|
||||
(LE) to store all numerics instead of big-endian (BE) as in UBJSON to avoid
|
||||
unnecessary conversions on commonly available platforms.
|
||||
|
||||
Compared to other binary-JSON-like formats such as MessagePack and CBOR, both BJData and
|
||||
UBJSON demonstrate a rare combination of being both binary and **quasi-human-readable**. This
|
||||
is because all semantic elements in BJData and UBJSON, including the data-type markers
|
||||
and name/string types are directly human-readable. Data stored in the BJData/UBJSON format
|
||||
are not only compact in size, fast to read/write, but also can be directly searched
|
||||
or read using simple processing.
|
||||
|
||||
!!! abstract "References"
|
||||
|
||||
- [BJData Specification](https://neurojson.org/bjdata/draft2)
|
||||
|
||||
## Serialization
|
||||
|
||||
The library uses the following mapping from JSON values types to BJData types according to the BJData specification:
|
||||
|
||||
| JSON value type | value/range | BJData type | marker |
|
||||
|-----------------|-------------------------------------------|----------------|--------|
|
||||
| null | `null` | null | `Z` |
|
||||
| boolean | `true` | true | `T` |
|
||||
| boolean | `false` | false | `F` |
|
||||
| number_integer | -9223372036854775808..-2147483649 | int64 | `L` |
|
||||
| number_integer | -2147483648..-32769 | int32 | `l` |
|
||||
| number_integer | -32768..-129 | int16 | `I` |
|
||||
| number_integer | -128..127 | int8 | `i` |
|
||||
| number_integer | 128..255 | uint8 | `U` |
|
||||
| number_integer | 256..32767 | int16 | `I` |
|
||||
| number_integer | 32768..65535 | uint16 | `u` |
|
||||
| number_integer | 65536..2147483647 | int32 | `l` |
|
||||
| number_integer | 2147483648..4294967295 | uint32 | `m` |
|
||||
| number_integer | 4294967296..9223372036854775807 | int64 | `L` |
|
||||
| number_integer | 9223372036854775808..18446744073709551615 | uint64 | `M` |
|
||||
| number_unsigned | 0..127 | int8 | `i` |
|
||||
| number_unsigned | 128..255 | uint8 | `U` |
|
||||
| number_unsigned | 256..32767 | int16 | `I` |
|
||||
| number_unsigned | 32768..65535 | uint16 | `u` |
|
||||
| number_unsigned | 65536..2147483647 | int32 | `l` |
|
||||
| number_unsigned | 2147483648..4294967295 | uint32 | `m` |
|
||||
| number_unsigned | 4294967296..9223372036854775807 | int64 | `L` |
|
||||
| number_unsigned | 9223372036854775808..18446744073709551615 | uint64 | `M` |
|
||||
| number_float | *any value* | float64 | `D` |
|
||||
| string | *with shortest length indicator* | string | `S` |
|
||||
| array | *see notes on optimized format/ND-array* | array | `[` |
|
||||
| object | *see notes on optimized format* | map | `{` |
|
||||
|
||||
!!! success "Complete mapping"
|
||||
|
||||
The mapping is **complete** in the sense that any JSON value type can be converted to a BJData value.
|
||||
|
||||
Any BJData output created by `to_bjdata` can be successfully parsed by `from_bjdata`.
|
||||
|
||||
!!! warning "Size constraints"
|
||||
|
||||
The following values can **not** be converted to a BJData value:
|
||||
|
||||
- strings with more than 18446744073709551615 bytes (theoretical)
|
||||
|
||||
!!! info "Unused BJData markers"
|
||||
|
||||
The following markers are not used in the conversion:
|
||||
|
||||
- `Z`: no-op values are not created.
|
||||
- `C`: single-byte strings are serialized with `S` markers.
|
||||
|
||||
!!! info "NaN/infinity handling"
|
||||
|
||||
If NaN or Infinity are stored inside a JSON number, they are
|
||||
serialized properly. This behavior differs from the `dump()`
|
||||
function which serializes NaN or Infinity to `null`.
|
||||
|
||||
|
||||
!!! info "Endianness"
|
||||
|
||||
A breaking difference between BJData and UBJSON is the endianness
|
||||
of numerical values. In BJData, all numerical data types (integers
|
||||
`UiuImlML` and floating-point values `hdD`) are stored in the little-endian (LE)
|
||||
byte order as opposed to big-endian as used by UBJSON. To adopt LE
|
||||
to store numeric records avoids unnecessary byte swapping on most modern
|
||||
computers where LE is used as the default byte order.
|
||||
|
||||
!!! info "Optimized formats"
|
||||
|
||||
The optimized formats for containers are supported: Parameter
|
||||
`use_size` adds size information to the beginning of a container and
|
||||
removes the closing marker. Parameter `use_type` further checks
|
||||
whether all elements of a container have the same type and adds the
|
||||
type marker to the beginning of the container. The `use_type`
|
||||
parameter must only be used together with `use_size = true`.
|
||||
|
||||
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.
|
||||
|
||||
!!! info "ND-array optimized format"
|
||||
|
||||
BJData extends UBJSON's optimized array **size** marker to support
|
||||
ND-array of uniform numerical data types (referred to as the *packed array*).
|
||||
For example, 2-D `uint8` integer array `[[1,2],[3,4],[5,6]]` that can be 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 and stored as `[$U#[$i#i2 2 3 1 2 3 4 5 6`
|
||||
or `[$U#[i2 i3] 1 2 3 4 5 6`.
|
||||
|
||||
In order to maintain the type and dimension information of an ND-array,
|
||||
when this library parses a BJData ND-array via `from_bjdata`, it converts the
|
||||
data into a JSON object, following the **annotated array format** as defined in the
|
||||
[JData specification (Draft 3)](https://github.com/NeuroJSON/jdata/blob/master/JData_specification.md#annotated-storage-of-n-d-arrays).
|
||||
For example, the above 2-D `uint8` array can be parsed and accessed as
|
||||
|
||||
```json
|
||||
{
|
||||
"_ArrayType_": "uint8",
|
||||
"_ArraySize_": [2,3],
|
||||
"_ArrayData_": [1,2,3,4,5,6]
|
||||
}
|
||||
```
|
||||
|
||||
In the reversed direction, when `to_bjdata` detects a JSON object in the
|
||||
above form, it automatically converts such object into a BJData ND-array
|
||||
to generate compact output. The only exception is that when the 1-D dimensional
|
||||
vector stored in `"_ArraySize_"` contains a single integer, or two integers with
|
||||
one being 1, a regular 1-D optimized array is generated.
|
||||
|
||||
The current version of this library has not yet supported automatic
|
||||
recognition and conversion from a nested JSON array input to a BJData ND-array.
|
||||
|
||||
!!! info "Restrictions in optimized data types for arrays and objects"
|
||||
|
||||
Due to diminished space saving, hampered readability, and increased
|
||||
security risks, in BJData, the allowed data types following the `$` marker
|
||||
in an optimized array and object container are restricted to
|
||||
**non-zero-fixed-length** data types. Therefore, the valid optimized
|
||||
type markers can only be one of `UiuImlMLhdDC`. This also means other
|
||||
variable (`[{SH`) or zero-length types (`TFN`) can not be used in an
|
||||
optimized array or object in BJData.
|
||||
|
||||
!!! info "Binary values"
|
||||
|
||||
If the JSON data contains the binary type, the value stored is a list
|
||||
of integers, as suggested by the BJData documentation. In particular,
|
||||
this means that serialization and the deserialization of a JSON
|
||||
containing binary values into BJData and back will result in a
|
||||
different JSON object.
|
||||
|
||||
|
||||
??? example
|
||||
|
||||
```cpp
|
||||
--8<-- "examples/to_bjdata.cpp"
|
||||
```
|
||||
|
||||
Output:
|
||||
|
||||
```c
|
||||
--8<-- "examples/to_bjdata.output"
|
||||
```
|
||||
|
||||
## Deserialization
|
||||
|
||||
The library maps BJData types to JSON value types as follows:
|
||||
|
||||
| BJData type | JSON value type | marker |
|
||||
|-------------|-----------------------------------------|--------|
|
||||
| no-op | *no value, next value is read* | `N` |
|
||||
| null | `null` | `Z` |
|
||||
| false | `false` | `F` |
|
||||
| true | `true` | `T` |
|
||||
| float16 | number_float | `h` |
|
||||
| float32 | number_float | `d` |
|
||||
| float64 | number_float | `D` |
|
||||
| uint8 | number_unsigned | `U` |
|
||||
| int8 | number_integer | `i` |
|
||||
| uint16 | number_unsigned | `u` |
|
||||
| int16 | number_integer | `I` |
|
||||
| uint32 | number_unsigned | `m` |
|
||||
| int32 | number_integer | `l` |
|
||||
| uint64 | number_unsigned | `M` |
|
||||
| int64 | number_integer | `L` |
|
||||
| string | string | `S` |
|
||||
| char | string | `C` |
|
||||
| array | array (optimized values are supported) | `[` |
|
||||
| ND-array | object (in JData annotated array format)|`[$.#[.`|
|
||||
| object | object (optimized values are supported) | `{` |
|
||||
|
||||
!!! success "Complete mapping"
|
||||
|
||||
The mapping is **complete** in the sense that any BJData value can be converted to a JSON value.
|
||||
|
||||
|
||||
??? example
|
||||
|
||||
```cpp
|
||||
--8<-- "examples/from_bjdata.cpp"
|
||||
```
|
||||
|
||||
Output:
|
||||
|
||||
```json
|
||||
--8<-- "examples/from_bjdata.output"
|
||||
```
|
||||
@@ -1,7 +1,9 @@
|
||||
# Binary Formats
|
||||
|
||||
Though JSON is a ubiquitous data format, it is not a very compact format suitable for data exchange, for instance over a network. Hence, the library supports
|
||||
Though JSON is a ubiquitous data format, it is not a very compact format suitable for data exchange, for instance over
|
||||
a network. Hence, the library supports
|
||||
|
||||
- [BJData](bjdata.md) (Binary JData),
|
||||
- [BSON](bson.md) (Binary JSON),
|
||||
- [CBOR](cbor.md) (Concise Binary Object Representation),
|
||||
- [MessagePack](messagepack.md), and
|
||||
@@ -15,6 +17,7 @@ to efficiently encode JSON values to byte vectors and to decode such vectors.
|
||||
|
||||
| Format | Serialization | Deserialization |
|
||||
|-------------|-----------------------------------------------|----------------------------------------------|
|
||||
| BJData | complete | complete |
|
||||
| BSON | incomplete: top-level value must be an object | incomplete, but all JSON types are supported |
|
||||
| CBOR | complete | incomplete, but all JSON types are supported |
|
||||
| MessagePack | complete | complete |
|
||||
@@ -24,6 +27,7 @@ to efficiently encode JSON values to byte vectors and to decode such vectors.
|
||||
|
||||
| Format | Binary values | Binary subtypes |
|
||||
|-------------|---------------|-----------------|
|
||||
| BJData | not supported | not supported |
|
||||
| BSON | supported | supported |
|
||||
| CBOR | supported | supported |
|
||||
| MessagePack | supported | supported |
|
||||
@@ -35,11 +39,14 @@ See [binary values](../binary_values.md) for more information.
|
||||
|
||||
| Format | canada.json | twitter.json | citm_catalog.json | jeopardy.json |
|
||||
|--------------------|-------------|--------------|-------------------|---------------|
|
||||
| BSON | 85,8 % | 95,2 % | 95,8 % | 106,7 % |
|
||||
| CBOR | 50,5 % | 86,3 % | 68,4 % | 88,0 % |
|
||||
| MessagePack | 50,6 % | 86,0 % | 68,5 % | 87,9 % |
|
||||
| UBJSON | 53,2 % | 91,3 % | 78,2 % | 96,6 % |
|
||||
| UBJSON (size) | 58,6 % | 92,3 % | 86,8 % | 97,4 % |
|
||||
| UBJSON (size+type) | 55,9 % | 92,3 % | 85,0 % | 95,0 % |
|
||||
| BJData | 53.2 % | 91.1 % | 78.1 % | 96.6 % |
|
||||
| BJData (size) | 58.6 % | 92.1 % | 86.7 % | 97.4 % |
|
||||
| BJData (size+tyoe) | 58.6 % | 92.1 % | 86.5 % | 97.4 % |
|
||||
| BSON | 85.8 % | 95.2 % | 95.8 % | 106.7 % |
|
||||
| CBOR | 50.5 % | 86.3 % | 68.4 % | 88.0 % |
|
||||
| MessagePack | 50.5 % | 86.0 % | 68.5 % | 87.9 % |
|
||||
| UBJSON | 53.2 % | 91.3 % | 78.2 % | 96.6 % |
|
||||
| UBJSON (size) | 58.6 % | 92.3 % | 86.8 % | 97.4 % |
|
||||
| UBJSON (size+type) | 55.9 % | 92.3 % | 85.0 % | 95.0 % |
|
||||
|
||||
Sizes compared to minified JSON value.
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
# Binary Values
|
||||
|
||||
The library implements several [binary formats](binary_formats/index.md) that encode JSON in an efficient way. Most of these formats support binary values; that is, values that have semantics define outside the library and only define a sequence of bytes to be stored.
|
||||
The library implements several [binary formats](binary_formats/index.md) that encode JSON in an efficient way. Most of
|
||||
these formats support binary values; that is, values that have semantics define outside the library and only define a
|
||||
sequence of bytes to be stored.
|
||||
|
||||
JSON itself does not have a binary value. As such, binary values are an extension that this library implements to store values received by a binary format. Binary values are never created by the JSON parser, and are only part of a serialized JSON text if they have been created manually or via a binary format.
|
||||
JSON itself does not have a binary value. As such, binary values are an extension that this library implements to store
|
||||
values received by a binary format. Binary values are never created by the JSON parser, and are only part of a
|
||||
serialized JSON text if they have been created manually or via a binary format.
|
||||
|
||||
## API for binary values
|
||||
|
||||
@@ -19,7 +23,9 @@ class json::binary_t {
|
||||
"std::vector<uint8_t>" <|-- json::binary_t
|
||||
```
|
||||
|
||||
By default, binary values are stored as `std::vector<std::uint8_t>`. This type can be changed by providing a template parameter to the `basic_json` type. To store binary subtypes, the storage type is extended and exposed as `json::binary_t`:
|
||||
By default, binary values are stored as `std::vector<std::uint8_t>`. This type can be changed by providing a template
|
||||
parameter to the `basic_json` type. To store binary subtypes, the storage type is extended and exposed as
|
||||
`json::binary_t`:
|
||||
|
||||
```cpp
|
||||
auto binary = json::binary_t({0xCA, 0xFE, 0xBA, 0xBE});
|
||||
@@ -87,7 +93,9 @@ Binary values are serialized differently according to the formats.
|
||||
|
||||
### JSON
|
||||
|
||||
JSON does not have a binary type, and this library does not introduce a new type as this would break conformance. Instead, binary values are serialized as an object with two keys: `bytes` holds an array of integers, and `subtype` is an integer or `null`.
|
||||
JSON does not have a binary type, and this library does not introduce a new type as this would break conformance.
|
||||
Instead, binary values are serialized as an object with two keys: `bytes` holds an array of integers, and `subtype`
|
||||
is an integer or `null`.
|
||||
|
||||
??? example
|
||||
|
||||
@@ -115,11 +123,72 @@ JSON does not have a binary type, and this library does not introduce a new type
|
||||
|
||||
!!! warning "No roundtrip for binary values"
|
||||
|
||||
The JSON parser will not parse the objects generated by binary values back to binary values. This is by design to remain standards compliant. Serializing binary values to JSON is only implemented for debugging purposes.
|
||||
The JSON parser will not parse the objects generated by binary values back to binary values. This is by design to
|
||||
remain standards compliant. Serializing binary values to JSON is only implemented for debugging purposes.
|
||||
|
||||
### BJData
|
||||
|
||||
[BJData](binary_formats/bjdata.md) neither supports binary values nor subtypes, and proposes to serialize binary values
|
||||
as array of uint8 values. This translation is implemented by the library.
|
||||
|
||||
??? example
|
||||
|
||||
Code:
|
||||
|
||||
```cpp
|
||||
// create a binary value of subtype 42 (will be ignored in BJData)
|
||||
json j;
|
||||
j["binary"] = json::binary({0xCA, 0xFE, 0xBA, 0xBE}, 42);
|
||||
|
||||
// convert to BJData
|
||||
auto v = json::to_bjdata(j);
|
||||
```
|
||||
|
||||
`v` is a `std::vector<std::uint8t>` with the following 20 elements:
|
||||
|
||||
```c
|
||||
0x7B // '{'
|
||||
0x69 0x06 // i 6 (length of the key)
|
||||
0x62 0x69 0x6E 0x61 0x72 0x79 // "binary"
|
||||
0x5B // '['
|
||||
0x55 0xCA 0x55 0xFE 0x55 0xBA 0x55 0xBE // content (each byte prefixed with 'U')
|
||||
0x5D // ']'
|
||||
0x7D // '}'
|
||||
```
|
||||
|
||||
The following code uses the type and size optimization for UBJSON:
|
||||
|
||||
```cpp
|
||||
// convert to UBJSON using the size and type optimization
|
||||
auto v = json::to_bjdata(j, true, true);
|
||||
```
|
||||
|
||||
The resulting vector has 22 elements; the optimization is not effective for examples with few values:
|
||||
|
||||
```c
|
||||
0x7B // '{'
|
||||
0x23 0x69 0x01 // '#' 'i' type of the array elements: unsigned integers
|
||||
0x69 0x06 // i 6 (length of the key)
|
||||
0x62 0x69 0x6E 0x61 0x72 0x79 // "binary"
|
||||
0x5B // '[' array
|
||||
0x24 0x55 // '$' 'U' type of the array elements: unsigned integers
|
||||
0x23 0x69 0x04 // '#' i 4 number of array elements
|
||||
0xCA 0xFE 0xBA 0xBE // content
|
||||
```
|
||||
|
||||
Note that subtype (42) is **not** serialized and that UBJSON has **no binary type**, and deserializing `v` would
|
||||
yield the following value:
|
||||
|
||||
```json
|
||||
{
|
||||
"binary": [202, 254, 186, 190]
|
||||
}
|
||||
```
|
||||
|
||||
### BSON
|
||||
|
||||
[BSON](binary_formats/bson.md) supports binary values and subtypes. If a subtype is given, it is used and added as unsigned 8-bit integer. If no subtype is given, the generic binary subtype 0x00 is used.
|
||||
[BSON](binary_formats/bson.md) supports binary values and subtypes. If a subtype is given, it is used and added as
|
||||
unsigned 8-bit integer. If no subtype is given, the generic binary subtype 0x00 is used.
|
||||
|
||||
??? example
|
||||
|
||||
@@ -159,7 +228,9 @@ JSON does not have a binary type, and this library does not introduce a new type
|
||||
|
||||
### CBOR
|
||||
|
||||
[CBOR](binary_formats/cbor.md) supports binary values, but no subtypes. Subtypes will be serialized as tags. Any binary value will be serialized as byte strings. The library will choose the smallest representation using the length of the byte array.
|
||||
[CBOR](binary_formats/cbor.md) supports binary values, but no subtypes. Subtypes will be serialized as tags. Any binary
|
||||
value will be serialized as byte strings. The library will choose the smallest representation using the length of the
|
||||
byte array.
|
||||
|
||||
??? example
|
||||
|
||||
@@ -185,7 +256,8 @@ JSON does not have a binary type, and this library does not introduce a new type
|
||||
0xCA 0xFE 0xBA 0xBE // content
|
||||
```
|
||||
|
||||
Note that the subtype is serialized as tag. However, parsing tagged values yield a parse error unless `json::cbor_tag_handler_t::ignore` or `json::cbor_tag_handler_t::store` is passed to `json::from_cbor`.
|
||||
Note that the subtype is serialized as tag. However, parsing tagged values yield a parse error unless
|
||||
`json::cbor_tag_handler_t::ignore` or `json::cbor_tag_handler_t::store` is passed to `json::from_cbor`.
|
||||
|
||||
```json
|
||||
{
|
||||
@@ -198,7 +270,9 @@ JSON does not have a binary type, and this library does not introduce a new type
|
||||
|
||||
### MessagePack
|
||||
|
||||
[MessagePack](binary_formats/messagepack.md) supports binary values and subtypes. If a subtype is given, the ext family is used. The library will choose the smallest representation among fixext1, fixext2, fixext4, fixext8, ext8, ext16, and ext32. The subtype is then added as signed 8-bit integer.
|
||||
[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, ext8, ext16, and
|
||||
ext32. The subtype is then added as signed 8-bit integer.
|
||||
|
||||
If no subtype is given, the bin family (bin8, bin16, bin32) is used.
|
||||
|
||||
@@ -239,7 +313,8 @@ If no subtype is given, the bin family (bin8, bin16, bin32) is used.
|
||||
|
||||
### UBJSON
|
||||
|
||||
[UBJSON](binary_formats/ubjson.md) neither supports binary values nor subtypes, and proposes to serialize binary values as array of uint8 values. This translation is implemented by the library.
|
||||
[UBJSON](binary_formats/ubjson.md) neither supports binary values nor subtypes, and proposes to serialize binary values
|
||||
as array of uint8 values. This translation is implemented by the library.
|
||||
|
||||
??? example
|
||||
|
||||
@@ -251,7 +326,7 @@ If no subtype is given, the bin family (bin8, bin16, bin32) is used.
|
||||
j["binary"] = json::binary({0xCA, 0xFE, 0xBA, 0xBE}, 42);
|
||||
|
||||
// convert to UBJSON
|
||||
auto v = json::to_msgpack(j);
|
||||
auto v = json::to_ubjson(j);
|
||||
```
|
||||
|
||||
`v` is a `std::vector<std::uint8t>` with the following 20 elements:
|
||||
@@ -287,7 +362,8 @@ If no subtype is given, the bin family (bin8, bin16, bin32) is used.
|
||||
0xCA 0xFE 0xBA 0xBE // content
|
||||
```
|
||||
|
||||
Note that subtype (42) is **not** serialized and that UBJSON has **no binary type**, and deserializing `v` would yield the following value:
|
||||
Note that subtype (42) is **not** serialized and that UBJSON has **no binary type**, and deserializing `v` would
|
||||
yield the following value:
|
||||
|
||||
```json
|
||||
{
|
||||
|
||||
@@ -2,9 +2,11 @@
|
||||
|
||||
## Overview
|
||||
|
||||
The `#!cpp at()` member function performs checked access; that is, it returns a reference to the desired value if it exists and throws a [`basic_json::out_of_range` exception](../../home/exceptions.md#out-of-range) otherwise.
|
||||
The [`at`](../../api/basic_json/at.md) member function performs checked access; that is, it returns a reference to the
|
||||
desired value if it exists and throws a [`basic_json::out_of_range` exception](../../home/exceptions.md#out-of-range)
|
||||
otherwise.
|
||||
|
||||
??? example
|
||||
??? example "Read access"
|
||||
|
||||
Consider the following JSON value:
|
||||
|
||||
@@ -18,18 +20,18 @@ The `#!cpp at()` member function performs checked access; that is, it returns a
|
||||
|
||||
Assume the value is parsed to a `json` variable `j`.
|
||||
|
||||
| expression | value |
|
||||
| ---------- | ----- |
|
||||
| `#!cpp j` | `#!json {"name": "Mary Smith", "age": 42, "hobbies": ["hiking", "reading"]}` |
|
||||
| `#!cpp j.at("name")` | `#!json "Mary Smith"` |
|
||||
| `#!cpp j.at("age")` | `#!json 42` |
|
||||
| `#!cpp j.at("hobbies")` | `#!json ["hiking", "reading"]` |
|
||||
| `#!cpp j.at("hobbies").at(0)` | `#!json "hiking"` |
|
||||
| `#!cpp j.at("hobbies").at(1)` | `#!json "reading"` |
|
||||
| expression | value |
|
||||
|-------------------------------|------------------------------------------------------------------------------|
|
||||
| `#!cpp j` | `#!json {"name": "Mary Smith", "age": 42, "hobbies": ["hiking", "reading"]}` |
|
||||
| `#!cpp j.at("name")` | `#!json "Mary Smith"` |
|
||||
| `#!cpp j.at("age")` | `#!json 42` |
|
||||
| `#!cpp j.at("hobbies")` | `#!json ["hiking", "reading"]` |
|
||||
| `#!cpp j.at("hobbies").at(0)` | `#!json "hiking"` |
|
||||
| `#!cpp j.at("hobbies").at(1)` | `#!json "reading"` |
|
||||
|
||||
The return value is a reference, so it can be modified by the original value.
|
||||
|
||||
??? example
|
||||
??? example "Write access"
|
||||
|
||||
```cpp
|
||||
j.at("name") = "John Smith";
|
||||
@@ -45,9 +47,10 @@ The return value is a reference, so it can be modified by the original value.
|
||||
}
|
||||
```
|
||||
|
||||
When accessing an invalid index (i.e., an index greater than or equal to the array size) or the passed object key is non-existing, an exception is thrown.
|
||||
When accessing an invalid index (i.e., an index greater than or equal to the array size) or the passed object key is
|
||||
non-existing, an exception is thrown.
|
||||
|
||||
??? example
|
||||
??? example "Accessing via invalid index or missing key"
|
||||
|
||||
```cpp
|
||||
j.at("hobbies").at(3) = "cooking";
|
||||
@@ -59,13 +62,24 @@ When accessing an invalid index (i.e., an index greater than or equal to the arr
|
||||
[json.exception.out_of_range.401] array index 3 is out of range
|
||||
```
|
||||
|
||||
When you [extended diagnostic messages](../../home/exceptions.md#extended-diagnostic-messages) are enabled by
|
||||
defining [`JSON_DIAGNOSTICS`](../../api/macros/json_diagnostics.md), the exception further gives information where
|
||||
the key or index is missing or out of range.
|
||||
|
||||
```
|
||||
[json.exception.out_of_range.401] (/hobbies) array index 3 is out of range
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
|
||||
!!! failure "Exceptions"
|
||||
|
||||
- `at` can only be used with objects (with a string argument) or with arrays (with a numeric argument). For other types, a [`basic_json::type_error`](../../home/exceptions.md#jsonexceptiontype_error304) is thrown.
|
||||
- [`basic_json::out_of_range` exception](../../home/exceptions.md#out-of-range) exceptions are thrown if the provided key is not found in an object or the provided index is invalid.
|
||||
- [`at`](../../api/basic_json/at.md) can only be used with objects (with a string argument) or with arrays (with a
|
||||
numeric argument). For other types, a [`basic_json::type_error`](../../home/exceptions.md#jsonexceptiontype_error304)
|
||||
is thrown.
|
||||
- [`basic_json::out_of_range` exception](../../home/exceptions.md#out-of-range) exceptions are thrown if the
|
||||
provided key is not found in an object or the provided index is invalid.
|
||||
|
||||
## Summary
|
||||
|
||||
|
||||
@@ -2,9 +2,10 @@
|
||||
|
||||
## Overview
|
||||
|
||||
Elements in a JSON object and a JSON array can be accessed via `#!cpp operator[]` similar to a `#!cpp std::map` and a `#!cpp std::vector`, respectively.
|
||||
Elements in a JSON object and a JSON array can be accessed via [`operator[]`](../../api/basic_json/operator%5B%5D.md)
|
||||
similar to a `#!cpp std::map` and a `#!cpp std::vector`, respectively.
|
||||
|
||||
??? example
|
||||
??? example "Read access"
|
||||
|
||||
Consider the following JSON value:
|
||||
|
||||
@@ -18,18 +19,19 @@ Elements in a JSON object and a JSON array can be accessed via `#!cpp operator[]
|
||||
|
||||
Assume the value is parsed to a `json` variable `j`.
|
||||
|
||||
| expression | value |
|
||||
| ---------- | ----- |
|
||||
| `#!cpp j` | `#!json {"name": "Mary Smith", "age": 42, "hobbies": ["hiking", "reading"]}` |
|
||||
| `#!cpp j["name"]` | `#!json "Mary Smith"` |
|
||||
| `#!cpp j["age"]` | `#!json 42` |
|
||||
| `#!cpp j["hobbies"]` | `#!json ["hiking", "reading"]` |
|
||||
| `#!cpp j["hobbies"][0]` | `#!json "hiking"` |
|
||||
| `#!cpp j["hobbies"][1]` | `#!json "reading"` |
|
||||
| expression | value |
|
||||
|-------------------------|------------------------------------------------------------------------------|
|
||||
| `#!cpp j` | `#!json {"name": "Mary Smith", "age": 42, "hobbies": ["hiking", "reading"]}` |
|
||||
| `#!cpp j["name"]` | `#!json "Mary Smith"` |
|
||||
| `#!cpp j["age"]` | `#!json 42` |
|
||||
| `#!cpp j["hobbies"]` | `#!json ["hiking", "reading"]` |
|
||||
| `#!cpp j["hobbies"][0]` | `#!json "hiking"` |
|
||||
| `#!cpp j["hobbies"][1]` | `#!json "reading"` |
|
||||
|
||||
The return value is a reference, so it can modify the original value. In case the passed object key is non-existing, a `#!json null` value is inserted which can be immediately be overwritten.
|
||||
The return value is a reference, so it can modify the original value. In case the passed object key is non-existing, a
|
||||
`#!json null` value is inserted which can be immediately be overwritten.
|
||||
|
||||
??? example
|
||||
??? example "Write access"
|
||||
|
||||
```cpp
|
||||
j["name"] = "John Smith";
|
||||
@@ -47,9 +49,10 @@ The return value is a reference, so it can modify the original value. In case th
|
||||
}
|
||||
```
|
||||
|
||||
When accessing an invalid index (i.e., an index greater than or equal to the array size), the JSON array is resized such that the passed index is the new maximal index. Intermediate values are filled with `#!json null`.
|
||||
When accessing an invalid index (i.e., an index greater than or equal to the array size), the JSON array is resized such
|
||||
that the passed index is the new maximal index. Intermediate values are filled with `#!json null`.
|
||||
|
||||
??? example
|
||||
??? example "Filling up arrays with `#!json null` values"
|
||||
|
||||
```cpp
|
||||
j["hobbies"][0] = "running";
|
||||
@@ -76,17 +79,23 @@ When accessing an invalid index (i.e., an index greater than or equal to the arr
|
||||
- `#!cpp std::vector::operator[]` never inserts a new element.
|
||||
- `#!cpp std::map::operator[]` is not available for const values.
|
||||
|
||||
The type `#!cpp json` wraps all JSON value types. It would be impossible to remove `operator[]` for const objects. At the same time, inserting elements for non-const objects is really convenient as it avoids awkward `insert` calls. To this end, we decided to have an inserting non-const behavior for both arrays and objects.
|
||||
The type `#!cpp json` wraps all JSON value types. It would be impossible to remove
|
||||
[`operator[]`](../../api/basic_json/operator%5B%5D.md) for const objects. At the same time, inserting elements for
|
||||
non-const objects is really convenient as it avoids awkward `insert` calls. To this end, we decided to have an
|
||||
inserting non-const behavior for both arrays and objects.
|
||||
|
||||
!!! info
|
||||
|
||||
The access is unchecked. In case the passed object key does not exist or the passed array index is invalid, no exception is thrown.
|
||||
The access is unchecked. In case the passed object key does not exist or the passed array index is invalid, no
|
||||
exception is thrown.
|
||||
|
||||
!!! danger
|
||||
|
||||
- It is **undefined behavior** to access a const object with a non-existing key.
|
||||
- It is **undefined behavior** to access a const array with an invalid index.
|
||||
- In debug mode, an **assertion** will fire in both cases. You can disable assertions by defining the preprocessor symbol `#!cpp NDEBUG` or redefine the macro [`JSON_ASSERT(x)`](../macros.md#json_assertx).
|
||||
- In debug mode, an **assertion** will fire in both cases. You can disable assertions by defining the preprocessor
|
||||
symbol `#!cpp NDEBUG` or redefine the macro [`JSON_ASSERT(x)`](../macros.md#json_assertx). See the documentation
|
||||
on [runtime assertions](../assertions.md) for more information.
|
||||
|
||||
!!! failure "Exceptions"
|
||||
|
||||
|
||||
@@ -113,7 +113,7 @@ for (auto& [key, val] : j_object.items())
|
||||
```cpp
|
||||
json j = {1, 2, 3, 4};
|
||||
|
||||
for (auto it = j.begin(); it != j.end(); ++it)
|
||||
for (auto it = j.rbegin(); it != j.rend(); ++it)
|
||||
{
|
||||
std::cout << *it << std::endl;
|
||||
}
|
||||
|
||||
@@ -42,30 +42,13 @@ If you do want to preserve the **insertion order**, you can try the type [`nlohm
|
||||
??? example
|
||||
|
||||
```cpp
|
||||
#include <iostream>
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
using ordered_json = nlohmann::ordered_json;
|
||||
|
||||
int main()
|
||||
{
|
||||
ordered_json j;
|
||||
j["one"] = 1;
|
||||
j["two"] = 2;
|
||||
j["three"] = 3;
|
||||
|
||||
std::cout << j.dump(2) << '\n';
|
||||
}
|
||||
--8<-- "examples/ordered_json.cpp"
|
||||
```
|
||||
|
||||
Output:
|
||||
|
||||
```json
|
||||
{
|
||||
"one": 1,
|
||||
"two": 2,
|
||||
"three": 3
|
||||
}
|
||||
--8<-- "examples/ordered_json.output"
|
||||
```
|
||||
|
||||
Alternatively, you can use a more sophisticated ordered map like [`tsl::ordered_map`](https://github.com/Tessil/ordered-map) ([integration](https://github.com/nlohmann/json/issues/546#issuecomment-304447518)) or [`nlohmann::fifo_map`](https://github.com/nlohmann/fifo_map) ([integration](https://github.com/nlohmann/json/issues/485#issuecomment-333652309)).
|
||||
|
||||
Reference in New Issue
Block a user