mirror of
https://github.com/nlohmann/json.git
synced 2026-10-27 00:08:55 +00:00
docs: address review comments on the new design
- Home: add a "Latest release" button - Sponsors: update the list and group it by tier - Features: list all feature pages on the index page - Releases: add highlights per release, link the 4.0 roadmap, add the first commit to the timeline - Exceptions: prefix all example messages with the exception name - API: no code font for format names in the See also links of the to_/from_ pages - Merge Patch: show the document before, the patch, and the result - Replace "--" with typographic dashes, mark external links with an icon, center Mermaid diagrams Signed-off-by: Niels Lohmann <mail@nlohmann.me>
This commit is contained in:
92 files changed
+626
-496
No files matched your search
@@ -30,7 +30,7 @@ class (either explicitly or via the conversion operators).
|
||||
|
||||
## Return value
|
||||
|
||||
1. (none) -- the converted value is written to the output parameter `val`.
|
||||
1. (none) — the converted value is written to the output parameter `val`.
|
||||
2. the JSON value `j` converted to `TargetType`
|
||||
|
||||
## Examples
|
||||
|
||||
@@ -29,9 +29,9 @@ Linear in the size of `init`.
|
||||
This function is only needed to express two edge cases that cannot be realized with the initializer list constructor
|
||||
([`basic_json(initializer_list_t, bool, value_t)`](basic_json.md)). These cases are:
|
||||
|
||||
1. creating an array whose elements are all pairs whose first element is a string -- in this case, the initializer list
|
||||
1. creating an array whose elements are all pairs whose first element is a string — in this case, the initializer list
|
||||
constructor would create an object, taking the first elements as keys
|
||||
2. creating an empty array -- passing the empty initializer list to the initializer list constructor yields an empty
|
||||
2. creating an empty array — passing the empty initializer list to the initializer list constructor yields an empty
|
||||
object
|
||||
|
||||
## Examples
|
||||
|
||||
@@ -52,7 +52,7 @@ basic_json(basic_json&& other) noexcept;
|
||||
The postcondition of this constructor can be restored by calling [`clear()`](clear.md).
|
||||
|
||||
2. Create a `#!json null` JSON value. It either takes a null pointer as parameter (explicitly creating `#!json null`)
|
||||
or no parameter (implicitly creating `#!json null`). The passed null pointer itself is not read -- it is only used to
|
||||
or no parameter (implicitly creating `#!json null`). The passed null pointer itself is not read — it is only used to
|
||||
choose the right constructor.
|
||||
|
||||
3. This is a "catch all" constructor for all compatible JSON types; that is, types for which a `to_json()` method
|
||||
|
||||
@@ -41,7 +41,7 @@ represent a byte array in modern C++.
|
||||
[`byte_container_with_subtype`](../byte_container_with_subtype/index.md) derives directly from it. Its
|
||||
`value_type` must additionally be exactly one byte wide (e.g., `std::uint8_t`/`char`/`std::byte`): the binary
|
||||
serializers (CBOR, MessagePack, BSON, UBJSON) read and write the container's raw bytes via
|
||||
`reinterpret_cast`, which is only correct for byte-sized elements -- a container like
|
||||
`reinterpret_cast`, which is only correct for byte-sized elements — a container like
|
||||
`#!cpp std::vector<std::intptr_t>` will not work as `BinaryType`. The elements must be stored contiguously, and
|
||||
the binary readers additionally require `resize()` and `operator[]`. See
|
||||
[Template Parameter Requirements](../../features/types/template_parameters.md#binarytype) for the full list.
|
||||
|
||||
@@ -43,7 +43,7 @@ store
|
||||
- [Binary values](../../features/binary_values.md) - how binary values and subtypes are handled
|
||||
- [`from_cbor`](from_cbor.md) - deserializes a JSON value from CBOR
|
||||
- [`input_format_t`](input_format_t.md) - the enumeration of supported input formats
|
||||
- [`CBOR`](../../features/binary_formats/cbor.md) - the article on the CBOR format
|
||||
- [CBOR](../../features/binary_formats/cbor.md) - the article on the CBOR format
|
||||
|
||||
## Version history
|
||||
|
||||
|
||||
@@ -41,7 +41,7 @@ bool empty() const noexcept
|
||||
|
||||
## Notes
|
||||
|
||||
This function does not return whether a string stored as JSON value is empty -- it returns whether the JSON container
|
||||
This function does not return whether a string stored as JSON value is empty — it returns whether the JSON container
|
||||
itself is empty which is `#!cpp false` in the case of a string.
|
||||
|
||||
## Examples
|
||||
|
||||
@@ -96,7 +96,7 @@ Linear in the size of the input.
|
||||
|
||||
## See also
|
||||
|
||||
- [`BON8`](../../features/binary_formats/bon8.md) - the format, its byte layout and how values are mapped
|
||||
- [BON8](../../features/binary_formats/bon8.md) - the format, its byte layout and how values are mapped
|
||||
- [Binary formats](../../features/binary_formats/index.md) - overview and comparison of the supported binary formats
|
||||
- [Parsing untrusted input](../../features/parsing/untrusted_input.md) - limits and safe handling of hostile data
|
||||
- [`to_bon8`](to_bon8.md) - create a BON8 serialization of a JSON value
|
||||
|
||||
@@ -108,7 +108,7 @@ Linear in the size of the input.
|
||||
|
||||
## See also
|
||||
|
||||
- [`BSON`](../../features/binary_formats/bson.md) - the format, its byte layout and how values are mapped
|
||||
- [BSON](../../features/binary_formats/bson.md) - the format, its byte layout and how values are mapped
|
||||
- [Binary formats](../../features/binary_formats/index.md) - overview and comparison of the supported binary formats
|
||||
- [Parsing untrusted input](../../features/parsing/untrusted_input.md) - limits and safe handling of hostile data
|
||||
- [Binary values](../../features/binary_values.md) - how binary values and subtypes are handled
|
||||
|
||||
@@ -114,7 +114,7 @@ Linear in the size of the input.
|
||||
|
||||
## See also
|
||||
|
||||
- [`CBOR`](../../features/binary_formats/cbor.md) - the format, its byte layout and how values are mapped
|
||||
- [CBOR](../../features/binary_formats/cbor.md) - the format, its byte layout and how values are mapped
|
||||
- [Binary formats](../../features/binary_formats/index.md) - overview and comparison of the supported binary formats
|
||||
- [Parsing untrusted input](../../features/parsing/untrusted_input.md) - limits and safe handling of hostile data
|
||||
- [Binary values](../../features/binary_values.md) - how binary values and subtypes are handled
|
||||
|
||||
@@ -107,7 +107,7 @@ Linear in the size of the input.
|
||||
|
||||
## See also
|
||||
|
||||
- [`UBJSON`](../../features/binary_formats/ubjson.md) - the format, its byte layout and how values are mapped
|
||||
- [UBJSON](../../features/binary_formats/ubjson.md) - the format, its byte layout and how values are mapped
|
||||
- [Binary formats](../../features/binary_formats/index.md) - overview and comparison of the supported binary formats
|
||||
- [Parsing untrusted input](../../features/parsing/untrusted_input.md) - limits and safe handling of hostile data
|
||||
- [Binary values](../../features/binary_values.md) - how binary values and subtypes are handled
|
||||
|
||||
@@ -54,7 +54,7 @@ using element_type = decltype(*j_object.items().begin());
|
||||
```
|
||||
|
||||
The per-element type (`iteration_proxy_value`) lives in the library's internal `detail` namespace and is
|
||||
intentionally unspecified as a stable, named type -- `decltype` is the supported way to obtain it, but its exact
|
||||
intentionally unspecified as a stable, named type — `decltype` is the supported way to obtain it, but its exact
|
||||
name/definition may change between versions.
|
||||
|
||||
## Return value
|
||||
|
||||
@@ -33,7 +33,7 @@ constant complexity.
|
||||
|
||||
## Notes
|
||||
|
||||
This function does not return the maximal length of a string stored as JSON value -- it returns the maximal number of
|
||||
This function does not return the maximal length of a string stored as JSON value — it returns the maximal number of
|
||||
string elements the JSON value can store which is `1`.
|
||||
|
||||
## Examples
|
||||
|
||||
@@ -20,7 +20,7 @@ To store objects in C++, a type is defined by the template parameters described
|
||||
`ObjectType`
|
||||
: the container to store objects. Its template parameters must have the same order and meaning as those of
|
||||
`std::map`; in particular, the third parameter is a comparator. `#!cpp std::unordered_map`, whose third parameter
|
||||
is a hash function, therefore needs an adapter -- see
|
||||
is a hash function, therefore needs an adapter — see
|
||||
[Template Parameter Requirements](../../features/types/template_parameters.md#objecttype) for the full list of
|
||||
requirements, an adapter example, and the containers that are known to work.
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ constant complexity.
|
||||
|
||||
## Notes
|
||||
|
||||
This function does not return the length of a string stored as JSON value -- it returns the number of elements in the
|
||||
This function does not return the length of a string stored as JSON value — it returns the number of elements in the
|
||||
JSON value which is `1` in the case of a string.
|
||||
|
||||
## Examples
|
||||
|
||||
@@ -20,7 +20,7 @@ JSON class into byte-sized characters during deserialization.
|
||||
|
||||
`StringType` must have a `char`-compatible `value_type`: the library relies on UTF-8/`char`-based storage and
|
||||
processing internally, so `std::wstring`, `std::u16string`, and `std::u32string` are **not** valid choices for
|
||||
`StringType`. To work with wide-character data, convert it to/from UTF-8 at the boundary instead -- see the
|
||||
`StringType`. To work with wide-character data, convert it to/from UTF-8 at the boundary instead — see the
|
||||
FAQ's [wide string handling](../../home/faq.md#wide-string-handling) section for a conversion recipe.
|
||||
|
||||
Beyond the character type, the library expects a substantial part of the `#!cpp std::string` interface (contiguous
|
||||
|
||||
@@ -82,7 +82,7 @@ Linear in the size of the JSON value `j`.
|
||||
|
||||
## See also
|
||||
|
||||
- [`BON8`](../../features/binary_formats/bon8.md) - the format, its byte layout and how values are mapped
|
||||
- [BON8](../../features/binary_formats/bon8.md) - the format, its byte layout and how values are mapped
|
||||
- [Binary formats](../../features/binary_formats/index.md) - overview and comparison of the supported binary formats
|
||||
- [`from_bon8`](from_bon8.md) - create a JSON value from an input in BON8 format
|
||||
- [`to_cbor`](to_cbor.md) - create a CBOR serialization of a JSON value
|
||||
|
||||
@@ -104,7 +104,7 @@ pass before anything is written.
|
||||
|
||||
## See also
|
||||
|
||||
- [`BSON`](../../features/binary_formats/bson.md) - the format, its byte layout and how values are mapped
|
||||
- [BSON](../../features/binary_formats/bson.md) - the format, its byte layout and how values are mapped
|
||||
- [Binary formats](../../features/binary_formats/index.md) - overview and comparison of the supported binary formats
|
||||
- [Binary values](../../features/binary_values.md) - how binary values and subtypes are handled
|
||||
- [`from_bson`](from_bson.md) - create a JSON value from an input in BSON format
|
||||
|
||||
@@ -77,7 +77,7 @@ Linear in the size of the JSON value `j`.
|
||||
|
||||
## See also
|
||||
|
||||
- [`CBOR`](../../features/binary_formats/cbor.md) - the format, its byte layout and how values are mapped
|
||||
- [CBOR](../../features/binary_formats/cbor.md) - the format, its byte layout and how values are mapped
|
||||
- [Binary formats](../../features/binary_formats/index.md) - overview and comparison of the supported binary formats
|
||||
- [Binary values](../../features/binary_values.md) - how binary values and subtypes are handled
|
||||
- [`from_cbor`](from_cbor.md) - create a JSON value from an input in CBOR format
|
||||
|
||||
@@ -101,7 +101,7 @@ Linear in the size of the JSON value `j`.
|
||||
|
||||
## See also
|
||||
|
||||
- [`UBJSON`](../../features/binary_formats/ubjson.md) - the format, its byte layout and how values are mapped
|
||||
- [UBJSON](../../features/binary_formats/ubjson.md) - the format, its byte layout and how values are mapped
|
||||
- [Binary formats](../../features/binary_formats/index.md) - overview and comparison of the supported binary formats
|
||||
- [Binary values](../../features/binary_values.md) - how binary values and subtypes are handled
|
||||
- [`from_ubjson`](from_ubjson.md) - create a JSON value from an input in UBJSON format
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
const char* type_name() const noexcept;
|
||||
```
|
||||
|
||||
Returns the type name as string to be used in error messages -- usually to indicate that a function was called on a
|
||||
Returns the type name as string to be used in error messages — usually to indicate that a function was called on a
|
||||
wrong JSON type.
|
||||
|
||||
## Return value
|
||||
|
||||
@@ -9,7 +9,7 @@ static bool accept(InputType&& input,
|
||||
|
||||
Checks whether the input is valid JSON, accepting and rejecting exactly what
|
||||
[`BasicJsonType::accept()`](../basic_json/accept.md) does, with the same options. Unlike [`parse()`](parse.md), this
|
||||
function never throws an exception for invalid input, and the returned `#!cpp bool` is the only result -- no document
|
||||
function never throws an exception for invalid input, and the returned `#!cpp bool` is the only result — no document
|
||||
is returned.
|
||||
|
||||
The result is the same as that of `BasicJsonType::accept()` by design; the difference is how the check is made. This
|
||||
|
||||
@@ -54,7 +54,7 @@ has `erase`; calling it on a read-only `basic_json_document` fails to compile (`
|
||||
|
||||
## Exceptions
|
||||
|
||||
1. Throws [`type_error.307`](../../home/exceptions.md#jsonexceptiontype_error307) if `object` is not an object -- the
|
||||
1. Throws [`type_error.307`](../../home/exceptions.md#jsonexceptiontype_error307) if `object` is not an object — the
|
||||
same message [`BasicJsonType::erase`](../basic_json/erase.md) throws for the same type.
|
||||
2. Throws `type_error.307` if `array` is not an array. Throws
|
||||
[`out_of_range.401`](../../home/exceptions.md#jsonexceptionout_of_range401) if `idx` is negative, or if
|
||||
@@ -86,12 +86,12 @@ always starts from this document's own [`root()`](root.md).
|
||||
|
||||
!!! info "Duplicate keys"
|
||||
|
||||
Overload 1. removes *every* member with `key`, not just the first -- unlike [`set`](set.md), which assigns the
|
||||
Overload 1. removes *every* member with `key`, not just the first — unlike [`set`](set.md), which assigns the
|
||||
first occurrence and drops the rest. This is why it returns a count rather than a single view: there may be
|
||||
more than one member removed, or none.
|
||||
|
||||
Like [`set`](set.md) and [`push_back`](push_back.md), `erase` never moves an element's *value*: a view still
|
||||
referring to a removed member or element keeps showing what it last held (see [Edits](index.md#edits)) -- it just no
|
||||
referring to a removed member or element keeps showing what it last held (see [Edits](index.md#edits)) — it just no
|
||||
longer appears when `array`/`object` is read, dumped, or iterated. What does change is the container's sequence of
|
||||
*links* to its elements: removing an element of `array` (2.) shifts the links to the elements after it by one, as
|
||||
[`insert`](insert.md) does in the other direction. *Every* iterator already taken over `array`/`object` is invalidated
|
||||
@@ -101,8 +101,8 @@ by an erase, not only those at or after the removed element, since the container
|
||||
|
||||
??? example
|
||||
|
||||
The example below drops a deprecated field and a decommissioned entry from a configuration document -- using all
|
||||
three overloads -- and shows what stays intact that would not with a plain `json`/`ordered_json` value: the order
|
||||
The example below drops a deprecated field and a decommissioned entry from a configuration document — using all
|
||||
three overloads — and shows what stays intact that would not with a plain `json`/`ordered_json` value: the order
|
||||
of the fields around the ones removed, and the exact spelling of a number that was never touched.
|
||||
|
||||
```cpp
|
||||
|
||||
@@ -108,7 +108,7 @@ points apply to every edit:
|
||||
anything `BasicJsonType` can be constructed from (numbers, strings, `#!cpp bool`, `#!cpp nullptr`, containers, ...).
|
||||
- [`dump()`](../basic_json_view/dump.md) writes an edited document with members in document order, new members at
|
||||
the end, and, with [`number_format::source`](../basic_json_view/number_format.md), keeps the spelling of every
|
||||
number that was not itself edited -- see [Editing a document](../../features/json_view.md#editing-a-document) for
|
||||
number that was not itself edited — see [Editing a document](../../features/json_view.md#editing-a-document) for
|
||||
why this matters.
|
||||
- [`read()`](read.md) discards all edits, [`shrink_to_fit()`](shrink_to_fit.md) does not move the node index once
|
||||
there are edits, and [`memory_usage()`](memory_usage.md) includes the memory edits use.
|
||||
|
||||
@@ -13,8 +13,8 @@ Inserts `value` into `array` as a new element before position `idx`, which must
|
||||
[`push_back`](push_back.md), a [null](../basic_json_view/is_null.md) `array` does *not* first become an empty array:
|
||||
`array` must already be an array.
|
||||
|
||||
`value` is accepted three ways: a [`basic_json_view`](../basic_json_view/index.md) of *any* document -- read-only or
|
||||
editable, and it does not have to be `array`'s own document -- which is copied so that nothing is shared with the
|
||||
`value` is accepted three ways: a [`basic_json_view`](../basic_json_view/index.md) of *any* document — read-only or
|
||||
editable, and it does not have to be `array`'s own document — which is copied so that nothing is shared with the
|
||||
source document afterward; a `BasicJsonType` value; or anything `BasicJsonType` can be constructed from (numbers,
|
||||
strings, `#!cpp bool`, `#!cpp nullptr`, containers, ...).
|
||||
|
||||
@@ -44,16 +44,16 @@ a view of the new element, now holding `value`
|
||||
|
||||
## Exception safety
|
||||
|
||||
Basic exception safety: `value` is fully encoded -- including the checks below -- into storage owned by the document
|
||||
Basic exception safety: `value` is fully encoded — including the checks below — into storage owned by the document
|
||||
before anything already reachable from [`root()`](root.md) is touched, so a failure while encoding `value` (an
|
||||
invalid argument, or `#!cpp std::bad_alloc`) leaves the document completely unchanged, other than memory allocated
|
||||
for the encoding that is not reclaimed. A failure of a later allocation -- while `array` switches from its parsed
|
||||
layout to a growable block, or while that block grows, see [Notes](#notes) -- can still leave `array` already
|
||||
for the encoding that is not reclaimed. A failure of a later allocation — while `array` switches from its parsed
|
||||
layout to a growable block, or while that block grows, see [Notes](#notes) — can still leave `array` already
|
||||
switched to that layout even though `value` itself was not inserted.
|
||||
|
||||
## Exceptions
|
||||
|
||||
Throws [`type_error.309`](../../home/exceptions.md#jsonexceptiontype_error309) if `array` is not an array -- the same
|
||||
Throws [`type_error.309`](../../home/exceptions.md#jsonexceptiontype_error309) if `array` is not an array — the same
|
||||
message [`BasicJsonType::insert`](../basic_json/insert.md) throws for the same type; a null `array` throws this too
|
||||
(see above). Throws [`out_of_range.401`](../../home/exceptions.md#jsonexceptionout_of_range401) if `idx` is negative,
|
||||
or if `#!cpp idx > array.size()`. Throws
|
||||
@@ -62,7 +62,7 @@ document") if `array` is a [discarded](../basic_json_view/is_discarded.md) view
|
||||
Throws [`type_error.302`](../../home/exceptions.md#jsonexceptiontype_error302) if `value` is a
|
||||
[discarded](../basic_json_view/is_discarded.md) view or a [discarded](../basic_json/is_discarded.md) `BasicJsonType`
|
||||
value, and [`type_error.319`](../../home/exceptions.md#jsonexceptiontype_error319) if `value` is (or contains) a
|
||||
binary value -- `BasicJsonType` can hold one, but a `json_document` cannot. Throws
|
||||
binary value — `BasicJsonType` can hold one, but a `json_document` cannot. Throws
|
||||
[`type_error.316`](../../home/exceptions.md#jsonexceptiontype_error316) if `value` is (or contains) a string that is
|
||||
not valid UTF-8, with the same message [`BasicJsonType::dump()`](../basic_json/dump.md) gives for that string.
|
||||
|
||||
@@ -76,8 +76,8 @@ grows in amortized constant time; inserting before the end within that block sti
|
||||
|
||||
## Notes
|
||||
|
||||
Like [`set`](set.md) on a member or an element, `insert` never moves an existing *element's value* -- only where
|
||||
`array`'s *links* to its elements live -- so a view of an existing element of `array` stays valid across an
|
||||
Like [`set`](set.md) on a member or an element, `insert` never moves an existing *element's value* — only where
|
||||
`array`'s *links* to its elements live — so a view of an existing element of `array` stays valid across an
|
||||
`insert`, and keeps referring to the same element even though its index shifts. Any iterator already taken over
|
||||
`array` is invalidated, since it was walking the old layout. See [Edits](index.md#edits) for what stays valid across
|
||||
an edit in general.
|
||||
@@ -88,7 +88,7 @@ an edit in general.
|
||||
|
||||
The example below inserts a step into the middle of a deployment plan, without touching the steps that come
|
||||
after it, and shows that a view taken before the insert keeps referring to the same element even though its
|
||||
index shifts -- something a plain `json`/`ordered_json` array, or its `std::vector`-based storage, has no
|
||||
index shifts — something a plain `json`/`ordered_json` array, or its `std::vector`-based storage, has no
|
||||
equivalent for.
|
||||
|
||||
```cpp
|
||||
|
||||
@@ -16,14 +16,14 @@ static basic_json_document load(std::vector<std::uint8_t>&& image,
|
||||
|
||||
1. Reads an image [`save()`](save.md) wrote, from a pointer and a byte count. The image is **borrowed**: `image`
|
||||
must stay alive and unchanged for as long as the returned document, and any view taken from it, is used.
|
||||
2. Reads an image from a `#!cpp std::vector`. Also **borrowed** -- equivalent to overload 1 called with
|
||||
2. Reads an image from a `#!cpp std::vector`. Also **borrowed** — equivalent to overload 1 called with
|
||||
`#!cpp image.data()` and `#!cpp image.size()`.
|
||||
3. Reads an image, keeping the vector instead of copying it: `image` is moved into the document (no copy), which
|
||||
then owns it for as long as it needs the text and the decoded strings. [`owns_source()`](owns_source.md) is
|
||||
`#!cpp true` afterward.
|
||||
|
||||
In every overload, the node index is copied into storage the document itself owns -- so that it is properly aligned,
|
||||
and, for an [editable](index.md#edits) document, can be edited -- while the text and the decoded strings stay in
|
||||
In every overload, the node index is copied into storage the document itself owns — so that it is properly aligned,
|
||||
and, for an [editable](index.md#edits) document, can be edited — while the text and the decoded strings stay in
|
||||
`image`. The hash indexes [large objects](../../features/json_view.md) use for lookup are rebuilt, exactly as after
|
||||
parsing.
|
||||
|
||||
@@ -49,13 +49,13 @@ Overloads 1 and 2 give the strong guarantee: `image` is only read, never written
|
||||
caller's buffer untouched.
|
||||
|
||||
Overload 3 moves `image` into the document *before* validating it, so that a good image is kept without a copy. If
|
||||
loading then fails, the partially built document -- and the vector now inside it -- is discarded along with the
|
||||
loading then fails, the partially built document — and the vector now inside it — is discarded along with the
|
||||
exception, and `image` itself is left **empty**, not restored to what was passed in. Move a copy in instead, or
|
||||
validate with overload 2 first, if the original vector must survive a failed load.
|
||||
|
||||
## Exceptions
|
||||
|
||||
On a big-endian target, throws [`type_error.320`](../../home/exceptions.md#jsonexceptiontype_error320) -- the same
|
||||
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
|
||||
@@ -66,7 +66,7 @@ Otherwise throws [`parse_error.116`](../../home/exceptions.md#jsonexceptionparse
|
||||
| `too short` | `image` is `#!cpp nullptr`, or `size` is smaller than the 64-byte header |
|
||||
| `unknown format` | the header's magic bytes or version do not match, or a reserved header field is not zero |
|
||||
| `sizes out of range` | the node count, text size, or decoded-string size the header describes does not fit `size`, or the `#!cpp '\0'` after the text or after the decoded strings is missing |
|
||||
| `the check failed` | `check` is not `#!cpp image_check::none`, and the image fails it -- see [`image_check`](#image_check) |
|
||||
| `the check failed` | `check` is not `#!cpp image_check::none`, and the image fails it — see [`image_check`](#image_check) |
|
||||
|
||||
!!! failure "Example messages"
|
||||
|
||||
@@ -116,7 +116,7 @@ How thoroughly `load()` validates `image` before trusting it.
|
||||
token is well-formed and matches the value stored for it. Strings and float tokens may share a range only if the
|
||||
ranges are identical (as nodes that share a value do), and never overlap otherwise. Reading and serializing a
|
||||
checked image is safe and always produces valid JSON, exactly as for a parsed document. This is the right choice for
|
||||
an image from anything you do not fully control -- a file, a cache shared with other processes, a peer on the
|
||||
an image from anything you do not fully control — a file, a cache shared with other processes, a peer on the
|
||||
network.
|
||||
|
||||
`bounds`
|
||||
@@ -136,7 +136,7 @@ How thoroughly `load()` validates `image` before trusting it.
|
||||
your own memory.
|
||||
|
||||
**Lifetime.** Overloads 1 and 2 borrow `image`: it must stay alive and byte-for-byte unchanged for as long as the
|
||||
returned document, and any [view](../basic_json_view/index.md) taken from it, is used -- exactly like a document
|
||||
returned document, and any [view](../basic_json_view/index.md) taken from it, is used — exactly like a document
|
||||
[`parse()`](parse.md) borrowed its input for. Overload 3 avoids this by keeping the vector itself; see
|
||||
[`owns_source`](owns_source.md).
|
||||
|
||||
@@ -145,7 +145,7 @@ returned document, and any [view](../basic_json_view/index.md) taken from it, is
|
||||
The image format is versioned but not yet stable, and may change in an incompatible way before it is declared
|
||||
stable; `load()` already rejects an image written by a different format version with `parse_error.116`
|
||||
("unknown format"). Use images to cache a document within one build of the library, or to hand one to another
|
||||
process running the *same* build on the *same* (little-endian) machine -- not as a long-term storage format.
|
||||
process running the *same* build on the *same* (little-endian) machine — not as a long-term storage format.
|
||||
|
||||
## Examples
|
||||
|
||||
@@ -154,8 +154,8 @@ returned document, and any [view](../basic_json_view/index.md) taken from it, is
|
||||
The example below saves a parsed document as an image, checks that `load()` reproduces the original
|
||||
[`dump()`](../basic_json_view/dump.md) without parsing, and shows the difference between
|
||||
`load(std::move(image))` (owned) and `load(image)` (borrowed). It then damages one byte of the image and shows
|
||||
`image_check::full` rejecting it with `parse_error.116`, while `image_check::bounds` -- meant for a cache the
|
||||
process already trusts -- still reads it without going out of bounds.
|
||||
`image_check::full` rejecting it with `parse_error.116`, while `image_check::bounds` — meant for a cache the
|
||||
process already trusts — still reads it without going out of bounds.
|
||||
|
||||
```cpp
|
||||
--8<-- "examples/basic_json_document__load.cpp"
|
||||
|
||||
@@ -23,7 +23,7 @@ Constant.
|
||||
|
||||
The exact value depends on the platform, the allocator, and the library's own layout, and may change between
|
||||
versions; do not rely on it being a specific number, and do not compare it across different builds or platforms.
|
||||
Compare it for the same document over time, or between documents built with the same binary, instead -- for instance
|
||||
Compare it for the same document over time, or between documents built with the same binary, instead — for instance
|
||||
to observe the effect of [`shrink_to_fit()`](shrink_to_fit.md).
|
||||
|
||||
## Examples
|
||||
|
||||
@@ -24,7 +24,7 @@ Both overloads accept the same JSON text as [`BasicJsonType::parse()`](../basic_
|
||||
the input) instead of a tree of `BasicJsonType` values. They accept every input `BasicJsonType::parse()` takes, and in
|
||||
addition a pointer to a null-terminated wide string (which `BasicJsonType::parse()` rejects). Contiguous inputs of
|
||||
single-byte characters that stay alive can be borrowed; all others (streams, `#!cpp FILE*`, wide characters, which
|
||||
must be converted to UTF-8, and non-contiguous iterators) are read into a copy that the document owns -- see the
|
||||
must be converted to UTF-8, and non-contiguous iterators) are read into a copy that the document owns — see the
|
||||
Notes. Use [`parse_copy()`](parse_copy.md) to get an owned copy of a borrowable input
|
||||
as well.
|
||||
|
||||
@@ -82,8 +82,8 @@ discarded; see [`is_discarded`](is_discarded.md).
|
||||
|
||||
## Exceptions
|
||||
|
||||
Throws the same exception [`BasicJsonType::parse()`](../basic_json/parse.md) throws for the same input and options --
|
||||
the same exception id, message, and position -- because on a failing input the library's own parser is run on the
|
||||
Throws the same exception [`BasicJsonType::parse()`](../basic_json/parse.md) throws for the same input and options —
|
||||
the same exception id, message, and position — because on a failing input the library's own parser is run on the
|
||||
same bytes to produce the diagnostic. This replay runs only for a failing input, and costs about a lexing pass up to
|
||||
the error (its SAX handler builds no values); with `allow_exceptions` set to `#!cpp false`, it is skipped and a
|
||||
discarded document is returned instead. Additionally throws
|
||||
@@ -100,7 +100,7 @@ Linear in the length of the input.
|
||||
|
||||
| `input` | ownership |
|
||||
|--------------------------------------------------------------------------------------|--------------------------------------------------------------|
|
||||
| lvalue byte container (`std::string`, `std::vector<char>`, ...), `std::string_view`, C string, character array | **borrowed** -- `input` must outlive the document |
|
||||
| lvalue byte container (`std::string`, `std::vector<char>`, ...), `std::string_view`, C string, character array | **borrowed** — `input` must outlive the document |
|
||||
| non-const rvalue `#!cpp std::string` | **owned**, moved in without a copy |
|
||||
| other rvalue byte container (including a `#!cpp const` rvalue `#!cpp std::string`) | **owned**, copied |
|
||||
| stream, `#!cpp FILE*`, wide characters, or anything else read through the general input adapter | **owned**, read into a buffer (a stream is read to its end) |
|
||||
@@ -117,8 +117,8 @@ See [`owns_source`](owns_source.md) to check which happened after a call, and th
|
||||
**Numbers.** As for [`BasicJsonType::parse()`](../basic_json/parse.md), an integer literal too large for the 64-bit
|
||||
integer type becomes a floating-point value.
|
||||
|
||||
**No lengths.** An integer argument that is not a `#!cpp bool` where the flags are expected -- for example
|
||||
`#!cpp parse(ptr, len)` -- does not compile (the overload is deleted). Such a call would convert `len` to
|
||||
**No lengths.** An integer argument that is not a `#!cpp bool` where the flags are expected — for example
|
||||
`#!cpp parse(ptr, len)` — does not compile (the overload is deleted). Such a call would convert `len` to
|
||||
`allow_exceptions` and read `ptr` as a null-terminated string, past the end of a buffer that has none. To parse a
|
||||
buffer of a given length, pass a pair of pointers: `#!cpp parse(ptr, ptr + len)`. The same holds for
|
||||
[`parse_copy`](parse_copy.md), [`accept`](accept.md), and [`read`](read.md).
|
||||
|
||||
@@ -8,8 +8,8 @@ view_type push_back(view_type array, V&& value);
|
||||
Appends `value` as a new last element of `array`. A [null](../basic_json_view/is_null.md) `array` first becomes an
|
||||
empty array, the same way [`set`](set.md) turns a null `object` into an empty object.
|
||||
|
||||
`value` is accepted three ways: a [`basic_json_view`](../basic_json_view/index.md) of *any* document -- read-only or
|
||||
editable, and it does not have to be `array`'s own document -- which is copied so that nothing is shared with the
|
||||
`value` is accepted three ways: a [`basic_json_view`](../basic_json_view/index.md) of *any* document — read-only or
|
||||
editable, and it does not have to be `array`'s own document — which is copied so that nothing is shared with the
|
||||
source document afterward; a `BasicJsonType` value; or anything `BasicJsonType` can be constructed from (numbers,
|
||||
strings, `#!cpp bool`, `#!cpp nullptr`, containers, ...).
|
||||
|
||||
@@ -35,23 +35,23 @@ a view of the new last element of `array`, now holding `value`
|
||||
|
||||
## Exception safety
|
||||
|
||||
Basic exception safety: `value` is fully encoded -- including the checks below -- into storage owned by the document
|
||||
Basic exception safety: `value` is fully encoded — including the checks below — into storage owned by the document
|
||||
before anything already reachable from [`root()`](root.md) is touched, so a failure while encoding `value` (an
|
||||
invalid argument, or `#!cpp std::bad_alloc`) leaves the document completely unchanged, other than memory allocated
|
||||
for the encoding that is not reclaimed. A failure of a later allocation -- while `array` switches from its parsed
|
||||
layout to a growable block, or while that block grows, see [Notes](#notes) -- can still leave a partial effect, such
|
||||
for the encoding that is not reclaimed. A failure of a later allocation — while `array` switches from its parsed
|
||||
layout to a growable block, or while that block grows, see [Notes](#notes) — can still leave a partial effect, such
|
||||
as a null `array` argument already turned into an empty array even though `value` itself was not appended.
|
||||
|
||||
## Exceptions
|
||||
|
||||
Throws [`type_error.308`](../../home/exceptions.md#jsonexceptiontype_error308) if `array` is neither an array nor
|
||||
null -- the same message [`BasicJsonType::push_back`](../basic_json/push_back.md) throws for the same type. Throws
|
||||
null — the same message [`BasicJsonType::push_back`](../basic_json/push_back.md) throws for the same type. Throws
|
||||
[`invalid_iterator.202`](../../home/exceptions.md#jsonexceptioninvalid_iterator202) ("view does not belong to this
|
||||
document") if `array` is a [discarded](../basic_json_view/is_discarded.md) view or a view of a *different* document.
|
||||
Throws [`type_error.302`](../../home/exceptions.md#jsonexceptiontype_error302) if `value` is a
|
||||
[discarded](../basic_json_view/is_discarded.md) view or a [discarded](../basic_json/is_discarded.md) `BasicJsonType`
|
||||
value, and [`type_error.319`](../../home/exceptions.md#jsonexceptiontype_error319) if `value` is (or contains) a
|
||||
binary value -- `BasicJsonType` can hold one, but a `json_document` cannot. Throws
|
||||
binary value — `BasicJsonType` can hold one, but a `json_document` cannot. Throws
|
||||
[`type_error.316`](../../home/exceptions.md#jsonexceptiontype_error316) if `value` is (or contains) a string that is
|
||||
not valid UTF-8, with the same message [`BasicJsonType::dump()`](../basic_json/dump.md) gives for that string.
|
||||
|
||||
@@ -59,14 +59,14 @@ not valid UTF-8, with the same message [`BasicJsonType::dump()`](../basic_json/d
|
||||
|
||||
Amortized constant, plus time linear in the size of `value` to encode it into the document's storage (constant for
|
||||
a scalar, linear in the number of nested values for an array or object): the elements of `array` move to a growable
|
||||
block of links the first time it is appended to (or [`set`](set.md) on), and that block itself grows -- doubling its
|
||||
capacity, so the cost of growing it amortizes to constant per element -- only once it runs out of room. See
|
||||
block of links the first time it is appended to (or [`set`](set.md) on), and that block itself grows — doubling its
|
||||
capacity, so the cost of growing it amortizes to constant per element — only once it runs out of room. See
|
||||
[Notes](#notes).
|
||||
|
||||
## Notes
|
||||
|
||||
Like [`set`](set.md) on a member or an element, `push_back` never moves an existing element itself -- only where
|
||||
`array`'s *links* to its elements live -- so a view of an existing element of `array` stays valid across a
|
||||
Like [`set`](set.md) on a member or an element, `push_back` never moves an existing element itself — only where
|
||||
`array`'s *links* to its elements live — so a view of an existing element of `array` stays valid across a
|
||||
`push_back`, but any iterator already taken over `array` is invalidated, since it was walking the old layout. See
|
||||
[Edits](index.md#edits) for what stays valid across an edit in general.
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@ Linear in the length of the input.
|
||||
|
||||
## Notes
|
||||
|
||||
Every view taken from `#!cpp *this` before the call -- including the previous [`root()`](root.md) -- is invalidated,
|
||||
Every view taken from `#!cpp *this` before the call — including the previous [`root()`](root.md) — is invalidated,
|
||||
whether or not the new parse succeeds; take fresh views from [`root()`](root.md) afterward.
|
||||
|
||||
`input` is borrowed or owned by the same rules as [`parse()`](parse.md#notes); a document can borrow on one call and
|
||||
|
||||
@@ -37,8 +37,8 @@ auto v = doc.root();
|
||||
```
|
||||
|
||||
`root()` is a cheap handle into the document's index, not a copy of anything; call it as often as needed. The
|
||||
returned view is valid under the same conditions as any other view of the document -- see
|
||||
[Object inspection](../basic_json_view/index.md) -- in particular, it is invalidated by the next
|
||||
returned view is valid under the same conditions as any other view of the document — see
|
||||
[Object inspection](../basic_json_view/index.md) — in particular, it is invalidated by the next
|
||||
[`read()`](read.md) or [`shrink_to_fit()`](shrink_to_fit.md) on this document. A view can dangle, like a
|
||||
`#!cpp std::string_view`; see [Ownership and lifetime](../../features/json_view.md#ownership-and-lifetime).
|
||||
|
||||
|
||||
@@ -6,13 +6,13 @@ std::vector<std::uint8_t> save() const;
|
||||
|
||||
Writes the document as an *image*: a byte buffer that [`load`](load.md) reads back without parsing. The image holds
|
||||
the node index, the source text (plus, for an edited document, the number tokens edits wrote), and the decoded
|
||||
strings (plus the strings edits wrote) -- everything [`root()`](root.md) needs, with nothing left to parse.
|
||||
strings (plus the strings edits wrote) — everything [`root()`](root.md) needs, with nothing left to parse.
|
||||
|
||||
An edited document is written in its *current* state, with its values in document order, the way the library's own
|
||||
parser would have produced them for that JSON text: a member [`set`](set.md) added goes at the end, an
|
||||
[`erase`](erase.md)d member leaves no trace, and a float that is not finite (NaN or positive/negative infinity)
|
||||
becomes null, the same substitution [`dump()`](../basic_json_view/dump.md) makes. The same document always saves to
|
||||
the same bytes -- also across `BasicJsonType` and `#!cpp Editable`, since the image reflects document order and
|
||||
the same bytes — also across `BasicJsonType` and `#!cpp Editable`, since the image reflects document order and
|
||||
values only, not which specialization produced them.
|
||||
|
||||
## Return value
|
||||
@@ -28,14 +28,14 @@ exactly as it was, and the partially built image is discarded with the exception
|
||||
## Exceptions
|
||||
|
||||
Throws [`type_error.320`](../../home/exceptions.md#jsonexceptiontype_error320) if the document is
|
||||
[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.
|
||||
|
||||
On a big-endian target, throws `type_error.320` with a different message instead: the image format is little-endian
|
||||
only (see [Notes](#notes)).
|
||||
|
||||
Throws [`out_of_range.416`](../../home/exceptions.md#jsonexceptionout_of_range416) if the node count, the text, or
|
||||
the decoded strings of the image would individually reach 4 GiB -- the same 32-bit offsets
|
||||
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.
|
||||
|
||||
!!! failure "Example messages"
|
||||
@@ -61,13 +61,13 @@ up in the image.
|
||||
and the sizes of the text and the decoded strings, all little-endian), followed by the nodes
|
||||
([16 bytes each](../../home/architecture.md#node-index-of-json-views)), the text and a `#!cpp '\0'`, and the decoded
|
||||
strings and a `#!cpp '\0'`. [`load`](load.md) checks the header, and the sizes it describes, before reading anything
|
||||
else -- see [`load`'s Exceptions](load.md#exceptions).
|
||||
else — see [`load`'s Exceptions](load.md#exceptions).
|
||||
|
||||
!!! warning "Experimental"
|
||||
|
||||
The image format is versioned but not yet stable: it may change in an incompatible way before it is declared
|
||||
stable. Use images to cache a document within one build of the library, or to hand one to another process running
|
||||
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.
|
||||
|
||||
**Little-endian only.** The image is written as raw little-endian bytes, with no byte-swapping. `save()` (and
|
||||
@@ -78,8 +78,8 @@ reader could not interpret correctly.
|
||||
|
||||
??? example "Caching a parsed document as an image"
|
||||
|
||||
The example below saves a parsed configuration as an image -- the way a service might cache one to answer later
|
||||
requests without parsing the text again -- and confirms that loading it back gives exactly the same result as
|
||||
The example below saves a parsed configuration as an image — the way a service might cache one to answer later
|
||||
requests without parsing the text again — and confirms that loading it back gives exactly the same result as
|
||||
parsing did, and that saving is deterministic.
|
||||
|
||||
```cpp
|
||||
|
||||
@@ -23,8 +23,8 @@ has `set`; calling it on a read-only `basic_json_document` fails to compile (`#!
|
||||
|
||||
1. Replaces the value `target` refers to with `value`.
|
||||
2. Sets the member `key` of the object `object` to `value`: assigns it if `object` already has a member with this
|
||||
key -- the first one, should the key occur more than once, and the later duplicates are then dropped (see the
|
||||
[Notes](#notes) below) -- or appends a new member at the end otherwise. A [null](../basic_json_view/is_null.md)
|
||||
key — the first one, should the key occur more than once, and the later duplicates are then dropped (see the
|
||||
[Notes](#notes) below) — or appends a new member at the end otherwise. A [null](../basic_json_view/is_null.md)
|
||||
`object` first becomes an empty object.
|
||||
3. Assigns `value` to the element at index `idx` of the array `array`, which must already exist (`#!cpp idx <
|
||||
array.size()`).
|
||||
@@ -37,7 +37,7 @@ has `set`; calling it on a read-only `basic_json_document` fails to compile (`#!
|
||||
null values up to that index), an object otherwise. An empty `ptr` sets [`root()`](root.md) itself, as in 1.
|
||||
|
||||
In every overload, `value` is accepted three ways: a [`basic_json_view`](../basic_json_view/index.md) of *any*
|
||||
document -- read-only or editable, and it does not have to be `target`'s/`object`'s/`array`'s own document -- which
|
||||
document — read-only or editable, and it does not have to be `target`'s/`object`'s/`array`'s own document — which
|
||||
is copied so that nothing is shared with the source document afterward; a `BasicJsonType` value; or anything
|
||||
`BasicJsonType` can be constructed from (numbers, strings, `#!cpp bool`, `#!cpp nullptr`, containers, ...).
|
||||
|
||||
@@ -82,11 +82,11 @@ is copied so that nothing is shared with the source document afterward; a `Basic
|
||||
|
||||
## Exception safety
|
||||
|
||||
Basic exception safety: `value` is fully encoded -- including the checks below -- into storage owned by the document
|
||||
Basic exception safety: `value` is fully encoded — including the checks below — into storage owned by the document
|
||||
before anything already reachable from [`root()`](root.md) is touched, so a failure while encoding `value` (an
|
||||
invalid argument, or `#!cpp std::bad_alloc`) leaves the document completely unchanged, other than memory allocated
|
||||
for the encoding that is not reclaimed. A failure of a later allocation -- while an edited array or object switches
|
||||
from its parsed layout to a growable block, see [Notes](#notes) -- can still leave a partial effect, such as a
|
||||
for the encoding that is not reclaimed. A failure of a later allocation — while an edited array or object switches
|
||||
from its parsed layout to a growable block, see [Notes](#notes) — can still leave a partial effect, such as a
|
||||
[null](../basic_json_view/is_null.md) `object`/`array` argument already turned into an empty object/array even
|
||||
though `value` itself was not linked in. Likewise, a failure of `value` in 4. leaves a null parent that is set with an
|
||||
index beyond 0 already filled with the null values before the index.
|
||||
@@ -95,14 +95,14 @@ index beyond 0 already filled with the null values before the index.
|
||||
|
||||
1. Throws [`type_error.302`](../../home/exceptions.md#jsonexceptiontype_error302) if `value` is a
|
||||
[discarded](../basic_json_view/is_discarded.md) view, or a [discarded](../basic_json/is_discarded.md)
|
||||
`BasicJsonType` value (e.g. `#!cpp BasicJsonType(value_t::discarded)`) -- an object or array `value`, of either
|
||||
`BasicJsonType` value (e.g. `#!cpp BasicJsonType(value_t::discarded)`) — an object or array `value`, of either
|
||||
kind, is fine and is encoded as a whole subtree.
|
||||
2. Throws [`type_error.305`](../../home/exceptions.md#jsonexceptiontype_error305) if `object` is neither an object
|
||||
nor null -- the same message [`operator[]`](../basic_json_view/operator%5B%5D.md) throws for a string argument on
|
||||
nor null — the same message [`operator[]`](../basic_json_view/operator%5B%5D.md) throws for a string argument on
|
||||
such a value. Throws [`type_error.316`](../../home/exceptions.md#jsonexceptiontype_error316) if `key` is not
|
||||
valid UTF-8, with the same message [`BasicJsonType::dump()`](../basic_json/dump.md) gives for that string.
|
||||
Also throws what 1. throws for `value`.
|
||||
3. Throws `type_error.305` if `array` is not an array -- the same message `operator[]` throws for a numeric argument
|
||||
3. Throws `type_error.305` if `array` is not an array — the same message `operator[]` throws for a numeric argument
|
||||
on such a value. Throws [`out_of_range.401`](../../home/exceptions.md#jsonexceptionout_of_range401) if `idx` is
|
||||
negative, or if `#!cpp idx >= array.size()`. Also throws what 1. throws for `value`.
|
||||
4. Throws what [`at`](../basic_json_view/at.md) throws (overload 3) for resolving `ptr`'s parent, except that a
|
||||
@@ -121,7 +121,7 @@ index beyond 0 already filled with the null values before the index.
|
||||
Also throws what 1. throws for `value`.
|
||||
|
||||
Every overload also throws [`type_error.319`](../../home/exceptions.md#jsonexceptiontype_error319) if `value` is (or
|
||||
contains) a binary value -- `BasicJsonType` can hold one, but a `json_document` cannot -- and
|
||||
contains) a binary value — `BasicJsonType` can hold one, but a `json_document` cannot — and
|
||||
[`invalid_iterator.202`](../../home/exceptions.md#jsonexceptioninvalid_iterator202) ("view does not belong to this
|
||||
document") if `target`/`object`/`array` is a [discarded](../basic_json_view/is_discarded.md) view or a view of a
|
||||
*different* document (overloads 1-3 only; overload 4 always starts from this document's own [`root()`](root.md)).
|
||||
@@ -132,7 +132,7 @@ document") if `target`/`object`/`array` is a [discarded](../basic_json_view/is_d
|
||||
number of nested values for an array or object. If `target` is itself an array or object that spans more than one
|
||||
node in its parent's original, unedited layout, and `value` is a scalar, replacing it additionally costs time
|
||||
linear in the size of the document, the *first* time (the parent of `target` is looked up from
|
||||
[`root()`](root.md), and then switches to links) -- see [Notes](#notes). Once the parent has links, `target` is
|
||||
[`root()`](root.md), and then switches to links) — see [Notes](#notes). Once the parent has links, `target` is
|
||||
replaced in constant time: setting every element of a large array one after the other is linear overall. To avoid
|
||||
the lookup altogether, use 3. (or 2. for an object), which know the parent.
|
||||
2. Linear in the number of members of `object`, to find an existing member with `key`, plus the complexity of 1. for
|
||||
@@ -147,7 +147,7 @@ document") if `target`/`object`/`array` is a [discarded](../basic_json_view/is_d
|
||||
!!! info "Duplicate keys"
|
||||
|
||||
If `object` already has more than one member with `key` (2.), the *first* one is assigned `value` and every
|
||||
later member with the same key is removed -- so that a lookup, an iteration, and
|
||||
later member with the same key is removed — so that a lookup, an iteration, and
|
||||
[`materialize()`](../basic_json_view/materialize.md) of `object` afterward all agree on a single value for
|
||||
`key`, the same way [`operator[]`](../basic_json_view/operator%5B%5D.md) already picks the first occurrence of a
|
||||
duplicate key for reading. See the [Notes on duplicate keys](../basic_json_view/operator%5B%5D.md#notes) of
|
||||
@@ -156,8 +156,8 @@ document") if `target`/`object`/`array` is a [discarded](../basic_json_view/is_d
|
||||
Setting a member (2.) or an element (3., through 4.) of an array or object whose elements have not been edited
|
||||
before switches it from its parsed layout to a growable block holding links to its elements; a later
|
||||
[`push_back`](push_back.md) or `set` on the same container reuses that block, growing it (amortized constant time)
|
||||
only once it runs out of room. This never moves an element itself -- only where the container's *links* to its
|
||||
elements live -- so a view of an element stays valid, but any iterator already taken over the container is
|
||||
only once it runs out of room. This never moves an element itself — only where the container's *links* to its
|
||||
elements live — so a view of an element stays valid, but any iterator already taken over the container is
|
||||
invalidated, since it was walking the old layout. See [Edits](index.md#edits) for what stays valid across an edit in
|
||||
general.
|
||||
|
||||
@@ -170,8 +170,8 @@ one-node scalar.
|
||||
|
||||
??? example "Example: (1)/(2)/(3)/(4) replace a value, set a member, assign an element, set via a JSON pointer"
|
||||
|
||||
The example below edits a small configuration document -- replacing a value, adding an object member, assigning
|
||||
an array element, and reaching a field through a JSON pointer -- and shows what
|
||||
The example below edits a small configuration document — replacing a value, adding an object member, assigning
|
||||
an array element, and reaching a field through a JSON pointer — and shows what
|
||||
[`dump()`](../basic_json_view/dump.md) preserves that is lost once the same edits are made on a `BasicJsonType`
|
||||
value instead: the order object members were written in, and the exact spelling of a number that was never
|
||||
touched.
|
||||
|
||||
@@ -15,7 +15,7 @@ basic_json_view at(IntegerType idx) const;
|
||||
basic_json_view at(const json_pointer& ptr) const;
|
||||
```
|
||||
|
||||
1. Returns the value of the object member with key `key` -- the first one, should the key occur more than once (see
|
||||
1. Returns the value of the object member with key `key` — the first one, should the key occur more than once (see
|
||||
[Notes on duplicate keys](operator[].md#notes)).
|
||||
2. Returns the array element at index `idx`. The template accepts every integer type except `#!cpp bool` and
|
||||
`#!cpp std::size_t` and forwards to the `size_type` overload, as for [`operator[]`](operator[].md); a negative
|
||||
@@ -62,7 +62,7 @@ Strong guarantee: there are no changes to the view or the document it refers to.
|
||||
- Throws [`out_of_range.401`](../../home/exceptions.md#jsonexceptionout_of_range401) if an array index in `ptr`
|
||||
is out of range.
|
||||
- Throws [`out_of_range.402`](../../home/exceptions.md#jsonexceptionout_of_range402) if a reference token is
|
||||
`#!cpp "-"` at an array -- `at` never inserts an element, so `#!cpp "-"` is always invalid.
|
||||
`#!cpp "-"` at an array — `at` never inserts an element, so `#!cpp "-"` is always invalid.
|
||||
- Throws [`out_of_range.403`](../../home/exceptions.md#jsonexceptionout_of_range403) if a reference token names
|
||||
an object member that does not exist.
|
||||
- Throws [`out_of_range.404`](../../home/exceptions.md#jsonexceptionout_of_range404) if `ptr` cannot be resolved
|
||||
@@ -76,7 +76,7 @@ None of these exceptions carry a [`JSON_DIAGNOSTICS`](../macros/json_diagnostics
|
||||
|
||||
1. Linear in the number of members: as for [`ordered_json`](../ordered_json.md), members are compared one after
|
||||
another, in document order, stopping at the first match. Each comparison first checks the
|
||||
key's length -- already known from the index, without reading the key bytes -- before comparing its content.
|
||||
key's length — already known from the index, without reading the key bytes — before comparing its content.
|
||||
Objects with 128 or more members get a hash index of their keys while parsing, so that a lookup in them takes
|
||||
constant time on average.
|
||||
2. Linear in `idx`: elements are skipped one at a time from the first one, since they are not a fixed size in the
|
||||
@@ -95,7 +95,7 @@ None of these exceptions carry a [`JSON_DIAGNOSTICS`](../macros/json_diagnostics
|
||||
the last value.
|
||||
|
||||
Unlike [`operator[]`](operator[].md), which returns a [discarded](is_discarded.md) view for a missing key or an
|
||||
out-of-range index, `at` always throws -- exactly as `BasicJsonType::at` does, and with the same messages, so
|
||||
out-of-range index, `at` always throws — exactly as `BasicJsonType::at` does, and with the same messages, so
|
||||
existing error handling written against `BasicJsonType::at` keeps working unchanged when switched to a view. This
|
||||
also holds for overload 3: unlike [`operator[]`](operator[].md) with a JSON pointer, which returns a discarded view
|
||||
for a missing key or an out-of-range index, `at` throws for those too (`out_of_range.403`/`out_of_range.401`).
|
||||
@@ -105,7 +105,7 @@ for a missing key or an out-of-range index, `at` throws for those too (`out_of_r
|
||||
??? example "Example: (1)/(2) access specified element with bounds checking"
|
||||
|
||||
The example below reads required fields out of a service configuration with `at`, and shows that the exceptions
|
||||
it throws -- for a wrong type and for a missing key -- carry the same messages
|
||||
it throws — for a wrong type and for a missing key — carry the same messages
|
||||
[`BasicJsonType::at`](../basic_json/at.md) would produce for the same JSON text.
|
||||
|
||||
```cpp
|
||||
|
||||
@@ -5,7 +5,7 @@ iterator begin() const noexcept;
|
||||
```
|
||||
|
||||
Returns an iterator to the first element of an array, or the first member value of an object, in **document order**
|
||||
-- the order the values appear in the source text, not sorted by key. A primitive value iterates as a range of one
|
||||
— the order the values appear in the source text, not sorted by key. A primitive value iterates as a range of one
|
||||
element (itself), and a `#!json null` value or a [discarded](is_discarded.md) view iterates as an empty range.
|
||||
|
||||
## Return value
|
||||
@@ -22,7 +22,7 @@ Constant.
|
||||
|
||||
## Notes
|
||||
|
||||
For an object, iteration visits **every** member, including all occurrences of a duplicate key -- unlike
|
||||
For an object, iteration visits **every** member, including all occurrences of a duplicate key — unlike
|
||||
[`operator[]`](operator[].md), [`at`](at.md), [`find`](find.md), and [`contains`](contains.md),
|
||||
which all resolve to the *first* member with a given key. See the
|
||||
[Notes on duplicate keys](operator[].md#notes) of `operator[]`.
|
||||
|
||||
@@ -25,7 +25,7 @@ Constant.
|
||||
??? example
|
||||
|
||||
The example below sums many measurements with `std::accumulate`, using `cbegin()`/[`cend()`](cend.md) as the
|
||||
range -- the same way it would for any standard container -- without ever materializing the whole array into a
|
||||
range — the same way it would for any standard container — without ever materializing the whole array into a
|
||||
`BasicJsonType` value.
|
||||
|
||||
```cpp
|
||||
|
||||
@@ -25,7 +25,7 @@ Constant.
|
||||
??? example
|
||||
|
||||
The example below checks that every record of a batch is an object with `std::all_of`, using
|
||||
[`cbegin()`](cbegin.md)/`cend()` as the range -- the same way it would for any standard container -- before
|
||||
[`cbegin()`](cbegin.md)/`cend()` as the range — the same way it would for any standard container — before
|
||||
materializing any record of the batch.
|
||||
|
||||
```cpp
|
||||
|
||||
@@ -34,11 +34,11 @@ No-throw guarantee: this function never throws exceptions.
|
||||
|
||||
1. Linear in the number of members: as for [`ordered_json`](../ordered_json.md), members are compared one after
|
||||
another, in document order, stopping at the first match. Each comparison first checks the
|
||||
key's length -- already known from the index, without reading the key bytes -- before comparing its content.
|
||||
key's length — already known from the index, without reading the key bytes — before comparing its content.
|
||||
Objects with 128 or more members get a hash index of their keys while parsing, so that a lookup in them takes
|
||||
constant time on average.
|
||||
2. Linear in the number of reference tokens of `ptr` and, for each token, in the number of members of the object at
|
||||
that level or the index into the array -- as for [`operator[]`](operator[].md#complexity) and
|
||||
that level or the index into the array — as for [`operator[]`](operator[].md#complexity) and
|
||||
[`at`](at.md#complexity) with a JSON pointer.
|
||||
|
||||
## Notes
|
||||
@@ -50,7 +50,7 @@ No-throw guarantee: this function never throws exceptions.
|
||||
`operator[]` and [Duplicate keys](../../features/json_view.md#duplicate-keys) for the reasons and for how to get
|
||||
the last value.
|
||||
|
||||
Overload 1 always returns `#!cpp false` when the value is not an object -- including a [discarded](is_discarded.md)
|
||||
Overload 1 always returns `#!cpp false` when the value is not an object — including a [discarded](is_discarded.md)
|
||||
view.
|
||||
|
||||
!!! info "Postconditions"
|
||||
|
||||
@@ -27,13 +27,13 @@ No-throw guarantee: this function never throws exceptions.
|
||||
|
||||
Linear in the number of members: unlike the lookup functions, `count()` does not stop at the first match, because it
|
||||
has to count every member with the key. Members are compared one after another, in document order. Each comparison
|
||||
first checks the key's length -- already known from the index, without reading the key bytes -- before comparing its
|
||||
first checks the key's length — already known from the index, without reading the key bytes — before comparing its
|
||||
content. The hash index of the keys of objects with 128 or more members does not help here, since every member
|
||||
is visited.
|
||||
|
||||
## Notes
|
||||
|
||||
This method always returns `#!cpp 0` when the value is not an object -- including a [discarded](is_discarded.md)
|
||||
This method always returns `#!cpp 0` when the value is not an object — including a [discarded](is_discarded.md)
|
||||
view.
|
||||
|
||||
If the source text repeats a key, `count()` returns more than `#!cpp 1` for it, even though the
|
||||
|
||||
@@ -11,7 +11,7 @@ Serializes this value (and its subtree) directly from the flat index, without ev
|
||||
first. With the default `#!cpp numbers == number_format::shortest`, the result is the same string
|
||||
[`BasicJsonType::dump`](../basic_json/dump.md) would produce for the value
|
||||
[`BasicJsonType::parse()`](../basic_json/parse.md) builds from the same source text, called with the same `indent`,
|
||||
`indent_char`, and `ensure_ascii` -- except that members of an object appear in document order rather than sorted by
|
||||
`indent_char`, and `ensure_ascii` — except that members of an object appear in document order rather than sorted by
|
||||
key, and *every* occurrence of a repeated key is written rather than only the last one (see
|
||||
[Notes on duplicate keys](operator[].md#notes)). For a `json_view` (whose `BasicJsonType` is not ordered), this means
|
||||
`dump()` can print an object's members in a different order than [`materialize()`](materialize.md)`.dump()` of the
|
||||
@@ -58,19 +58,19 @@ Linear in the size of the output text.
|
||||
## Notes
|
||||
|
||||
The walk over the subtree is iterative, so the nesting depth it can write is limited by available memory only, not by
|
||||
the call stack -- as for [`materialize()`](materialize.md).
|
||||
the call stack — as for [`materialize()`](materialize.md).
|
||||
|
||||
Strings are escaped by the same rules as [`BasicJsonType::dump`](../basic_json/dump.md).
|
||||
|
||||
With `#!cpp numbers == number_format::shortest`, floats are written with the library's shortest round-trip conversion,
|
||||
exactly as [`BasicJsonType::dump`](../basic_json/dump.md) would (e.g. `#!cpp 1.5`, `#!cpp 100.0`, `#!cpp 1e+100`), and
|
||||
integers are copied from the source text -- already canonical in JSON, so this matches their shortest form too --
|
||||
integers are copied from the source text — already canonical in JSON, so this matches their shortest form too —
|
||||
except that `#!cpp -0` is written as `#!cpp 0`, the way [`BasicJsonType::parse()`](../basic_json/parse.md) reads it.
|
||||
|
||||
`#!cpp number_format::source` copies every number exactly as written in the source text instead, with no exception
|
||||
for `#!cpp -0` -- `#!cpp 1.50`, `#!cpp 1E2`, `#!cpp -0.0`, `#!cpp -0`, or all digits of an integer literal with more
|
||||
for `#!cpp -0` — `#!cpp 1.50`, `#!cpp 1E2`, `#!cpp -0.0`, `#!cpp -0`, or all digits of an integer literal with more
|
||||
digits than any number type holds (such a literal is itself classified as a float, see
|
||||
[What is different](../../features/json_view.md#what-is-different)) -- something `BasicJsonType` cannot do, since
|
||||
[What is different](../../features/json_view.md#what-is-different)) — something `BasicJsonType` cannot do, since
|
||||
parsing already reduces every number to its parsed value.
|
||||
|
||||
## Examples
|
||||
|
||||
@@ -31,7 +31,7 @@ Constant.
|
||||
|
||||
## Notes
|
||||
|
||||
As for [`BasicJsonType::empty()`](../basic_json/empty.md), this does not return whether a string value is empty -- it
|
||||
As for [`BasicJsonType::empty()`](../basic_json/empty.md), this does not return whether a string value is empty — it
|
||||
is `#!cpp false` for any string, regardless of its length.
|
||||
|
||||
## Examples
|
||||
|
||||
@@ -5,7 +5,7 @@ iterator end() const noexcept;
|
||||
```
|
||||
|
||||
Returns an iterator to one past the last element of an array, one past the last member value of an object, in
|
||||
**document order** -- see [`begin()`](begin.md). A primitive value iterates as a range of one element (itself), and a
|
||||
**document order** — see [`begin()`](begin.md). A primitive value iterates as a range of one element (itself), and a
|
||||
`#!json null` value or a [discarded](is_discarded.md) view iterates as an empty range (`#!cpp begin() == end()`).
|
||||
|
||||
## Return value
|
||||
|
||||
@@ -6,7 +6,7 @@ iterator find(const char* key) const;
|
||||
iterator find(const string_t& key) const;
|
||||
```
|
||||
|
||||
Finds a member with key `key` -- the first one, should the key occur more than once (see
|
||||
Finds a member with key `key` — the first one, should the key occur more than once (see
|
||||
[Notes on duplicate keys](operator[].md#notes)). If the value is not an object, or no member has this key,
|
||||
[`end()`](end.md) is returned.
|
||||
|
||||
@@ -27,7 +27,7 @@ No-throw guarantee: this function never throws exceptions.
|
||||
|
||||
Linear in the number of members: as for [`ordered_json`](../ordered_json.md), members are compared one after another,
|
||||
in document order, stopping at the first match. Each comparison first checks the key's length
|
||||
-- already known from the index, without reading the key bytes -- before comparing its content.
|
||||
— already known from the index, without reading the key bytes — before comparing its content.
|
||||
Objects with 128 or more members get a hash index of their keys while parsing, so that a lookup in them takes
|
||||
constant time on average.
|
||||
|
||||
@@ -41,7 +41,7 @@ constant time on average.
|
||||
the last value.
|
||||
|
||||
Unlike [`BasicJsonType::find`](../basic_json/find.md), which always returns `#!cpp end()` for a non-object type, this
|
||||
also does so for a [discarded](is_discarded.md) view -- there is no separate "invalid" iterator to return.
|
||||
also does so for a [discarded](is_discarded.md) view — there is no separate "invalid" iterator to return.
|
||||
|
||||
## Examples
|
||||
|
||||
|
||||
@@ -7,19 +7,19 @@ T get() const;
|
||||
|
||||
Converts the value to `T`.
|
||||
|
||||
For the types below, the conversion works directly on the flat index -- no `BasicJsonType` value is built for it:
|
||||
For the types below, the conversion works directly on the flat index — no `BasicJsonType` value is built for it:
|
||||
|
||||
- `#!cpp bool`
|
||||
- arithmetic types other than `#!cpp bool` (for a boolean, `#!cpp 0`/`#!cpp 1`, exactly as for
|
||||
[`BasicJsonType::get<T>()`](../basic_json/get.md))
|
||||
- `#!cpp std::nullptr_t`
|
||||
- `#!cpp std::basic_string<char, Traits, Alloc>` (including `string_t`) -- a copy of the string
|
||||
- [`string_view_t`](index.md#member-types) -- **no copy**: the returned view points into the document's
|
||||
- `#!cpp std::basic_string<char, Traits, Alloc>` (including `string_t`) — a copy of the string
|
||||
- [`string_view_t`](index.md#member-types) — **no copy**: the returned view points into the document's
|
||||
[`source()`](../basic_json_document/source.md) text, or, for a string that contains escape sequences, into the
|
||||
document's own buffer of decoded strings (see [`get_string()`](get_string.md))
|
||||
- `BasicJsonType` -- equivalent to [`materialize()`](materialize.md)
|
||||
- `basic_json_view` -- returns `#!cpp *this`
|
||||
- `#!cpp std::vector<U, A>` -- from an array, element by element, each converted with `#!cpp get<U>()`; `#!cpp
|
||||
- `BasicJsonType` — equivalent to [`materialize()`](materialize.md)
|
||||
- `basic_json_view` — returns `#!cpp *this`
|
||||
- `#!cpp std::vector<U, A>` — from an array, element by element, each converted with `#!cpp get<U>()`; `#!cpp
|
||||
std::vector<basic_json_view>` keeps a view of every element instead of a value
|
||||
- `#!cpp std::map<K, V, C, A>` and `#!cpp std::unordered_map<K, V, H, E, A>`, if `K` is constructible from a `#!cpp
|
||||
(const char*, std::size_t)` pair -- from an object, member by member, each value converted with `#!cpp get<V>()`; with a repeated
|
||||
@@ -27,8 +27,8 @@ For the types below, the conversion works directly on the flat index -- no `Basi
|
||||
[`materialize()`](materialize.md)) does; `#!cpp std::map<std::string, basic_json_view>` keeps views of the members
|
||||
instead of values
|
||||
|
||||
Every other `T` -- `#!cpp std::list`, `#!cpp std::pair`, `#!cpp std::array`, enumerations, user types with a
|
||||
`from_json()`, ... -- is converted by `#!cpp materialize().get<T>()`: the subtree is built into a real `BasicJsonType`
|
||||
Every other `T` — `#!cpp std::list`, `#!cpp std::pair`, `#!cpp std::array`, enumerations, user types with a
|
||||
`from_json()`, ... — is converted by `#!cpp materialize().get<T>()`: the subtree is built into a real `BasicJsonType`
|
||||
value first (as [`BasicJsonType::parse()`](../basic_json/parse.md) would), and converted from there exactly as
|
||||
[`BasicJsonType::get<T>()`](../basic_json/get.md) would convert it.
|
||||
|
||||
@@ -49,13 +49,13 @@ Strong guarantee: there are no changes to the view or the document it refers to.
|
||||
|
||||
- For the directly-converted types listed above (other than `BasicJsonType` and `basic_json_view`, which never
|
||||
throw): throws [`type_error.302`](../../home/exceptions.md#jsonexceptiontype_error302) if the value's type does not
|
||||
match `T` -- the same exception, with the same message, that [`BasicJsonType::get<T>()`](../basic_json/get.md)
|
||||
match `T` — the same exception, with the same message, that [`BasicJsonType::get<T>()`](../basic_json/get.md)
|
||||
throws for the same JSON type and `T`.
|
||||
- For `#!cpp std::vector<U, A>`: throws `type_error.302` if the value is not an array; otherwise, whatever converting
|
||||
an element to `U` throws.
|
||||
- For `#!cpp std::map`/`#!cpp std::unordered_map`: throws `type_error.302` if the value is not an object; otherwise,
|
||||
whatever converting a member to the mapped type throws.
|
||||
- For every other `T`: whatever [`materialize().get<T>()`](../basic_json/get.md) throws -- typically `type_error.302`,
|
||||
- For every other `T`: whatever [`materialize().get<T>()`](../basic_json/get.md) throws — typically `type_error.302`,
|
||||
or whatever a user-provided `from_json()` throws.
|
||||
|
||||
None of the exceptions thrown directly by this function (the first three bullets above) carry a
|
||||
@@ -107,7 +107,7 @@ document.
|
||||
|
||||
The example below reads typed fields straight into C++ variables, collects a view of every array element with
|
||||
`#!cpp get<std::vector<basic_json_view>>()` instead of a value, and converts a nested object into a user type
|
||||
through its `from_json()` -- which runs on a `BasicJsonType` value `materialize()` builds for just that one
|
||||
through its `from_json()` — which runs on a `BasicJsonType` value `materialize()` builds for just that one
|
||||
member.
|
||||
|
||||
```cpp
|
||||
|
||||
@@ -41,8 +41,8 @@ counterpart, except that it returns a view instead of a reference to a value tha
|
||||
document, the returned [`string_view_t`](index.md#member-types) is valid as long as the caller's buffer; for an owned
|
||||
one, as long as the document.
|
||||
|
||||
The returned [`string_view_t`](index.md#member-types) is valid exactly as long as the view that produced it -- see the
|
||||
[validity rules](index.md) of `basic_json_view` -- and, for a string with no escapes, for as long as the document's
|
||||
The returned [`string_view_t`](index.md#member-types) is valid exactly as long as the view that produced it — see the
|
||||
[validity rules](index.md) of `basic_json_view` — and, for a string with no escapes, for as long as the document's
|
||||
source text, which for a borrowed document must remain valid **and unmodified** for as long as the document exists,
|
||||
since floating-point values and unescaped strings are read from the source lazily.
|
||||
|
||||
@@ -52,8 +52,8 @@ since floating-point values and unescaped strings are read from the source lazil
|
||||
|
||||
The example below pulls one field out of a JSON text that stands in for a large API response, and shows that no
|
||||
`#!cpp std::string` was allocated for it: the returned view still points inside the original buffer. A field that
|
||||
contains an escape sequence cannot point into the original text -- it was decoded once into the document's own
|
||||
buffer instead -- but still avoids a per-field allocation.
|
||||
contains an escape sequence cannot point into the original text — it was decoded once into the document's own
|
||||
buffer instead — but still avoids a per-field allocation.
|
||||
|
||||
```cpp
|
||||
--8<-- "examples/basic_json_view__get_string.cpp"
|
||||
|
||||
@@ -7,9 +7,9 @@ T& get_to(T& v) const;
|
||||
|
||||
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`,
|
||||
`basic_json_view`, `#!cpp std::vector`, and `#!cpp std::map`/`#!cpp std::unordered_map` with string keys -- `v` is
|
||||
`basic_json_view`, `#!cpp std::vector`, and `#!cpp std::map`/`#!cpp std::unordered_map` with string keys — `v` is
|
||||
assigned: `#!cpp v = get<T>()`.
|
||||
- For every other type, the subtree is built into a `BasicJsonType` value and `#!cpp materialize().get_to(v)` is
|
||||
called, i.e. `from_json()` is invoked with the existing `v`, exactly as
|
||||
|
||||
@@ -36,11 +36,11 @@ Moving the document itself does not invalidate its views: the index is heap-allo
|
||||
[`json_pointer`](../json_pointer/index.md). Unlike `basic_json`, there are no implicit conversion operators (no
|
||||
`#!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 Editable == true`) sees every edit made through
|
||||
[`basic_json_document::set`](../basic_json_document/set.md) and
|
||||
[`basic_json_document::push_back`](../basic_json_document/push_back.md): once a value is changed, every view that
|
||||
still refers to it -- including ones taken before the change -- reads the new value. See
|
||||
still refers to it — including ones taken before the change — reads the new value. See
|
||||
[Edits](../basic_json_document/index.md#edits).
|
||||
|
||||
## Template parameters
|
||||
|
||||
@@ -6,7 +6,7 @@ bool is_discarded() const noexcept;
|
||||
|
||||
Returns whether this view is invalid, i.e. does not refer to a value. This is the case for a default-constructed
|
||||
view (see [(constructor)](basic_json_view.md)), and for [`root()`](../basic_json_document/root.md) of a document
|
||||
that is itself [discarded](../basic_json_document/is_discarded.md) -- in particular, the root of a failed
|
||||
that is itself [discarded](../basic_json_document/is_discarded.md) — in particular, the root of a failed
|
||||
[`parse()`](../basic_json_document/parse.md) with `allow_exceptions` set to `#!cpp false`.
|
||||
|
||||
A discarded view is also what [`operator[]`](operator[].md) returns for a missing key, an index out of range, or a
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
/* unspecified */ items() const noexcept;
|
||||
```
|
||||
|
||||
Returns a range of items -- (key, value) pairs -- for use in range-based for loops. An item's `#!cpp key()` is a
|
||||
Returns a range of items — (key, value) pairs — for use in range-based for loops. An item's `#!cpp key()` is a
|
||||
`#!cpp string_view_t` (for an array element, its index converted to a string, as for
|
||||
[`BasicJsonType::items()`](../basic_json/items.md)), and its `#!cpp value()` is a `basic_json_view` of the element.
|
||||
|
||||
@@ -47,7 +47,7 @@ Constant.
|
||||
## Notes
|
||||
|
||||
As for [`begin()`](begin.md)/[`end()`](end.md), `items()` visits **every** member of an object, including all
|
||||
occurrences of a duplicate key -- unlike [`operator[]`](operator[].md), [`at`](at.md), [`find`](find.md),
|
||||
occurrences of a duplicate key — unlike [`operator[]`](operator[].md), [`at`](at.md), [`find`](find.md),
|
||||
and [`contains`](contains.md), which resolve to the *first* member with a given key. See the
|
||||
[Notes on duplicate keys](operator[].md#notes) of `operator[]`.
|
||||
|
||||
@@ -63,8 +63,8 @@ and [`contains`](contains.md), which resolve to the *first* member with a given
|
||||
|
||||
The example below shows a settings object whose source text records every update to a key as a duplicate
|
||||
member, in the order they happened. `items()` walks all of them, so the update history is visible, while
|
||||
[`operator[]`](operator[].md) only ever sees the *first* one and [`materialize()`](materialize.md) -- like
|
||||
[`BasicJsonType::parse()`](../basic_json/parse.md) -- keeps only the *last*.
|
||||
[`operator[]`](operator[].md) only ever sees the *first* one and [`materialize()`](materialize.md) — like
|
||||
[`BasicJsonType::parse()`](../basic_json/parse.md) — keeps only the *last*.
|
||||
|
||||
```cpp
|
||||
--8<-- "examples/basic_json_view__items.cpp"
|
||||
|
||||
@@ -28,7 +28,7 @@ Linear in the size of the subtree.
|
||||
## Notes
|
||||
|
||||
`materialize()` replays the subtree through the same SAX builder [`BasicJsonType::parse()`](../basic_json/parse.md)
|
||||
uses, so the result matches it exactly -- including, for an object, that a repeated key keeps only its
|
||||
uses, so the result matches it exactly — including, for an object, that a repeated key keeps only its
|
||||
last value. The replay is iterative, so it is not limited by the call stack the way a naive recursive conversion
|
||||
would be; the JSON nesting depth is limited only by available memory, as for `BasicJsonType::parse()` itself.
|
||||
|
||||
@@ -43,7 +43,7 @@ never caches the result.
|
||||
|
||||
??? example
|
||||
|
||||
The example below skips messages that are not useful -- a discarded value, or an empty array -- using only
|
||||
The example below skips messages that are not useful — a discarded value, or an empty array — using only
|
||||
[`is_array()`](is_array.md) and [`empty()`](empty.md), and calls `materialize()` only for the messages that are
|
||||
actually used, so no `BasicJsonType` value (and none of its per-element allocations) is ever built for the
|
||||
skipped ones.
|
||||
|
||||
@@ -10,14 +10,14 @@ enum class number_format {
|
||||
This enumeration is used in [`dump`](dump.md) to choose how numbers are written. Two values are differentiated:
|
||||
|
||||
shortest
|
||||
: integers are copied from the source text -- already canonical in JSON -- except that `#!cpp -0` becomes
|
||||
: integers are copied from the source text — already canonical in JSON — except that `#!cpp -0` becomes
|
||||
`#!cpp 0`, the way [`BasicJsonType::parse()`](../basic_json/parse.md) reads it; floats are written with the
|
||||
library's shortest round-trip conversion, exactly as [`BasicJsonType::dump()`](../basic_json/dump.md) would (e.g.
|
||||
`#!cpp 1.5`, `#!cpp 100.0`, `#!cpp 1e+100`)
|
||||
|
||||
source
|
||||
: every number is copied exactly as it appears in the source text -- `#!cpp 1.50`, `#!cpp 1E2`, `#!cpp -0`, all
|
||||
digits of an integer literal with more digits than any number type holds -- something `BasicJsonType` cannot do,
|
||||
: every number is copied exactly as it appears in the source text — `#!cpp 1.50`, `#!cpp 1E2`, `#!cpp -0`, all
|
||||
digits of an integer literal with more digits than any number type holds — something `BasicJsonType` cannot do,
|
||||
since parsing already reduces every number to its parsed value
|
||||
|
||||
## Examples
|
||||
|
||||
@@ -9,7 +9,7 @@ Returns the number exactly as it appears in the source text, without parsing or
|
||||
## Return value
|
||||
|
||||
The number's token text, as a [`string_view_t`](index.md#member-types) into the document's
|
||||
[`source()`](../basic_json_document/source.md) text -- for example `#!cpp "1.50"`, `#!cpp "1E2"`, `#!cpp "-0"`, or an
|
||||
[`source()`](../basic_json_document/source.md) text — for example `#!cpp "1.50"`, `#!cpp "1E2"`, `#!cpp "-0"`, or an
|
||||
integer literal with more digits than any number type holds (such as a 30-digit integer, which [`get<T>()`](get.md)
|
||||
and [`materialize()`](materialize.md) can only represent approximately, as a `number_float_t`).
|
||||
|
||||
@@ -35,12 +35,12 @@ Constant.
|
||||
`BasicJsonType` has no counterpart to this function: once a number is parsed into `number_integer_t`,
|
||||
`number_unsigned_t`, or `number_float_t`, its original textual form (leading zeros aside, which are already rejected
|
||||
by the grammar; trailing zeros in the fraction; the case and sign of the exponent; ...) is gone. `number_token()` is
|
||||
useful precisely where that form must survive -- a price or an identifier that must be reproduced exactly, or a
|
||||
useful precisely where that form must survive — a price or an identifier that must be reproduced exactly, or a
|
||||
number too large for any of `BasicJsonType`'s number types to hold without loss.
|
||||
|
||||
The returned [`string_view_t`](index.md#member-types) always points into the document's
|
||||
[`source()`](../basic_json_document/source.md) text -- numbers are never decoded into the document's separate string
|
||||
buffer -- and is valid exactly as long as that text is, see the [validity rules](index.md) of `basic_json_view`.
|
||||
[`source()`](../basic_json_document/source.md) text — numbers are never decoded into the document's separate string
|
||||
buffer — and is valid exactly as long as that text is, see the [validity rules](index.md) of `basic_json_view`.
|
||||
|
||||
## Examples
|
||||
|
||||
@@ -48,7 +48,7 @@ buffer -- and is valid exactly as long as that text is, see the [validity rules]
|
||||
|
||||
The example below keeps a price and an order ID exactly as they were written in an incoming order, where
|
||||
converting them with [`get<T>()`](get.md) would lose information: the price picks up floating-point rounding, and
|
||||
the order ID -- more digits than a 64-bit integer holds -- can only be approximated as a `#!cpp double` once
|
||||
the order ID — more digits than a 64-bit integer holds — can only be approximated as a `#!cpp double` once
|
||||
`#!cpp materialize()`d.
|
||||
|
||||
```cpp
|
||||
|
||||
@@ -15,8 +15,8 @@ basic_json_view operator[](IntegerType idx) const;
|
||||
basic_json_view operator[](const json_pointer& ptr) const;
|
||||
```
|
||||
|
||||
1. Returns the value of the object member with key `key` -- the first one, should the key occur more than once (see
|
||||
the [Notes](#notes) below) -- or a [discarded](is_discarded.md) view if there is no such member.
|
||||
1. Returns the value of the object member with key `key` — the first one, should the key occur more than once (see
|
||||
the [Notes](#notes) below) — or a [discarded](is_discarded.md) view if there is no such member.
|
||||
2. Returns the array element at index `idx`, or a [discarded](is_discarded.md) view if `idx` is out of range. The
|
||||
template accepts every integer type except `#!cpp bool` and `#!cpp std::size_t` (`#!cpp int`, `#!cpp unsigned`,
|
||||
`#!cpp long`, `#!cpp std::int64_t`, ...) and forwards to the `size_type` overload, so that an integer argument is
|
||||
@@ -55,11 +55,11 @@ Strong guarantee: there are no changes to the view or the document it refers to.
|
||||
## Exceptions
|
||||
|
||||
1. Throws [`type_error.305`](../../home/exceptions.md#jsonexceptiontype_error305) if the value is not an object and
|
||||
not [discarded](is_discarded.md) --
|
||||
not [discarded](is_discarded.md) —
|
||||
the same exception, with the same message, that the **const** overload of
|
||||
[`BasicJsonType::operator[]`](../basic_json/operator%5B%5D.md) throws for a string argument on a non-object value.
|
||||
2. Throws [`type_error.305`](../../home/exceptions.md#jsonexceptiontype_error305) if the value is not an array and
|
||||
not [discarded](is_discarded.md) --
|
||||
not [discarded](is_discarded.md) —
|
||||
the same exception, with the same message, that the **const** overload of
|
||||
[`BasicJsonType::operator[]`](../basic_json/operator%5B%5D.md) throws for a numeric argument on a non-array value.
|
||||
3. Throws the same exceptions, with the same messages, that the **const** overload of
|
||||
@@ -81,7 +81,7 @@ None of these exceptions carry a [`JSON_DIAGNOSTICS`](../macros/json_diagnostics
|
||||
|
||||
1. Linear in the number of members: as for [`ordered_json`](../ordered_json.md), members are compared one after
|
||||
another, in document order, stopping at the first match. Each comparison first checks the
|
||||
key's length -- already known from the index, without reading the key bytes -- before comparing its content, so a
|
||||
key's length — already known from the index, without reading the key bytes — before comparing its content, so a
|
||||
key of a different length than `key` is rejected without touching the source text.
|
||||
Objects with 128 or more members get a hash index of their keys while parsing, so that a lookup in them takes
|
||||
constant time on average.
|
||||
@@ -97,7 +97,7 @@ Unlike `BasicJsonType::operator[]`, which is undefined behavior (guarded by a
|
||||
[runtime assertion](../../features/assertions.md)) for a missing key on a **const** value, this operator returns a
|
||||
safe, testable result for a missing key or an index out of range: a [discarded](is_discarded.md) view, which is
|
||||
tested with [`is_discarded`](is_discarded.md).
|
||||
There is also no non-const overload that inserts a missing key or extends an array -- a view never modifies the
|
||||
There is also no non-const overload that inserts a missing key or extends an array — a view never modifies the
|
||||
document.
|
||||
|
||||
!!! info "Chained access"
|
||||
@@ -126,8 +126,8 @@ document.
|
||||
|
||||
Overload 3 walks `ptr` one reference token at a time, starting at this value, the same way [`at`](at.md) and
|
||||
[`contains`](contains.md) do. It only ever returns a discarded view where the **const** overload of
|
||||
`BasicJsonType::operator[]` would be undefined behavior for the same pointer -- a missing object member or an
|
||||
out-of-range array index -- and still throws for every other way `ptr` can fail to resolve. See
|
||||
`BasicJsonType::operator[]` would be undefined behavior for the same pointer — a missing object member or an
|
||||
out-of-range array index — and still throws for every other way `ptr` can fail to resolve. See
|
||||
[`at`](at.md#exceptions) for the checked version, which throws in every case instead, and
|
||||
[`contains`](contains.md) for a version that never throws.
|
||||
|
||||
@@ -137,7 +137,7 @@ document.
|
||||
|
||||
The example below reads a couple of fields out of a batch of user records without ever materializing a full
|
||||
`BasicJsonType` value for the batch. `operator[]` is used both to look up an optional object member and to index
|
||||
into an array -- in both cases, a missing value comes back as a discarded view that can be tested with a plain
|
||||
into an array — in both cases, a missing value comes back as a discarded view that can be tested with a plain
|
||||
`#!cpp if`, instead of relying on undefined behavior.
|
||||
|
||||
```cpp
|
||||
|
||||
@@ -17,7 +17,7 @@ bool operator==(const BasicJsonType& lhs, const basic_json_view& rhs);
|
||||
|
||||
Neither overload builds a `BasicJsonType` value for a view to do the comparison (see [Notes](#notes) below). Numbers
|
||||
compare by value across their types (`#!cpp 1 == 1.0`), and an object compares by its members, with duplicate keys
|
||||
resolved exactly as `parse()` resolves them -- the last value, at the position of the first occurrence of the key.
|
||||
resolved exactly as `parse()` resolves them — the last value, at the position of the first occurrence of the key.
|
||||
This is not what [`operator[]`](operator[].md) and the other lookups return for a duplicate key: they find the *first*
|
||||
member (see [Duplicate keys](../../features/json_view.md#duplicate-keys)).
|
||||
|
||||
@@ -55,7 +55,7 @@ compared. Two arrays of different [`size()`](size.md) are rejected without visit
|
||||
## Notes
|
||||
|
||||
Only a single number, boolean, or `#!cpp null` value is ever materialized into a `BasicJsonType`, to reuse its
|
||||
`operator==` -- for numbers, so that values written differently in the source text but equal in value (e.g. an
|
||||
`operator==` — for numbers, so that values written differently in the source text but equal in value (e.g. an
|
||||
integer and a floating-point literal) still compare equal, following the same rules `BasicJsonType` does for special
|
||||
values such as `#!cpp NaN`. Constructing one of these scalars never allocates. Strings are compared directly, without
|
||||
allocating, either from the source text on both sides or, for overload 2, against `BasicJsonType`'s own string.
|
||||
@@ -85,7 +85,7 @@ the way to get a `BasicJsonType` value that supports it.
|
||||
??? example
|
||||
|
||||
The example below checks whether a newly received configuration differs from the previous one, and whether a
|
||||
received document matches what a test expects -- directly on views, without ever materializing a `BasicJsonType`
|
||||
received document matches what a test expects — directly on views, without ever materializing a `BasicJsonType`
|
||||
value for either side.
|
||||
|
||||
```cpp
|
||||
|
||||
@@ -6,7 +6,7 @@ std::ostream& operator<<(std::ostream& o, const basic_json_view& v);
|
||||
|
||||
Not available when [`JSON_NO_IO`](../macros/json_no_io.md) is defined.
|
||||
|
||||
Serializes the given view `v` to the output stream `o`, using [`dump`](dump.md) -- exactly as
|
||||
Serializes the given view `v` to the output stream `o`, using [`dump`](dump.md) — exactly as
|
||||
`#!cpp operator<<(std::ostream&, const basic_json&)` does for a `basic_json` value.
|
||||
|
||||
- The indentation of the output can be controlled with the member variable `width` of the output stream `o`. For
|
||||
@@ -38,7 +38,7 @@ the stream `o`
|
||||
|
||||
May throw `#!cpp std::bad_alloc`, propagated from [`dump`](dump.md#exceptions). Unlike
|
||||
`#!cpp operator<<(std::ostream&, const basic_json&)`, there is no UTF-8 decoding step that could throw
|
||||
[`type_error.316`](../../home/exceptions.md#jsonexceptiontype_error316), and no `error_handler` to choose between --
|
||||
[`type_error.316`](../../home/exceptions.md#jsonexceptiontype_error316), and no `error_handler` to choose between —
|
||||
see the [Exceptions](dump.md#exceptions) of `dump`.
|
||||
|
||||
## Complexity
|
||||
@@ -49,8 +49,8 @@ Linear, as [`dump`](dump.md#complexity).
|
||||
|
||||
??? example
|
||||
|
||||
The example below writes one record out of a larger batch straight to a log stream -- compact for a one-line
|
||||
entry, and pretty-printed with `std::setw`/`std::setfill` for a readable dump -- without ever building a
|
||||
The example below writes one record out of a larger batch straight to a log stream — compact for a one-line
|
||||
entry, and pretty-printed with `std::setw`/`std::setfill` for a readable dump — without ever building a
|
||||
`BasicJsonType` value for the record, or for the rest of the batch.
|
||||
|
||||
```cpp
|
||||
|
||||
@@ -15,7 +15,7 @@ bool operator!=(const BasicJsonType& lhs, const basic_json_view& rhs);
|
||||
|
||||
Since `operator!=` is defined as the negation of [`operator==`](operator_eq.md), it follows the same rules for
|
||||
special cases: for instance, since a [discarded](is_discarded.md) view is never equal to anything by default (see
|
||||
[operator=='s Notes](operator_eq.md#notes)), it is never *unequal* to anything either -- `#!cpp discarded != discarded`
|
||||
[operator=='s Notes](operator_eq.md#notes)), it is never *unequal* to anything either — `#!cpp discarded != discarded`
|
||||
is also `#!cpp false`, exactly as for a discarded `BasicJsonType` value.
|
||||
|
||||
## Parameters
|
||||
@@ -46,7 +46,7 @@ Linear, as [`operator==`](operator_eq.md#complexity).
|
||||
|
||||
## Notes
|
||||
|
||||
See the [Notes](operator_eq.md#notes) of `operator==` -- in particular for how an object's members are compared
|
||||
See the [Notes](operator_eq.md#notes) of `operator==` — in particular for how an object's members are compared
|
||||
(order matters for [`ordered_json_view`](../ordered_json_view.md) but not for [`json_view`](../json_view.md)) and
|
||||
for how discarded views compare.
|
||||
|
||||
@@ -58,7 +58,7 @@ the way to get a `BasicJsonType` value that supports it.
|
||||
??? example
|
||||
|
||||
The example below asserts, as a test would, that a received document differs from an unwanted value, and shows
|
||||
that -- as for [`json`](../json.md)/[`ordered_json`](../ordered_json.md) -- reordering an object's members is
|
||||
that — as for [`json`](../json.md)/[`ordered_json`](../ordered_json.md) — reordering an object's members is
|
||||
detected as a difference for an `ordered_json_view` but not for a `json_view`.
|
||||
|
||||
```cpp
|
||||
|
||||
@@ -30,10 +30,10 @@ Constant: for an object or array, the element count is stored in the index, not
|
||||
|
||||
## Notes
|
||||
|
||||
As for [`BasicJsonType::size()`](../basic_json/size.md), this does not return the length of a string value -- it is
|
||||
As for [`BasicJsonType::size()`](../basic_json/size.md), this does not return the length of a string value — it is
|
||||
`1` for a string, regardless of its length.
|
||||
|
||||
If the source text has an object with a duplicate key, every occurrence counts towards its `size()` -- unlike
|
||||
If the source text has an object with a duplicate key, every occurrence counts towards its `size()` — unlike
|
||||
[`materialize()`](materialize.md) (and [`BasicJsonType::parse()`](../basic_json/parse.md)), which keeps only the last
|
||||
value for a repeated key. This means `#!cpp v.size()` can be larger than `#!cpp v.materialize().size()`. See the
|
||||
[Notes on duplicate keys](operator[].md#notes) of `operator[]` for why lookups and iteration disagree on how many
|
||||
|
||||
@@ -13,7 +13,7 @@ materializing anything.
|
||||
byte offset of the first byte of the value's token (for a string: the first byte after the opening quote) in
|
||||
[`source()`](../basic_json_document/source.md).
|
||||
- `#!cpp static_cast<std::size_t>(-1)` for a [discarded](is_discarded.md) view, and for a string that contains
|
||||
escapes -- such a string was decoded once into the document's own buffer, so there is no single byte range in
|
||||
escapes — such a string was decoded once into the document's own buffer, so there is no single byte range in
|
||||
`source()` left to point at.
|
||||
|
||||
## Exception safety
|
||||
|
||||
@@ -5,7 +5,7 @@ value_t type() const noexcept;
|
||||
```
|
||||
|
||||
Returns the type of the value this view refers to, as a value from the [`value_t`](../basic_json/value_t.md)
|
||||
enumeration -- the same enumeration [`BasicJsonType::type()`](../basic_json/type.md) uses.
|
||||
enumeration — the same enumeration [`BasicJsonType::type()`](../basic_json/type.md) uses.
|
||||
|
||||
## Return value
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
const char* type_name() const noexcept;
|
||||
```
|
||||
|
||||
Returns the type name as string to be used in error messages -- usually to indicate that a function was called on a
|
||||
Returns the type name as string to be used in error messages — usually to indicate that a function was called on a
|
||||
wrong JSON type. Identical to [`BasicJsonType::type_name()`](../basic_json/type_name.md), including the extra
|
||||
`#!cpp "discarded"` return value for a [discarded](is_discarded.md) view (`BasicJsonType::type_name()` produces the
|
||||
same string for a discarded `BasicJsonType` value).
|
||||
@@ -39,7 +39,7 @@ Constant.
|
||||
|
||||
??? example
|
||||
|
||||
The example below reports why some parsed messages were rejected, using only `type_name()` -- no
|
||||
The example below reports why some parsed messages were rejected, using only `type_name()` — no
|
||||
`BasicJsonType` value is ever built for the ones that are wrong, and the message text matches what
|
||||
[`BasicJsonType::type_name()`](../basic_json/type_name.md) would produce for the same value.
|
||||
|
||||
|
||||
@@ -12,8 +12,8 @@ T value(const json_pointer& ptr, const T& default_value) const;
|
||||
string_t value(const json_pointer& ptr, const char* default_value) const;
|
||||
```
|
||||
|
||||
1. Returns the value of the object member with key `key` -- the first one, should the key occur more than once (see
|
||||
[Notes on duplicate keys](operator[].md#notes)) -- converted to `T`, or `default_value` if there is no such member.
|
||||
1. Returns the value of the object member with key `key` — the first one, should the key occur more than once (see
|
||||
[Notes on duplicate keys](operator[].md#notes)) — converted to `T`, or `default_value` if there is no such member.
|
||||
2. Returns the value a JSON pointer `ptr` refers to, starting at this value, converted to `T`, or `default_value` if
|
||||
`ptr` cannot be resolved.
|
||||
|
||||
@@ -48,16 +48,16 @@ Strong guarantee: there are no changes to the view or the document it refers to.
|
||||
|
||||
## Exceptions
|
||||
|
||||
1. Throws [`type_error.306`](../../home/exceptions.md#jsonexceptiontype_error306) if the value is not an object --
|
||||
1. Throws [`type_error.306`](../../home/exceptions.md#jsonexceptiontype_error306) if the value is not an object —
|
||||
the same exception, with the same message, that [`BasicJsonType::value`](../basic_json/value.md) throws for the
|
||||
same call. If a member with key `key` is found, throws whatever converting it to `T` throws (typically
|
||||
[`type_error.302`](../../home/exceptions.md#jsonexceptiontype_error302), with the same message
|
||||
[`BasicJsonType::value`](../basic_json/value.md) throws for the same mismatch); a missing member never throws.
|
||||
2. Throws [`type_error.306`](../../home/exceptions.md#jsonexceptiontype_error306) if this value -- not the value `ptr`
|
||||
resolves to -- is neither an object nor an array. Throws [`parse_error.106`](../../home/exceptions.md#jsonexceptionparse_error106)
|
||||
2. Throws [`type_error.306`](../../home/exceptions.md#jsonexceptiontype_error306) if this value — not the value `ptr`
|
||||
resolves to — is neither an object nor an array. Throws [`parse_error.106`](../../home/exceptions.md#jsonexceptionparse_error106)
|
||||
or [`parse_error.109`](../../home/exceptions.md#jsonexceptionparse_error109) if `ptr` contains a malformed array
|
||||
index. If `ptr` resolves to a value, throws whatever converting it to `T` throws. Every other way `ptr` can fail to
|
||||
resolve -- a missing key, an out-of-range or "`-`" array index, an unresolvable token on a primitive -- yields
|
||||
resolve — a missing key, an out-of-range or "`-`" array index, an unresolvable token on a primitive — yields
|
||||
`default_value` instead of throwing, exactly as [`BasicJsonType::value`](../basic_json/value.md) catches
|
||||
`out_of_range` and returns `default_value`.
|
||||
|
||||
@@ -73,7 +73,7 @@ None of these exceptions carry a [`JSON_DIAGNOSTICS`](../macros/json_diagnostics
|
||||
Objects with 128 or more members get a hash index of their keys while parsing, so that a lookup in them takes
|
||||
constant time on average.
|
||||
2. Linear in the number of reference tokens of `ptr` and, for each token, in the number of members of the object at
|
||||
that level or the index into the array -- as for the [`operator[]`](operator[].md#complexity) and
|
||||
that level or the index into the array — as for the [`operator[]`](operator[].md#complexity) and
|
||||
[`at`](at.md#complexity) overloads that take a JSON pointer. Plus the complexity of converting the resolved value
|
||||
to `T`.
|
||||
|
||||
@@ -89,7 +89,7 @@ None of these exceptions carry a [`JSON_DIAGNOSTICS`](../macros/json_diagnostics
|
||||
!!! info "Differences to `at` and `operator[]`"
|
||||
|
||||
Unlike [`at`](at.md), this function does not throw if `key`/`ptr` resolves to no value. Unlike
|
||||
[`operator[]`](operator[].md), it never returns a [discarded](is_discarded.md) view -- it always returns a `T` --
|
||||
[`operator[]`](operator[].md), it never returns a [discarded](is_discarded.md) view — it always returns a `T` —
|
||||
and it is available on any view, since it never needs to insert a missing element the way the non-const
|
||||
`BasicJsonType::operator[]` would.
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ bool operator==(const byte_container_with_subtype& rhs) const;
|
||||
```
|
||||
|
||||
Compares two byte containers for equality by comparing (1) the underlying binary data (the `BinaryType` base, compared
|
||||
with `BinaryType`'s own `operator==`) and (2) the subtype information -- both containers must either have no subtype,
|
||||
with `BinaryType`'s own `operator==`) and (2) the subtype information — both containers must either have no subtype,
|
||||
or have a subtype and the same subtype value.
|
||||
|
||||
## Parameters
|
||||
|
||||
@@ -9,14 +9,14 @@ 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
|
||||
[`json`](json.md) specialization: in addition to everything [`json_document`](json_document.md) offers,
|
||||
[`set`](basic_json_document/set.md) and [`push_back`](basic_json_document/push_back.md) change values after
|
||||
parsing, without ever rewriting the source text -- see [Edits](basic_json_document/index.md#edits) and
|
||||
parsing, without ever rewriting the source text — see [Edits](basic_json_document/index.md#edits) and
|
||||
[Editing a document](../features/json_view.md#editing-a-document).
|
||||
|
||||
## Examples
|
||||
|
||||
??? example
|
||||
|
||||
The example below patches two fields of a small configuration document -- changing one and adding another --
|
||||
The example below patches two fields of a small configuration document — changing one and adding another —
|
||||
and dumps it back out with the member order and the spelling of the untouched number preserved, something a
|
||||
plain [`json`](json.md) value cannot do.
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ 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
|
||||
[`json_editable_document`](json_editable_document.md). It offers the same read-only interface as
|
||||
[`json_view`](json_view.md); what is different is what it can be a view *of* -- a value that
|
||||
[`json_view`](json_view.md); what is different is what it can be a view *of* — a value that
|
||||
[`set`](basic_json_document/set.md) and [`push_back`](basic_json_document/push_back.md) can change, with every view
|
||||
still referring to it seeing the change, see [Edits](basic_json_document/index.md#edits).
|
||||
|
||||
@@ -17,7 +17,7 @@ still referring to it seeing the change, see [Edits](basic_json_document/index.m
|
||||
??? example
|
||||
|
||||
The example below is the same as [`json_editable_document`'s](json_editable_document.md): every view read back
|
||||
out of the document -- `#!cpp doc.root()` and the views nested under it -- sees the edits made through `set`.
|
||||
out of the document — `#!cpp doc.root()` and the views nested under it — sees the edits made through `set`.
|
||||
|
||||
```cpp
|
||||
--8<-- "examples/json_editable_document.cpp"
|
||||
|
||||
@@ -17,7 +17,7 @@ When the macro is not defined, the library will define it to its default value.
|
||||
|
||||
!!! info "Known compiler/stdlib exclusions"
|
||||
|
||||
- **MinGW** -- disabled, because its `std::ranges` support is incomplete ([issue #4916](https://github.com/nlohmann/json/issues/4916)).
|
||||
- **MinGW** — disabled, because its `std::ranges` support is incomplete ([issue #4916](https://github.com/nlohmann/json/issues/4916)).
|
||||
- All toolchains for which [`JSON_HAS_RANGES`](json_has_ranges.md#default-definition) is disabled.
|
||||
|
||||
## Examples
|
||||
|
||||
@@ -24,7 +24,7 @@ simdutf library. When it is not defined, no simdutf header is included and there
|
||||
|
||||
simdutf requires C++17 and its header rejects older standards with an `#!cpp #error`. The backend is therefore only
|
||||
compiled in from C++17 on. In C++11 and C++14 the macro has no effect and the scalar validator is used, which
|
||||
accepts and rejects exactly the same input -- only throughput differs. Setting the macro project-wide is therefore
|
||||
accepts and rejects exactly the same input — only throughput differs. Setting the macro project-wide is therefore
|
||||
safe even when some translation units are built with an older standard.
|
||||
|
||||
!!! warning "Define consistently"
|
||||
|
||||
@@ -81,7 +81,7 @@ input >> j2; // parses the next value
|
||||
needed. This is tracked in [#5340](https://github.com/nlohmann/json/issues/5340).
|
||||
|
||||
Note that reading concatenated values does **not** work for [JSON Lines](../features/parsing/json_lines.md)
|
||||
(newline-delimited JSON) input -- see that page for why and for the recommended alternative.
|
||||
(newline-delimited JSON) input — see that page for why and for the recommended alternative.
|
||||
|
||||
By default, a `'\0'` (NUL) byte encountered while reading a value is treated as end of input, rather than as an
|
||||
ordinary (and, outside of a string, invalid) byte; see the [FAQ entry](../home/faq.md#nul-bytes-in-the-input) for
|
||||
|
||||
@@ -10,8 +10,8 @@ This type is an **editable** [`basic_json_document`](basic_json_document/index.m
|
||||
[`ordered_json`](ordered_json.md) specialization: [`set`](basic_json_document/set.md) and
|
||||
[`push_back`](basic_json_document/push_back.md) change values after parsing, as for
|
||||
[`json_editable_document`](json_editable_document.md), and
|
||||
[`materialize()`](basic_json_view/materialize.md) preserves the document order of object members -- including
|
||||
members [`set`](basic_json_document/set.md) added -- instead of sorting them like
|
||||
[`materialize()`](basic_json_view/materialize.md) preserves the document order of object members — including
|
||||
members [`set`](basic_json_document/set.md) added — instead of sorting them like
|
||||
[`json_editable_document`](json_editable_document.md) does.
|
||||
|
||||
## Examples
|
||||
|
||||
@@ -105,7 +105,7 @@ This differs from `#!cpp std::map`, where the same operations are O(log n).
|
||||
|
||||
If key order matters for objects of that size, consider a container with a lookup index, such as
|
||||
[`nlohmann::fifo_map`](https://github.com/nlohmann/fifo_map)
|
||||
([integration](https://github.com/nlohmann/json/issues/485#issuecomment-333652309)), as the object type -- see
|
||||
([integration](https://github.com/nlohmann/json/issues/485#issuecomment-333652309)), as the object type — see
|
||||
[object order](../features/object_order.md).
|
||||
|
||||
## Examples
|
||||
|
||||
@@ -512,6 +512,27 @@ body:has(.nj-hero) .md-content {
|
||||
.md-typeset .mermaid {
|
||||
overflow-x: auto;
|
||||
}
|
||||
/* ... and one that is narrower than the column sits in the middle of it */
|
||||
.md-typeset .mermaid {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
/* external links (marked by js/external-links.js) get a small "open in new window" icon (Font Awesome
|
||||
"external-link-alt") in front of them */
|
||||
.md-typeset a.nj-external::before {
|
||||
content: "";
|
||||
display: inline-block;
|
||||
width: .72em;
|
||||
height: .72em;
|
||||
margin-right: .3em;
|
||||
background-color: currentColor;
|
||||
opacity: .65;
|
||||
-webkit-mask: var(--nj-external-icon) no-repeat center / contain;
|
||||
mask: var(--nj-external-icon) no-repeat center / contain;
|
||||
}
|
||||
:root {
|
||||
--nj-external-icon: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path d="M432 320h-32a16 16 0 0 0-16 16v112H64V128h144a16 16 0 0 0 16-16V80a16 16 0 0 0-16-16H48A48 48 0 0 0 0 112v352a48 48 0 0 0 48 48h352a48 48 0 0 0 48-48V336a16 16 0 0 0-16-16zM488 0H360c-21.37 0-32.05 25.91-17 41l35.73 35.73L135 320.37a24 24 0 0 0 0 34L157.67 377a24 24 0 0 0 34 0l243.61-243.68L471 169c15 15 41 4.5 41-17V24a24 24 0 0 0-24-24z"/></svg>');
|
||||
}
|
||||
|
||||
|
||||
/* ---- polish pass ---- */
|
||||
|
||||
@@ -275,7 +275,7 @@ To pick the macro for your own type and get code to start from, answer the quest
|
||||
|
||||
The `NLOHMANN_DEFINE_TYPE_*`/`NLOHMANN_DEFINE_DERIVED_TYPE_*` macros are generic over any `basic_json`
|
||||
specialization, including `nlohmann::ordered_json`. Simply use `ordered_json` as the target type and members
|
||||
are serialized in declaration order -- no separate macro or extra code is needed.
|
||||
are serialized in declaration order — no separate macro or extra code is needed.
|
||||
|
||||
```cpp
|
||||
namespace ns {
|
||||
@@ -308,7 +308,7 @@ To pick the macro for your own type and get code to start from, answer the quest
|
||||
|
||||
There is currently no `NLOHMANN_DEFINE_TYPE_*`-style macro for types that are not
|
||||
[DefaultConstructible](https://en.cppreference.com/w/cpp/named_req/DefaultConstructible). This is not an
|
||||
intentional omission of documentation -- no such macro exists yet; see
|
||||
intentional omission of documentation — no such macro exists yet; see
|
||||
[How can I use `get()` for non-default constructible/non-copyable types?](#how-can-i-use-get-for-non-default-constructiblenon-copyable-types)
|
||||
for the manual pattern to use instead.
|
||||
|
||||
@@ -465,7 +465,7 @@ For smart pointers, class hierarchies, `std::variant`, and `std::chrono`, see
|
||||
## Why can't I convert to/from `std::any`?
|
||||
|
||||
`std::any` is intentionally excluded from `get<T>()`/generic conversion support, so `get<std::any>()` and
|
||||
containers like `std::map<std::string, std::any>` fail to compile by design -- there is no way to know, from a
|
||||
containers like `std::map<std::string, std::any>` fail to compile by design — there is no way to know, from a
|
||||
`json` value alone, which concrete type to store inside the `std::any`. To work with heterogeneous JSON values,
|
||||
dispatch on the value's type manually and construct the `std::any` (or extract from it) yourself:
|
||||
|
||||
@@ -497,7 +497,7 @@ what the library does instead.
|
||||
|
||||
## Why does `std::wstring` convert or dump incorrectly?
|
||||
|
||||
The library assumes UTF-8 encoding internally, so `std::wstring` is not supported out of the box -- see the FAQ
|
||||
The library assumes UTF-8 encoding internally, so `std::wstring` is not supported out of the box — see the FAQ
|
||||
entry on [wide string handling](../home/faq.md#wide-string-handling) for why, and for a UTF-8 conversion recipe.
|
||||
|
||||
## Can I write my own serializer? (Advanced use)
|
||||
|
||||
@@ -11,7 +11,7 @@ This library does not support comments *by default*. It does so for three reason
|
||||
|
||||
3. It is dangerous for interoperability if some libraries add comment support while others do not. Please check [The Harmful Consequences of the Robustness Principle](https://tools.ietf.org/html/draft-iab-protocol-maintenance-01) on this.
|
||||
|
||||
However, you can set parameter `ignore_comments` to `#!cpp true` in the [`parse`](../api/basic_json/parse.md) function to ignore `//` or `/* */` comments. Comments will then be treated as whitespace. Combined with [`ignore_trailing_commas`](trailing_commas.md) (also a `parse` parameter), this covers what is commonly referred to as **JSONC** (JSON with Comments, as used e.g. by Visual Studio Code's `.jsonc` files) -- comments and trailing commas, nothing more. This is a different, smaller extension than [JSON5](https://json5.org), which additionally allows unquoted keys, single-quoted strings, and other syntax changes that this library does not support.
|
||||
However, you can set parameter `ignore_comments` to `#!cpp true` in the [`parse`](../api/basic_json/parse.md) function to ignore `//` or `/* */` comments. Comments will then be treated as whitespace. Combined with [`ignore_trailing_commas`](trailing_commas.md) (also a `parse` parameter), this covers what is commonly referred to as **JSONC** (JSON with Comments, as used e.g. by Visual Studio Code's `.jsonc` files) — comments and trailing commas, nothing more. This is a different, smaller extension than [JSON5](https://json5.org), which additionally allows unquoted keys, single-quoted strings, and other syntax changes that this library does not support.
|
||||
|
||||
For more information, see [JSON With Commas and Comments (JWCC)](https://nigeltao.github.io/blog/2021/json-with-commas-comments.html).
|
||||
|
||||
|
||||
@@ -177,7 +177,7 @@ which forces the explicit `get` form and can catch unintended conversions at com
|
||||
`std::optional<T>` from delegating to `get<T>()`, to avoid a constructor ambiguity with
|
||||
`std::optional<T>`'s own converting constructor from `basic_json`. As a result,
|
||||
`static_cast<std::optional<T>>(json_value)` goes through `std::optional<T>`'s own converting
|
||||
constructor rather than through `get<std::optional<T>>()`, which can behave differently -- for example,
|
||||
constructor rather than through `get<std::optional<T>>()`, which can behave differently — for example,
|
||||
with a custom `adl_serializer<std::optional<T>>` specialization. Prefer `get<std::optional<T>>()`/`get_to()`
|
||||
over `static_cast` for optional types.
|
||||
|
||||
@@ -193,7 +193,7 @@ which forces the explicit `get` form and can catch unintended conversions at com
|
||||
- The JSON array has **too many** elements: the surplus is **silently discarded**, and no exception is
|
||||
thrown.
|
||||
- The JSON array has **too few** elements: `at` throws
|
||||
[`out_of_range.401`](../home/exceptions.md#jsonexceptionout_of_range401) for the first missing index --
|
||||
[`out_of_range.401`](../home/exceptions.md#jsonexceptionout_of_range401) for the first missing index —
|
||||
an out-of-range error, not a [`type_error`](../home/exceptions.md#type-errors), even though the cause
|
||||
is a shape mismatch.
|
||||
|
||||
@@ -211,7 +211,7 @@ which forces the explicit `get` form and can catch unintended conversions at com
|
||||
|
||||
## Omitting a field when serializing `std::optional`
|
||||
|
||||
By default, `to_json` for `std::optional<T>` writes either the value or `#!json null` -- there is no built-in way
|
||||
By default, `to_json` for `std::optional<T>` writes either the value or `#!json null` — there is no built-in way
|
||||
to make a field disappear from the serialized object entirely when the `std::optional` is `std::nullopt`. Because
|
||||
a specialization of `adl_serializer<std::optional<T>>` only controls how the *value* is converted (it cannot
|
||||
prevent the containing object's `to_json` from inserting the key in the first place), omission has to be
|
||||
@@ -243,7 +243,7 @@ json j = numbers; // [1,2,3]
|
||||
!!! info "Constructing from a C++20 range view"
|
||||
|
||||
A `json` array can also be constructed directly from a C++20 range view (`std::ranges::view`), such as the result
|
||||
of `std::views::filter` or `std::views::transform` -- no intermediate container is needed:
|
||||
of `std::views::filter` or `std::views::transform` — no intermediate container is needed:
|
||||
|
||||
```cpp
|
||||
std::vector<int> nums{1, 2, 37, 42, 21};
|
||||
|
||||
@@ -10,7 +10,8 @@ C++ types, and finally serialize it again.
|
||||
understand the `#!cpp {}` vs. `#!cpp []` ambiguity.
|
||||
- [Parsing](parsing/index.md) — read a JSON value from a string, file, or stream, including
|
||||
[JSON Lines](parsing/json_lines.md), [callbacks](parsing/parser_callbacks.md), the
|
||||
[SAX interface](parsing/sax_interface.md), [error handling](parsing/parse_exceptions.md), and
|
||||
[SAX interface](parsing/sax_interface.md), [error handling](parsing/parse_exceptions.md),
|
||||
[large and partial input](parsing/large_and_partial_input.md), and
|
||||
[parsing untrusted input](parsing/untrusted_input.md).
|
||||
- [Zero-copy JSON views](json_view.md) — read a JSON text through a flat index instead of building a `json` tree;
|
||||
strings and numbers stay in the input and are only decoded when needed.
|
||||
@@ -33,6 +34,8 @@ C++ types, and finally serialize it again.
|
||||
- [Converting values](conversions.md) — get values out with [`get`](../api/basic_json/get.md)/[`get_to`](../api/basic_json/get_to.md),
|
||||
and understand implicit conversions.
|
||||
- [Arbitrary types conversions](arbitrary_types.md) — teach the library about your own structs and classes.
|
||||
- [Recipes for common types](type_recipes.md) — convert smart pointers, `std::variant`, `std::chrono` types, and class
|
||||
hierarchies, which the library deliberately leaves to you.
|
||||
- [Specializing enum conversion](enum_conversion.md) — map enums to strings instead of integers.
|
||||
|
||||
## Serializing values
|
||||
@@ -52,6 +55,7 @@ C++ types, and finally serialize it again.
|
||||
template parameters has to provide.
|
||||
- [Object order](object_order.md) — keep insertion order with [`ordered_json`](../api/ordered_json.md).
|
||||
- [Performance](performance.md) — practical advice on parsing, memory use, serialization, and compile times.
|
||||
- [Working without exceptions](no_exceptions.md) — what to use when exceptions are unwanted or unavailable.
|
||||
- [Runtime assertions](assertions.md), [supported macros](macros.md), the [`nlohmann` namespace](namespace.md), and
|
||||
[C++ modules](modules.md) — build-time and runtime configuration.
|
||||
|
||||
|
||||
@@ -21,15 +21,15 @@ referenced in place in the source text: a float is converted when it is read, an
|
||||
sequences are decoded, into one shared buffer owned by the document.
|
||||
|
||||
[`basic_json_view`](../api/basic_json_view/index.md) is a small, trivially copyable handle (two pointers) into that
|
||||
index. It gives you the read-only, type-inspection part of the `basic_json` interface --
|
||||
index. It gives you the read-only, type-inspection part of the `basic_json` interface —
|
||||
[`type()`](../api/basic_json_view/type.md) and the `is_*()` predicates,
|
||||
[`size()`](../api/basic_json_view/size.md)/[`empty()`](../api/basic_json_view/empty.md) -- as well as element access
|
||||
[`size()`](../api/basic_json_view/size.md)/[`empty()`](../api/basic_json_view/empty.md) — as well as element access
|
||||
([`operator[]`](../api/basic_json_view/operator%5B%5D.md), [`at`](../api/basic_json_view/at.md),
|
||||
[`front`](../api/basic_json_view/front.md)/[`back`](../api/basic_json_view/back.md)), lookup
|
||||
([`find`](../api/basic_json_view/find.md), [`contains`](../api/basic_json_view/contains.md),
|
||||
[`count`](../api/basic_json_view/count.md)), and iteration
|
||||
([`begin`](../api/basic_json_view/begin.md)/[`end`](../api/basic_json_view/end.md),
|
||||
[`items`](../api/basic_json_view/items.md)) -- without ever allocating a `basic_json` value. When you do need an
|
||||
[`items`](../api/basic_json_view/items.md)) — without ever allocating a `basic_json` value. When you do need an
|
||||
actual `basic_json` value for a subtree, [`materialize()`](../api/basic_json_view/materialize.md) builds exactly the
|
||||
one [`parse()`](../api/basic_json/parse.md) would have produced for it.
|
||||
|
||||
@@ -70,7 +70,7 @@ A document either **borrows** the text it was parsed from, or **owns** its own c
|
||||
[`owns_source()`](../api/basic_json_document/owns_source.md) to find out which happened.
|
||||
[`parse()`](../api/basic_json_document/parse.md) decides this from the value category and type of its argument (an
|
||||
lvalue `#!cpp std::string` is borrowed; an rvalue `#!cpp std::string` is moved in, owned without a copy; a stream is
|
||||
read into an owned buffer; and so on -- see [`parse`'s Notes](../api/basic_json_document/parse.md#notes) for the full
|
||||
read into an owned buffer; and so on — see [`parse`'s Notes](../api/basic_json_document/parse.md#notes) for the full
|
||||
table). [`parse_copy()`](../api/basic_json_document/parse_copy.md) always owns a copy, regardless of the input.
|
||||
|
||||
!!! warning "A borrowed document depends on your buffer"
|
||||
@@ -101,7 +101,7 @@ whenever any of the other conditions above was not met.
|
||||
A view can dangle, exactly like a `#!cpp std::string_view`: nothing stops you from using it after its document is
|
||||
gone. This is deliberate. A view is two pointers and trivially copyable; making it safe (a `#!cpp std::shared_ptr` in
|
||||
the document and a `#!cpp std::weak_ptr` in each view) would make it larger, add reference counting to every copy,
|
||||
and a `lock()` to every access -- exactly the costs the view exists to avoid. What is caught is the obvious case:
|
||||
and a `lock()` to every access — exactly the costs the view exists to avoid. What is caught is the obvious case:
|
||||
because a view dies with its document, [`root()`](../api/basic_json_document/root.md) is not callable on a temporary
|
||||
document: `#!cpp auto v = json_document::parse(text).root();` does not compile. Give the document a name first.
|
||||
|
||||
@@ -123,7 +123,7 @@ document: `#!cpp auto v = json_document::parse(text).root();` does not compile.
|
||||
[`parse()`](../api/basic_json_document/parse.md) accept and reject exactly the same inputs as
|
||||
[`basic_json::accept()`](../api/basic_json/accept.md)/[`basic_json::parse()`](../api/basic_json/parse.md), with the
|
||||
same `ignore_comments` and `ignore_trailing_commas` options.
|
||||
- **Errors.** A failing parse throws the same exception -- the same id, message, and position -- because on failure
|
||||
- **Errors.** A failing parse throws the same exception — the same id, message, and position — because on failure
|
||||
the library's own parser is run on the same bytes to produce the diagnostic. Valid input never pays for this, and
|
||||
the replay builds no values: it costs about a lexing pass up to the error.
|
||||
`#!cpp allow_exceptions == false` skips the replay and gives a
|
||||
@@ -169,7 +169,7 @@ document: `#!cpp auto v = json_document::parse(text).root();` does not compile.
|
||||
element access and lookup functions never carry the JSON Pointer path `JSON_DIAGNOSTICS` would otherwise add: the
|
||||
view has no `basic_json` value to point at, so the exception is created without one, regardless of how
|
||||
`BasicJsonType` was built.
|
||||
- **Ordering comparisons are not provided** by `basic_json_view` -- there is no `#!cpp operator<`.
|
||||
- **Ordering comparisons are not provided** by `basic_json_view` — there is no `#!cpp operator<`.
|
||||
[`operator==`](../api/basic_json_view/operator_eq.md) and [`operator!=`](../api/basic_json_view/operator_ne.md) are
|
||||
provided, though: two views, or a view and a `BasicJsonType` value, compare equal exactly when
|
||||
[`materialize()`](../api/basic_json_view/materialize.md) or [`parse()`](../api/basic_json/parse.md) would produce
|
||||
@@ -228,36 +228,36 @@ number of distinct keys, or reject duplicates when iterating.
|
||||
`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`/`ordered_json` (via
|
||||
[`materialize()`](../api/basic_json_view/materialize.md)), `basic_json_view` itself, `#!cpp std::vector<U>`, and
|
||||
`#!cpp std::map`/`#!cpp std::unordered_map` with string-like keys. Every other type -- `#!cpp std::list`,
|
||||
`#!cpp std::pair`, `#!cpp std::array`, enumerations, user types with a `from_json()` -- goes through
|
||||
`#!cpp std::map`/`#!cpp std::unordered_map` with string-like keys. Every other type — `#!cpp std::list`,
|
||||
`#!cpp std::pair`, `#!cpp std::array`, enumerations, user types with a `from_json()` — goes through
|
||||
[`materialize()`](../api/basic_json_view/materialize.md)`.get<T>()` instead: the subtree is built into a real
|
||||
`basic_json` value first, exactly as [`parse()`](../api/basic_json/parse.md) would, and converted from there.
|
||||
|
||||
Two conversions never copy at all:
|
||||
|
||||
- [`get_string()`](../api/basic_json_view/get_string.md) (equivalently, `#!cpp get<string_view_t>()`) returns a
|
||||
string as a `string_view_t` pointing into the document's [`source()`](../api/basic_json_document/source.md) text --
|
||||
or, for a string that contains escape sequences, into the document's own buffer of decoded strings -- instead of
|
||||
string as a `string_view_t` pointing into the document's [`source()`](../api/basic_json_document/source.md) text —
|
||||
or, for a string that contains escape sequences, into the document's own buffer of decoded strings — instead of
|
||||
allocating a new `#!cpp std::string`.
|
||||
- [`number_token()`](../api/basic_json_view/number_token.md) returns a number exactly as it was written in the
|
||||
source, e.g. `#!cpp "1.50"`, `#!cpp "1E2"`, or an integer with more digits than any number type holds, instead of
|
||||
rounding it into a `#!cpp double`/`#!cpp int64_t` the way `#!cpp get<T>()` (and
|
||||
[`basic_json::parse()`](../api/basic_json/parse.md)) would.
|
||||
|
||||
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 a view back
|
||||
|
||||
[`dump()`](../api/basic_json_view/dump.md) serializes a view directly from the flat index, without ever building a
|
||||
`basic_json` value. An object's members are written in document order, not sorted by key, and *every* occurrence of a
|
||||
repeated key is written, not only the last one -- the same two ways [iteration](#what-is-different) already differs
|
||||
repeated key is written, not only the last one — the same two ways [iteration](#what-is-different) already differs
|
||||
from a [`materialize()`](../api/basic_json_view/materialize.md)d value, see [Duplicate keys](#duplicate-keys).
|
||||
`#!cpp materialize().dump()` gives a different result in both respects for a `json_view`.
|
||||
|
||||
By default, numbers are written the way [`basic_json::dump()`](../api/basic_json/dump.md) would.
|
||||
[`number_format::source`](../api/basic_json_view/number_format.md) instead copies every number exactly as it was
|
||||
written in the source text -- a price like `#!cpp 19.90`, a long order or account ID with more digits than any number
|
||||
type holds, or a high-precision coordinate -- something `basic_json` cannot do at all, since parsing already reduces
|
||||
written in the source text — a price like `#!cpp 19.90`, a long order or account ID with more digits than any number
|
||||
type holds, or a high-precision coordinate — something `basic_json` cannot do at all, since parsing already reduces
|
||||
a number to its parsed `#!cpp double`/`#!cpp int64_t` value.
|
||||
|
||||
[`operator<<`](../api/basic_json_view/operator_ltlt.md) writes a view to a stream the way `basic_json`'s does, using
|
||||
@@ -266,14 +266,14 @@ the stream's `width`/`fill` for indentation.
|
||||
## Editing a document
|
||||
|
||||
Everything above is read-only: a `json_document`/`json_view` lets you look at a parsed text without copying it, but
|
||||
not change it. [`basic_json_document<BasicJsonType, true>`](../api/basic_json_document/index.md) -- more conveniently
|
||||
not change it. [`basic_json_document<BasicJsonType, true>`](../api/basic_json_document/index.md) — more conveniently
|
||||
spelled [`json_editable_document`](../api/json_editable_document.md) or
|
||||
[`ordered_json_editable_document`](../api/ordered_json_editable_document.md) -- also lets you
|
||||
[`ordered_json_editable_document`](../api/ordered_json_editable_document.md) — also lets you
|
||||
[`set`](../api/basic_json_document/set.md) a value, [`push_back`](../api/basic_json_document/push_back.md) onto or
|
||||
[`insert`](../api/basic_json_document/insert.md) into an array, and [`erase`](../api/basic_json_document/erase.md)
|
||||
an object member or an array element, still without ever building a `basic_json` tree for parts you do not touch.
|
||||
|
||||
`#!cpp Editable` defaults to `#!cpp false`, so `json_document`/`ordered_json_document` are unaffected -- they carry
|
||||
`#!cpp Editable` defaults to `#!cpp false`, so `json_document`/`ordered_json_document` are unaffected — they carry
|
||||
none of the bookkeeping edits need, and calling `set`/`push_back`/`insert`/`erase` on one is a compile error, not a
|
||||
runtime one.
|
||||
|
||||
@@ -283,7 +283,7 @@ The `#!cpp 19.90` price from [above](#writing-a-view-back) is exactly the kind o
|
||||
or `ordered_json` value in place lossy. Say you parse a configuration file, patch one field, and write it back:
|
||||
|
||||
- **`json`** re-sorts every key on the way in (`object_t` is a `#!cpp std::map`) and rewrites every number to its
|
||||
shortest round-trip form on the way out -- a one-field patch turns into a diff that reorders the whole file and
|
||||
shortest round-trip form on the way out — a one-field patch turns into a diff that reorders the whole file and
|
||||
rewrites `#!cpp 19.90` to `#!cpp 19.9`.
|
||||
- **`ordered_json`** keeps the key order, but still rewrites every number the same way: parsing has already reduced
|
||||
it to a `#!cpp double`/`#!cpp int64_t`, and there is no way back to how it was spelled in the source text.
|
||||
@@ -309,9 +309,9 @@ The patch of the example below (set `"host"`, add `"retries"`) written back by e
|
||||
</div>
|
||||
|
||||
An editable document keeps both. [`dump()`](../api/basic_json_view/dump.md) of an edited document writes members in
|
||||
document order -- a member [`set`](../api/basic_json_document/set.md) added goes at the end, exactly where it was
|
||||
document order — a member [`set`](../api/basic_json_document/set.md) added goes at the end, exactly where it was
|
||||
inserted, and an [`erase`](../api/basic_json_document/erase.md)d member simply leaves a gap: everything around it
|
||||
keeps its place -- and [`number_format::source`](../api/basic_json_view/number_format.md) keeps the exact spelling
|
||||
keeps its place — and [`number_format::source`](../api/basic_json_view/number_format.md) keeps the exact spelling
|
||||
of every number an edit did not itself touch; a number an edit *did* touch is written the way
|
||||
[`BasicJsonType::dump()`](../api/basic_json/dump.md) would write it, since there is no source spelling for a brand
|
||||
new value.
|
||||
@@ -330,14 +330,14 @@ new value.
|
||||
|
||||
### What stays valid, and what an edit costs
|
||||
|
||||
The source text itself is **never written**, and the parsed index never moves -- a value keeps the node it was
|
||||
The source text itself is **never written**, and the parsed index never moves — a value keeps the node it was
|
||||
parsed into for as long as it is not itself replaced. So every [view](../api/basic_json_view/index.md) taken before
|
||||
an edit, including a previously obtained [`root()`](../api/basic_json_document/root.md), stays valid and, if it
|
||||
still refers to the edited value, sees the edit; a view of a value a later edit drops or replaces just keeps showing
|
||||
what it last held. New values go to storage the document allocates and owns on demand. The one thing an edit does
|
||||
invalidate is the **iterators** taken over an edited array or object: the first time an element is added to it,
|
||||
inserted into it, erased from it, or replaced by a value that spans a different number of nodes, its elements move from the parsed, fixed layout to a growable block of links
|
||||
so that [`push_back`](../api/basic_json_document/push_back.md) can later grow it in amortized constant time --
|
||||
so that [`push_back`](../api/basic_json_document/push_back.md) can later grow it in amortized constant time —
|
||||
existing elements are not touched, but an iterator that was walking the old layout no longer matches. A string
|
||||
obtained with
|
||||
[`get_string()`](../api/basic_json_view/get_string.md) is unaffected either way and stays valid across further
|
||||
@@ -386,13 +386,13 @@ Step through the edits of a small document (the node fields follow the [architec
|
||||
## Images
|
||||
|
||||
[`save()`](../api/basic_json_document/save.md) writes a document as an *image*: a byte buffer that
|
||||
[`load()`](../api/basic_json_document/load.md) reads back into a document without parsing -- no lexing, no building
|
||||
[`load()`](../api/basic_json_document/load.md) reads back into a document without parsing — no lexing, no building
|
||||
the node index, nothing but copying the nodes and pointing the text and the decoded strings at the image. Where
|
||||
[`parse_copy()`](../api/basic_json_document/parse_copy.md) still has to scan the whole input,
|
||||
[`load()`](../api/basic_json_document/load.md) turns that scan into a copy of the node index alone.
|
||||
|
||||
**Why.** A document that is parsed once and then read many times -- a configuration loaded at startup, a template
|
||||
rendered on every request, a large reference dataset a worker process needs in memory -- pays for parsing once but
|
||||
**Why.** A document that is parsed once and then read many times — a configuration loaded at startup, a template
|
||||
rendered on every request, a large reference dataset a worker process needs in memory — pays for parsing once but
|
||||
can amortize [`save()`](../api/basic_json_document/save.md)'s cost across every later load. That makes images useful
|
||||
for a cache: save a document the first time it is parsed (to a file, a shared-memory segment, an in-process cache),
|
||||
and [`load()`](../api/basic_json_document/load.md) it on every later use instead of parsing the source text again.
|
||||
@@ -403,10 +403,10 @@ plus pointers into the received bytes, not a re-parse.
|
||||
**Choosing a check.** [`load()`](../api/basic_json_document/load.md) takes an
|
||||
[`image_check`](../api/basic_json_document/load.md#image_check) that trades validation against speed:
|
||||
`image_check::full` (the default) checks everything the parser itself guarantees, so a checked image is exactly as
|
||||
safe to read and serialize as a freshly parsed document -- the right choice whenever the image did not come straight
|
||||
safe to read and serialize as a freshly parsed document — the right choice whenever the image did not come straight
|
||||
from this process's own [`save()`](../api/basic_json_document/save.md), such as a file or a network peer.
|
||||
`image_check::bounds` only checks structure and bounds -- cheaper, since it skips scanning the text and the decoded
|
||||
strings -- and fits a cache the process trusts, one it wrote and reads back itself. `image_check::none` skips
|
||||
`image_check::bounds` only checks structure and bounds — cheaper, since it skips scanning the text and the decoded
|
||||
strings — and fits a cache the process trusts, one it wrote and reads back itself. `image_check::none` skips
|
||||
validation entirely, for an image trusted as much as the process's own memory. See
|
||||
[`load()`'s Notes](../api/basic_json_document/load.md#notes) for exactly what each level does and does not guarantee.
|
||||
|
||||
@@ -425,7 +425,7 @@ validation entirely, for an image trusted as much as the process's own memory. S
|
||||
!!! warning "Experimental"
|
||||
|
||||
The image format is versioned but not yet stable, and may change in an incompatible way before it is declared
|
||||
stable. It is little-endian only, and tied to the library build that wrote it -- use it to cache a document or to
|
||||
stable. It is little-endian only, and tied to the library build that wrote it — use it to cache a document or to
|
||||
hand one to another process running the *same* build, not as a long-term storage format; keep the original JSON
|
||||
text if a saved document needs to be readable by a future library version.
|
||||
|
||||
@@ -441,8 +441,8 @@ either.
|
||||
| **Ownership** | owns every value | owns nothing; you decide what to keep, in your handler | borrows or owns the *text*; the index is always owned by the document | same as `json_document`; edits go to storage the document owns |
|
||||
| **Mutability** | freely mutable | not applicable (a one-shot event stream) | read-only | [`set`](../api/basic_json_document/set.md)/[`push_back`](../api/basic_json_document/push_back.md)/[`insert`](../api/basic_json_document/insert.md)/[`erase`](../api/basic_json_document/erase.md) edit in place; the source text is never rewritten |
|
||||
| **What you get** | a full tree you can read, write, and keep as long as you like | a sequence of callbacks; whatever your handler builds from them | a flat index plus, on demand, [`materialize()`](../api/basic_json_view/materialize.md)d `json`/`ordered_json` values for the parts you actually use | the same, plus [`dump()`](../api/basic_json_view/dump.md) of an edited document that keeps the member order and, with [`number_format::source`](../api/basic_json_view/number_format.md), the spelling of every untouched number |
|
||||
| **Typical use** | general-purpose JSON handling: config, request/response bodies you build or modify, anything you hold onto | validating or projecting a text into your own data structure without ever holding the whole thing as JSON | large or high-volume input where you only need part of it, or need it repeatedly, and can keep the source text (or a copy) alive for as long as the document lives | a document you read, patch a few fields of, and write back -- a configuration file, for instance -- where the rest of it should come back exactly as it was |
|
||||
| **Caching/reload** | not applicable -- re-parse, or roll your own serialization | not applicable | [`save()`](../api/basic_json_document/save.md)/[`load()`](../api/basic_json_document/load.md): cache the parsed index as an image and reload it without parsing | same, saving the document's current -- possibly edited -- state |
|
||||
| **Typical use** | general-purpose JSON handling: config, request/response bodies you build or modify, anything you hold onto | validating or projecting a text into your own data structure without ever holding the whole thing as JSON | large or high-volume input where you only need part of it, or need it repeatedly, and can keep the source text (or a copy) alive for as long as the document lives | a document you read, patch a few fields of, and write back — a configuration file, for instance — where the rest of it should come back exactly as it was |
|
||||
| **Caching/reload** | not applicable — re-parse, or roll your own serialization | not applicable | [`save()`](../api/basic_json_document/save.md)/[`load()`](../api/basic_json_document/load.md): cache the parsed index as an image and reload it without parsing | same, saving the document's current — possibly edited — state |
|
||||
|
||||
<p class="nj-table-caption" markdown>Each column is one way to work with JSON in this library, and each row compares one property of them.</p>
|
||||
|
||||
|
||||
@@ -12,18 +12,61 @@ easier to read and write for object-shaped documents.
|
||||
The function [`merge_diff`](../api/basic_json/merge_diff.md) creates a merge patch that changes one JSON value into
|
||||
another.
|
||||
|
||||
The example below shows every rule in one patch, member by member:
|
||||
The example below applies one patch to one document. Here is the document before:
|
||||
|
||||
```json
|
||||
{
|
||||
"title": "Goodbye!",
|
||||
"author": {
|
||||
"givenName": "John",
|
||||
"familyName": "Doe"
|
||||
},
|
||||
"tags": ["example", "sample"],
|
||||
"content": "This will be unchanged"
|
||||
}
|
||||
```
|
||||
|
||||
This is the patch:
|
||||
|
||||
```json
|
||||
{
|
||||
"title": "Hello!",
|
||||
"phoneNumber": "+01-123-456-7890",
|
||||
"author": {
|
||||
"familyName": null
|
||||
},
|
||||
"tags": ["example"]
|
||||
}
|
||||
```
|
||||
|
||||
And this is the document after applying it:
|
||||
|
||||
```json
|
||||
{
|
||||
"title": "Hello!",
|
||||
"author": {
|
||||
"givenName": "John"
|
||||
},
|
||||
"tags": ["example"],
|
||||
"content": "This will be unchanged",
|
||||
"phoneNumber": "+01-123-456-7890"
|
||||
}
|
||||
```
|
||||
|
||||
The table goes through the members one by one. "Member" is the name of an object member in the patch (and in the
|
||||
document); it is not a [JSON Pointer](json_pointer.md) and nothing of it is passed to the function: the whole patch is
|
||||
passed to [`merge_patch`](../api/basic_json/merge_patch.md).
|
||||
|
||||
<div class="nj-pointer-mpt" markdown>
|
||||
|
||||
| Rule | Key | Target | Patch | Result |
|
||||
|------|-----|--------|-------|--------|
|
||||
| Rule | Member | Before | Patch | After |
|
||||
|------|--------|--------|-------|-------|
|
||||
| <span class="nj-pointer-mp nj-pointer-mp--set">change value</span> | `title` | `#!json "Goodbye!"` | `#!json "Hello!"` | `#!json "Hello!"` |
|
||||
| <span class="nj-pointer-mp nj-pointer-mp--add">add key</span> | `phoneNumber` | <span class="nj-pointer-mp-none">(no key)</span> | `#!json "+01-123-456-7890"` | `#!json "+01-123-456-7890"` |
|
||||
| <span class="nj-pointer-mp nj-pointer-mp--del">null removes key</span> | `author.familyName` | `#!json "Doe"` | `#!json null` | <span class="nj-pointer-mp-none">(removed)</span> |
|
||||
| <span class="nj-pointer-mp nj-pointer-mp--add">add key</span> | `phoneNumber` | <span class="nj-pointer-mp-none">(no member)</span> | `#!json "+01-123-456-7890"` | `#!json "+01-123-456-7890"` |
|
||||
| <span class="nj-pointer-mp nj-pointer-mp--rec">object merges recursively</span> | `author` | `#!json {"givenName": "John", "familyName": "Doe"}` | `#!json {"familyName": null}` | `#!json {"givenName": "John"}` |
|
||||
| <span class="nj-pointer-mp nj-pointer-mp--del">null removes key</span> | `familyName` inside `author` | `#!json "Doe"` | `#!json null` | <span class="nj-pointer-mp-none">(removed)</span> |
|
||||
| <span class="nj-pointer-mp nj-pointer-mp--arr">array replaced whole</span> | `tags` | `#!json ["example", "sample"]` | `#!json ["example"]` | `#!json ["example"]` |
|
||||
| <span class="nj-pointer-mp nj-pointer-mp--keep">unchanged key</span> | `content` | `#!json "This will be unchanged"` | <span class="nj-pointer-mp-none">(no key)</span> | `#!json "This will be unchanged"` |
|
||||
| <span class="nj-pointer-mp nj-pointer-mp--keep">unchanged key</span> | `content` | `#!json "This will be unchanged"` | <span class="nj-pointer-mp-none">(no member)</span> | `#!json "This will be unchanged"` |
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ json data = json::parse(f);
|
||||
```
|
||||
|
||||
The input must be encoded in UTF-8; other encodings are not supported. The exception is wide-character input, which
|
||||
is read as UTF-16 or UTF-32 -- depending on the character type -- and converted to UTF-8; see the
|
||||
is read as UTF-16 or UTF-32 — depending on the character type — and converted to UTF-8; see the
|
||||
[`parse`](../../api/basic_json/parse.md) page for an example. A single input may contain only one JSON value.
|
||||
Inputs consisting of multiple values separated by newlines are handled by the [JSON Lines](json_lines.md) format; input
|
||||
that arrives in chunks or contains several values is covered in
|
||||
|
||||
@@ -61,7 +61,7 @@ JSON Lines input with more than one value is treated as invalid JSON by the [`pa
|
||||
}
|
||||
```
|
||||
|
||||
A value that is a number must be followed by whitespace -- see the [notes](../../api/operator_gtgt.md#notes) of
|
||||
A value that is a number must be followed by whitespace — see the [notes](../../api/operator_gtgt.md#notes) of
|
||||
`operator>>` for details.
|
||||
|
||||
## See also
|
||||
|
||||
@@ -102,7 +102,7 @@ was called:
|
||||
|
||||
The JSON specification leaves the handling of objects with repeated keys up to the implementation. As described in
|
||||
[`object_t`](../../api/basic_json/object_t.md#behavior), it is unspecified which value for a repeated key ends up in
|
||||
the resulting `#!c json` value -- once parsing has produced that value, the duplicate is already gone, because object
|
||||
the resulting `#!c json` value — once parsing has produced that value, the duplicate is already gone, because object
|
||||
storage maps each key to a single value. If duplicate keys should instead be treated as an error, a parser callback
|
||||
can detect them while the object is still being read, before that ambiguity ever applies.
|
||||
|
||||
@@ -129,7 +129,7 @@ This approach has three limitations:
|
||||
maintaining a stack of the enclosing keys and array indices in the callback as well.
|
||||
|
||||
A [SAX interface](sax_interface.md) does not lift the position limitation: its `key` function receives no position
|
||||
either -- only `parse_error` is passed the byte position.
|
||||
either — only `parse_error` is passed the byte position.
|
||||
|
||||
## Recipe: streaming a large homogeneous array
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Parsing Untrusted Input
|
||||
|
||||
This page is for applications that parse JSON -- or one of the supported [binary formats](../binary_formats/index.md)
|
||||
(BJData, BON8, BSON, CBOR, MessagePack, UBJSON) -- from a source they do not fully control, such as a network
|
||||
This page is for applications that parse JSON — or one of the supported [binary formats](../binary_formats/index.md)
|
||||
(BJData, BON8, BSON, CBOR, MessagePack, UBJSON) — from a source they do not fully control, such as a network
|
||||
connection, an uploaded file, or another process. It summarizes what the library already does for such input and what
|
||||
remains the caller's responsibility, linking to the pages that cover each aspect in detail rather than repeating them.
|
||||
|
||||
@@ -50,12 +50,12 @@ stack, however deeply it is nested.
|
||||
[SAX handler](sax_interface.md) (for the JSON parser or a binary format alike) and throwing once your limit is
|
||||
exceeded.
|
||||
|
||||
Once a value has been parsed, operations that walk it recursively -- serializing it with
|
||||
Once a value has been parsed, operations that walk it recursively — serializing it with
|
||||
[`dump`](../../api/basic_json/dump.md), hashing it, copying it, comparing two values with `#!cpp ==`, `#!cpp <`, or (in
|
||||
C++20) `#!cpp <=>`, merging with [`update`](../../api/basic_json/update.md), applying a
|
||||
[`merge_patch`](../../api/basic_json/merge_patch.md), creating a patch with [`diff`](../../api/basic_json/diff.md) or
|
||||
[`merge_diff`](../../api/basic_json/merge_diff.md), [`flatten`](../../api/basic_json/flatten.md), and the binary
|
||||
writers (`to_cbor`, `to_msgpack`, ...) -- descend at most 128 levels on the call stack and continue
|
||||
writers (`to_cbor`, `to_msgpack`, ...) — descend at most 128 levels on the call stack and continue
|
||||
below that with an explicit stack instead, so none of them can exhaust the stack either, however deeply the value is
|
||||
nested. Destroying a value (its destructor) never recurses at all, regardless of nesting depth, for the same reason.
|
||||
|
||||
@@ -63,12 +63,12 @@ nested. Destroying a value (its destructor) never recurses at all, regardless of
|
||||
|
||||
The library does not limit the overall size of a JSON text; a value nested or wide enough will use memory
|
||||
proportional to the input. If you parse untrusted input of unbounded size, check the size of the file or stream
|
||||
yourself before -- or while -- handing it to `parse()`.
|
||||
yourself before — or while — handing it to `parse()`.
|
||||
|
||||
For the binary formats, an announced size is never trusted outright:
|
||||
|
||||
- Reading a string or binary value copies the input in bounded 4096-byte chunks and grows the result as bytes are
|
||||
actually consumed, rather than allocating the announced length up front -- a truncated input runs out of bytes
|
||||
actually consumed, rather than allocating the announced length up front — a truncated input runs out of bytes
|
||||
(reported as a parse error) instead of triggering an oversized allocation.
|
||||
- When an array announces its number of elements and the array container supports `reserve()` (as `#!cpp std::vector`,
|
||||
the default, does), the library reserves storage for at most 16384 of them upfront, regardless of how large the
|
||||
@@ -91,7 +91,7 @@ Invalid UTF-8 is rejected while parsing, not just while serializing:
|
||||
|
||||
A `#!cpp '\0'` (NUL) byte *inside* a quoted JSON string is always rejected (it must be escaped as `\u0000`). A NUL byte
|
||||
*outside* of a string is different: by default it is silently treated as the end of the input, so trailing bytes after
|
||||
it -- including further, otherwise well-formed JSON -- are silently ignored rather than rejected. Since untrusted input
|
||||
it — including further, otherwise well-formed JSON — are silently ignored rather than rejected. Since untrusted input
|
||||
that happens to embed a NUL is a way to make part of it disappear without a parse error, see the
|
||||
[FAQ entry](../../home/faq.md#nul-bytes-in-the-input) and consider defining
|
||||
[`JSON_STRICT_NUL_HANDLING`](../../api/macros/json_strict_nul_handling.md) to `1` to reject a NUL byte like any other
|
||||
@@ -116,7 +116,7 @@ silently resolving them one way or another, see the
|
||||
|
||||
## Numbers
|
||||
|
||||
A number whose value cannot be represented -- for instance `1E1000`, which overflows `double` -- is rejected while
|
||||
A number whose value cannot be represented — for instance `1E1000`, which overflows `double` — is rejected while
|
||||
parsing as [`out_of_range.406`](../../home/exceptions.md#jsonexceptionout_of_range406) rather than silently becoming
|
||||
infinity. An integer that is syntactically valid but does not fit the 64-bit integer types is not rejected; it is
|
||||
instead stored as a `double`, which may lose precision for very large values. See
|
||||
@@ -139,7 +139,7 @@ conforming JSON consumers is exactly what the default rejects.
|
||||
[SAX handler](sax_interface.md); the library bounds the call stack but not memory use.
|
||||
- Bound the size of the input itself before parsing, independent of the library's own bounded allocations for binary
|
||||
format lengths.
|
||||
- Decide up front how you want a string with invalid UTF-8 -- from any source, not only parsing -- to be serialized
|
||||
- Decide up front how you want a string with invalid UTF-8 — from any source, not only parsing — to be serialized
|
||||
(`strict`, `replace`, or `ignore`), rather than discovering it from an uncaught `type_error.316`.
|
||||
- If a stray NUL byte silently truncating trailing input is a problem for your input format, define
|
||||
`JSON_STRICT_NUL_HANDLING`.
|
||||
|
||||
@@ -6,7 +6,7 @@ first. If a hard real-time budget or the last percent of throughput matters more
|
||||
[faster, more specialized library](https://github.com/miloyip/nativejson-benchmark#parsing-time) may be a better fit.
|
||||
|
||||
That said, how you use this library still makes a measurable difference. This page collects practical, code-verified
|
||||
techniques for reducing time, memory, and compile-time cost -- without repeating the detailed pages it links to.
|
||||
techniques for reducing time, memory, and compile-time cost — without repeating the detailed pages it links to.
|
||||
|
||||
## Parsing input
|
||||
|
||||
@@ -14,8 +14,8 @@ techniques for reducing time, memory, and compile-time cost -- without repeating
|
||||
`#!cpp FILE*` (see [Parsing](parsing/index.md#input)). Internally, every input is wrapped in an
|
||||
[input adapter](../home/architecture.md#input-adapters), and not all adapters are equally fast.
|
||||
|
||||
For inputs backed by contiguous, single-byte memory -- a `#!cpp std::string`, a `#!cpp std::vector<char>`, a string
|
||||
literal, or a pointer range -- the library uses `iterator_input_adapter`, wrapped in a raw pointer so the fast paths
|
||||
For inputs backed by contiguous, single-byte memory — a `#!cpp std::string`, a `#!cpp std::vector<char>`, a string
|
||||
literal, or a pointer range — the library uses `iterator_input_adapter`, wrapped in a raw pointer so the fast paths
|
||||
below apply on every supported standard. This adapter exposes two optimizations the lexer detects at compile time:
|
||||
|
||||
- it can reconstruct already-consumed input on demand for error messages, instead of copying every character as it is
|
||||
@@ -69,7 +69,7 @@ a DOM, three alternatives avoid building it:
|
||||
`basic_json` values.
|
||||
- Pass a [parser callback](parsing/parser_callbacks.md) to `parse`. This still builds a DOM, but the callback can
|
||||
discard finished elements as soon as they are handled, so memory usage stays bounded by one element (plus the
|
||||
unparsed remainder of the input) instead of the whole document -- see the [recipe for streaming a large homogeneous
|
||||
unparsed remainder of the input) instead of the whole document — see the [recipe for streaming a large homogeneous
|
||||
array](parsing/parser_callbacks.md#recipe-streaming-a-large-homogeneous-array).
|
||||
- Parse into a [`json_document`](json_view.md) (`#!cpp <nlohmann/json_view.hpp>`) instead of a `basic_json`. It keeps
|
||||
the input text and builds a flat index of 16 bytes per value; strings and floating-point numbers are not copied, but
|
||||
@@ -85,15 +85,15 @@ at a time, and a malformed line does not invalidate lines already processed.
|
||||
## Binary formats
|
||||
|
||||
JSON text is not a compact format. If the data is only exchanged between programs (not read by humans), the
|
||||
[binary formats](binary_formats/index.md) -- BJData, BON8, BSON, CBOR, MessagePack, and UBJSON -- encode the same
|
||||
[binary formats](binary_formats/index.md) — BJData, BON8, BSON, CBOR, MessagePack, and UBJSON — encode the same
|
||||
values more compactly, which reduces both the bytes transferred and, for most of them, the work needed to parse them
|
||||
back. The [size comparison](binary_formats/index.md#sizes) on that page, measured against minified JSON for four
|
||||
reference documents, shows the effect varies a lot by document shape: CBOR and MessagePack come out at 50.5% of the
|
||||
minified JSON size for the numeric-array-heavy `canada.json`, but only around 87-88% for the string-heavy
|
||||
`jeopardy.json`, where there is less numeric data to encode more compactly. BON8 is the most compact option in that
|
||||
comparison for text-heavy documents (63.5%-87.5%), at the cost of an
|
||||
[incomplete serializer](binary_formats/index.md#completeness) (no unsigned integers above int64). Which format -- and
|
||||
whether it is worth the loss of human readability at all -- depends on the actual data; see the
|
||||
[incomplete serializer](binary_formats/index.md#completeness) (no unsigned integers above int64). Which format — and
|
||||
whether it is worth the loss of human readability at all — depends on the actual data; see the
|
||||
[comparison tables](binary_formats/index.md#comparison) before choosing one.
|
||||
|
||||
<div class="nj-charts-grid-wrap" markdown>
|
||||
@@ -113,7 +113,7 @@ The default [`json`](../api/json.md) type stores object keys in a `#!cpp std::ma
|
||||
insertion, and erasure, at the cost of sorting keys alphabetically rather than preserving insertion order (see
|
||||
[Object Order](object_order.md)). [`ordered_json`](../api/ordered_json.md) uses
|
||||
[`nlohmann::ordered_map`](../api/ordered_map.md) instead, a `#!cpp std::vector`-backed container with no lookup index:
|
||||
every key-based operation is a **linear scan**, so building an object of `n` distinct keys costs **O(n²)** in total --
|
||||
every key-based operation is a **linear scan**, so building an object of `n` distinct keys costs **O(n²)** in total —
|
||||
this applies equally to inserting keys one by one and to parsing an object, since the parser inserts each key as it is
|
||||
read. The [measurements on the `ordered_map` page](../api/ordered_map.md#complexity) show this is
|
||||
negligible at typical object sizes (2000 keys: 0.7 ms for `json` vs. 3.6 ms for `ordered_json`, a 5x factor) but grows
|
||||
@@ -131,7 +131,7 @@ may not be acceptable. The library's [`ObjectType` template parameter](types/tem
|
||||
set to a different container instead: `#!cpp nlohmann::fifo_map` keeps insertion order with a real lookup index
|
||||
(avoiding the quadratic cost), while `#!cpp std::unordered_map`, `#!cpp boost::unordered_flat_map`,
|
||||
`#!cpp absl::flat_hash_map`, and similar hash maps trade insertion order for average-case constant-time lookup (through
|
||||
an adapter, since their template argument order does not match what `basic_json` expects) -- see
|
||||
an adapter, since their template argument order does not match what `basic_json` expects) — see
|
||||
[Object Order](object_order.md#alternative-behavior-preserve-insertion-order) for the full list.
|
||||
|
||||
## Avoiding copies
|
||||
@@ -146,13 +146,13 @@ an adapter, since their template argument order does not match what `basic_json`
|
||||
- **Access without copying.** [`get<T>()`](../api/basic_json/get.md) returns a copy of the stored value converted to
|
||||
`T`. When a reference or pointer to the value already stored inside the `basic_json` is enough,
|
||||
[`get_ref()`](../api/basic_json/get_ref.md) and [`get_ptr()`](../api/basic_json/get_ptr.md) access it directly:
|
||||
both pages state, word for word, "No copies are made." -- at the cost of that reference or pointer becoming invalid
|
||||
both pages state, word for word, "No copies are made." — at the cost of that reference or pointer becoming invalid
|
||||
once the underlying value changes.
|
||||
- **Iterate by reference.** `#!cpp basic_json::iterator::operator*()` returns a `reference` (an alias for
|
||||
`#!cpp basic_json&`), but a range-based for loop with a by-value loop variable (`#!cpp for (auto el : j)`) still
|
||||
copies each element, because plain `#!cpp auto` drops the reference. Write `#!cpp for (const auto& el : j)` (or
|
||||
`#!cpp auto&` for a mutable loop), and use [`items()`](../api/basic_json/items.md) the same way when the key is
|
||||
needed too -- its own examples use `#!cpp for (auto& el : j.items())`.
|
||||
needed too — its own examples use `#!cpp for (auto& el : j.items())`.
|
||||
- **Construct in place.** [`emplace_back()`](../api/basic_json/emplace_back.md) (arrays, amortized constant time) and
|
||||
[`emplace()`](../api/basic_json/emplace.md) (objects, logarithmic in the size of the container for `json`) forward
|
||||
their arguments directly to a `basic_json` constructor, rather than requiring a temporary value to be
|
||||
@@ -161,13 +161,13 @@ an adapter, since their template argument order does not match what `basic_json`
|
||||
in instead of copying it.
|
||||
- **Skip the bounds check when it is redundant.** [`at()`](../api/basic_json/at.md) and
|
||||
[`operator[]`](../api/basic_json/operator%5B%5D.md) have the same complexity (constant for a valid array index,
|
||||
logarithmic for an object key in `json`) -- the difference is that `at()` additionally checks the key or index and
|
||||
logarithmic for an object key in `json`) — the difference is that `at()` additionally checks the key or index and
|
||||
throws if it is invalid, while `operator[]` does not (see [unchecked access](element_access/unchecked_access.md) and
|
||||
[checked access](element_access/checked_access.md)). Prefer `operator[]` when the surrounding code has already
|
||||
established that the access is valid.
|
||||
- **Reserve array capacity.** `basic_json` has no public `reserve()`, but when building a large array
|
||||
incrementally with a known final size, [`get_ref()`](../api/basic_json/get_ref.md) exposes the underlying
|
||||
`#!cpp array_t` so it can be reserved directly -- see
|
||||
`#!cpp array_t` so it can be reserved directly — see
|
||||
["reserving array capacity"](element_access/unchecked_access.md#performance-reserving-array-capacity) for the
|
||||
one-line recipe.
|
||||
|
||||
@@ -200,7 +200,7 @@ an adapter, since their template argument order does not match what `basic_json`
|
||||
(word for word from the page); any non-negative `indent` pretty-prints instead, which is more readable but produces
|
||||
more bytes and more work. `dump()` builds and returns a complete `#!cpp string_t` containing the whole serialization.
|
||||
[`operator<<`](../api/operator_ltlt.md) writes directly to a `#!cpp std::ostream` instead, through the same
|
||||
serializer, but without ever materializing that intermediate string -- so if the destination is a stream (a file, or
|
||||
serializer, but without ever materializing that intermediate string — so if the destination is a stream (a file, or
|
||||
`#!cpp std::cout`), `#!cpp os << j;` avoids the allocation and copy that `#!cpp os << j.dump();` would incur for large
|
||||
values.
|
||||
|
||||
@@ -211,7 +211,7 @@ while it is in use:
|
||||
|
||||
- [`JSON_DIAGNOSTICS`](../api/macros/json_diagnostics.md) adds a JSON Pointer to exception messages, pointing at the
|
||||
value that triggered the exception. Quoting the page directly: "enabling this macro increases the size of every
|
||||
JSON value by one pointer and adds some runtime overhead" -- every value gains a parent pointer that has to be kept
|
||||
JSON value by one pointer and adds some runtime overhead" — every value gains a parent pointer that has to be kept
|
||||
up to date as the document is built and modified.
|
||||
- [`JSON_DIAGNOSTIC_POSITIONS`](../api/macros/json_diagnostic_positions.md) adds
|
||||
[`start_pos()`](../api/basic_json/start_pos.md) and [`end_pos()`](../api/basic_json/end_pos.md), the byte offsets a
|
||||
@@ -228,7 +228,7 @@ untrusted input, or in a debug build), and keep them off in a release build that
|
||||
[`basic_json`](../api/basic_json/index.md), [`json`](../api/json.md), [`ordered_json`](../api/ordered_json.md),
|
||||
[`json_pointer`](../api/json_pointer/index.md), and [`adl_serializer`](../api/adl_serializer/index.md), pulling in only
|
||||
a handful of lightweight standard headers instead of the full `json.hpp`. A header that only needs to *name*
|
||||
`nlohmann::json` -- in a function signature or a class member declaration, for instance -- can include `json_fwd.hpp`
|
||||
`nlohmann::json` — in a function signature or a class member declaration, for instance — can include `json_fwd.hpp`
|
||||
and leave `#!cpp #include <nlohmann/json.hpp>` to the source files that actually parse, build, or serialize values,
|
||||
the same way a project would forward-declare any other heavy class to keep it out of widely-included headers:
|
||||
|
||||
@@ -249,8 +249,8 @@ nlohmann::json my_type::config() const { /* ... */ }
|
||||
```
|
||||
|
||||
One caveat: ABI-affecting macros such as `JSON_DIAGNOSTICS` and `JSON_DIAGNOSTIC_POSITIONS` are encoded into the
|
||||
library's [inline namespace name](namespace.md#limitations). Every translation unit -- whether it includes
|
||||
`json_fwd.hpp` or the full header -- must define them the same way, or linking fails with undefined references
|
||||
library's [inline namespace name](namespace.md#limitations). Every translation unit — whether it includes
|
||||
`json_fwd.hpp` or the full header — must define them the same way, or linking fails with undefined references
|
||||
instead of a compile error.
|
||||
|
||||
If I/O support is not needed at all, [`JSON_NO_IO`](../api/macros/json_no_io.md) excludes `<cstdio>`, `<ios>`,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Template Parameter Requirements
|
||||
|
||||
Class [`basic_json`](../../api/basic_json/index.md) is configurable through eleven template parameters. The library
|
||||
never formally states what a type passed for one of these parameters has to provide -- the requirements are implied by
|
||||
never formally states what a type passed for one of these parameters has to provide — the requirements are implied by
|
||||
the way the library uses the resulting [`object_t`](../../api/basic_json/object_t.md),
|
||||
[`array_t`](../../api/basic_json/array_t.md), [`string_t`](../../api/basic_json/string_t.md), etc. This page collects
|
||||
these requirements so they do not have to be discovered by trial and error. Each section lists the concrete types
|
||||
@@ -16,9 +16,9 @@ To change a single template parameter and keep the others, use the member alias
|
||||
|
||||
Requirements are split into two groups:
|
||||
|
||||
- **Always required** -- needed to instantiate `basic_json` at all, or needed by functions that virtually every program
|
||||
- **Always required** — needed to instantiate `basic_json` at all, or needed by functions that virtually every program
|
||||
uses (construction, element access, [`dump`](../../api/basic_json/dump.md)).
|
||||
- **Required for ...** -- only needed when a particular part of the API is instantiated. Member function templates are
|
||||
- **Required for ...** — only needed when a particular part of the API is instantiated. Member function templates are
|
||||
only instantiated when they are used, so a type may be perfectly usable even though it does not satisfy these
|
||||
requirements, as long as the corresponding functions are never called.
|
||||
|
||||
@@ -56,8 +56,8 @@ Requirements are split into two groups:
|
||||
|
||||
!!! warning "Third-party containers and incomplete types"
|
||||
|
||||
`object_t` is instantiated inside the definition of `basic_json` -- it is probed for a `key_compare` member to
|
||||
form [`object_comparator_t`](../../api/basic_json/object_comparator_t.md) -- i.e. while `basic_json` is still an
|
||||
`object_t` is instantiated inside the definition of `basic_json` — it is probed for a `key_compare` member to
|
||||
form [`object_comparator_t`](../../api/basic_json/object_comparator_t.md) — i.e. while `basic_json` is still an
|
||||
incomplete type. `#!cpp std::map` is required by the standard to support incomplete mapped types; most
|
||||
third-party maps are not, and inspecting the mapped type at class scope (for instance with
|
||||
`#!cpp std::is_trivially_move_assignable`) makes them unusable as `ObjectType`, no matter how their template
|
||||
@@ -65,7 +65,7 @@ Requirements are split into two groups:
|
||||
`robin_hood::unordered_node_map`, `folly::F14FastMap`, and `eastl::hash_map`.
|
||||
|
||||
`array_t` is only *named* in the class definition and is not instantiated until `basic_json` is complete, so an
|
||||
`ArrayType` that inspects its value type at class scope is generally fine -- `boost::container::small_vector` and
|
||||
`ArrayType` that inspects its value type at class scope is generally fine — `boost::container::small_vector` and
|
||||
`static_vector` both reject incomplete value types yet work here. `absl::InlinedVector` is the exception: the
|
||||
`#!cpp std::is_trivially_move_assignable<basic_json>` it evaluates while instantiating itself re-enters the
|
||||
library's own trait machinery mid-instantiation.
|
||||
@@ -93,7 +93,7 @@ i.e., the template arguments follow the order and meaning of `std::map`.
|
||||
|
||||
- The template must be usable with **four** type arguments in the order shown above. The third argument is a
|
||||
**comparator**; containers that expect something else in this position (e.g., a hash function) need an alias template
|
||||
or wrapper -- see [Notes](#notes).
|
||||
or wrapper — see [Notes](#notes).
|
||||
- An optional member type `key_compare`. If it is present it becomes
|
||||
[`object_comparator_t`](../../api/basic_json/object_comparator_t.md); otherwise
|
||||
[`default_object_comparator_t`](../../api/basic_json/default_object_comparator_t.md) is used.
|
||||
@@ -116,7 +116,7 @@ i.e., the template arguments follow the order and meaning of `std::map`.
|
||||
semantics; multimaps cannot be used.
|
||||
- The type must be swappable (via `std::swap` or an ADL `swap`).
|
||||
- The comparison operators `==` and `<`; `!=`, `<=`, `>`, and `>=` are derived from them. Where the library uses
|
||||
three-way comparison (C++20), `==` and `<=>` are required **instead** -- the six two-way operators do not satisfy
|
||||
three-way comparison (C++20), `==` and `<=>` are required **instead** — the six two-way operators do not satisfy
|
||||
it. They implement [`basic_json`'s comparison operators](../../api/basic_json/operator_eq.md).
|
||||
|
||||
### Required for heterogeneous key lookup
|
||||
@@ -200,7 +200,7 @@ object keys are serialized by [`dump`](../../api/basic_json/dump.md) and visited
|
||||
With [`JSON_DIAGNOSTICS`](../../api/macros/json_diagnostics.md) enabled, the library detects insertion-ordered maps by
|
||||
probing for a `capacity()` member function (`nlohmann::ordered_map` inherits it from `std::vector`) and refreshes all
|
||||
parent pointers after every insertion. An `ObjectType` that happens to have a `capacity()` member is therefore treated
|
||||
conservatively -- this is correct, but slower.
|
||||
conservatively — this is correct, but slower.
|
||||
|
||||
#### Key order and duplicate keys
|
||||
|
||||
@@ -211,7 +211,7 @@ The library does not sort or de-duplicate keys itself; the behavior described in
|
||||
|
||||
`docs/mkdocs/docs/examples/custom_object_type.hpp` wraps a private `#!cpp std::map` and satisfies every
|
||||
requirement above. It does not define `key_compare`, so `object_comparator_t` falls back to
|
||||
[`default_object_comparator_t`](../../api/basic_json/default_object_comparator_t.md) -- a good starting point for
|
||||
[`default_object_comparator_t`](../../api/basic_json/default_object_comparator_t.md) — a good starting point for
|
||||
a custom `ObjectType`.
|
||||
|
||||
```cpp
|
||||
@@ -305,7 +305,7 @@ using array_t = ArrayType<basic_json, AllocatorType<basic_json>>;
|
||||
!!! tip "Reference implementation"
|
||||
|
||||
`docs/mkdocs/docs/examples/custom_array_type.hpp` wraps a private `#!cpp std::vector` and satisfies every
|
||||
requirement above -- a good starting point for a custom `ArrayType`.
|
||||
requirement above — a good starting point for a custom `ArrayType`.
|
||||
|
||||
```cpp
|
||||
--8<-- "examples/custom_array_type.hpp"
|
||||
@@ -385,13 +385,13 @@ using array_t = ArrayType<basic_json, AllocatorType<basic_json>>;
|
||||
|
||||
### Required for JSON Pointer, `flatten`, and `diff`
|
||||
|
||||
- A static member `npos` and the member function `find_first_of(char, size_type)` -- together with `data()`,
|
||||
- A static member `npos` and the member function `find_first_of(char, size_type)` — together with `data()`,
|
||||
`reserve(n)`, and `append(const char*, size_type)` they implement the escaping and unescaping of reference tokens
|
||||
described in RFC 6901. Neither `find(const StringType&, size_type)`, nor `substr(pos, count)`, nor
|
||||
`replace(pos, count, const StringType&)` is required.
|
||||
- `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
|
||||
- `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
|
||||
[`operator[](const json_pointer&)`](../../api/basic_json/operator%5B%5D.md) to decide whether a reference token
|
||||
denotes an array index.
|
||||
|
||||
@@ -417,7 +417,7 @@ using array_t = ArrayType<basic_json, AllocatorType<basic_json>>;
|
||||
| `#!cpp std::pmr::string` | see the warning below before relying on the memory resource |
|
||||
| `boost::container::string` | needs a user-supplied `#!cpp std::hash` specialization (Boost provides `boost::hash` instead) |
|
||||
| `folly::fbstring` | requires C++20, see the note above |
|
||||
| `eastl::string` | needs a user-supplied `#!cpp std::hash` and an ADL `int_to_string` (it is not assignable from a `#!cpp std::string`); [`parse`](../../api/basic_json/parse.md) does not accept it directly -- pass a character range or a `#!cpp std::string` |
|
||||
| `eastl::string` | needs a user-supplied `#!cpp std::hash` and an ADL `int_to_string` (it is not assignable from a `#!cpp std::string`); [`parse`](../../api/basic_json/parse.md) does not accept it directly — pass a character range or a `#!cpp std::string` |
|
||||
| a custom string class in a user-defined namespace | if the requirements above are met |
|
||||
|
||||
### Types that cannot be used
|
||||
@@ -435,13 +435,13 @@ using array_t = ArrayType<basic_json, AllocatorType<basic_json>>;
|
||||
allocation and has to be stateless (see [`AllocatorType`](#allocatortype)), and string values the library creates
|
||||
are constructed with their own default allocator. So:
|
||||
|
||||
- Every string the library itself produces -- from [`parse`](../../api/basic_json/parse.md), from
|
||||
[`dump`](../../api/basic_json/dump.md), or by default construction -- allocates from
|
||||
- Every string the library itself produces — from [`parse`](../../api/basic_json/parse.md), from
|
||||
[`dump`](../../api/basic_json/dump.md), or by default construction — allocates from
|
||||
`#!cpp std::pmr::get_default_resource()`.
|
||||
- **Copying** an arena-backed string into a value silently drops its memory resource: the copy lands on the
|
||||
default resource, because `#!cpp std::pmr::polymorphic_allocator` does not propagate on copy construction.
|
||||
Nothing warns about this.
|
||||
- **Moving** one in does keep it, and later growth still allocates from that arena -- but it does not survive a
|
||||
- **Moving** one in does keep it, and later growth still allocates from that arena — but it does not survive a
|
||||
copy of the enclosing `basic_json`.
|
||||
- Passing `#!cpp std::pmr::polymorphic_allocator` as `AllocatorType` does not work around any of this; it does
|
||||
not compile.
|
||||
@@ -452,7 +452,7 @@ using array_t = ArrayType<basic_json, AllocatorType<basic_json>>;
|
||||
!!! tip "Reference implementation"
|
||||
|
||||
`docs/mkdocs/docs/examples/custom_string_type.hpp` wraps a private `#!cpp std::string` and satisfies every
|
||||
requirement above -- a good starting point for a custom `StringType`. The unit test
|
||||
requirement above — a good starting point for a custom `StringType`. The unit test
|
||||
`tests/src/unit-alt-string.cpp` contains a more thorough variant, `alt_string`, exercised against a larger part
|
||||
of the API.
|
||||
|
||||
@@ -480,8 +480,8 @@ using array_t = ArrayType<basic_json, AllocatorType<basic_json>>;
|
||||
|
||||
- A literal type that is trivially default-constructible, trivially copyable, and trivially destructible; otherwise the
|
||||
union's special member functions are deleted.
|
||||
- **Implicitly** convertible from `#!cpp bool` -- an `#!cpp explicit` constructor is not enough, because the
|
||||
`to_json` overload for a custom `BooleanType` is constrained on `#!cpp std::is_convertible` -- and contextually
|
||||
- **Implicitly** convertible from `#!cpp bool` — an `#!cpp explicit` constructor is not enough, because the
|
||||
`to_json` overload for a custom `BooleanType` is constrained on `#!cpp std::is_convertible` — and contextually
|
||||
convertible to `#!cpp bool` (here an `#!cpp explicit operator bool` is fine).
|
||||
- Comparison operators `==`, `!=`, `<`, `<=`, `>`, `>=` (or `<=>`).
|
||||
- Convertible from and to `#!cpp bool` through the serializer, because
|
||||
@@ -492,7 +492,7 @@ There is little reason to use anything other than `#!cpp bool` here.
|
||||
### Compatible types
|
||||
|
||||
`#!cpp bool` is the only usable choice. Another trivially copyable type that is implicitly convertible to and from
|
||||
`#!cpp bool` -- `#!cpp std::uint8_t`, say -- does compile, and JSON booleans still round-trip, but the type then
|
||||
`#!cpp bool` — `#!cpp std::uint8_t`, say — does compile, and JSON booleans still round-trip, but the type then
|
||||
serves as both `boolean_t` and an ordinary integer: `basic_json` can no longer be constructed or assigned from a
|
||||
`#!cpp std::uint8_t` at all (the boolean and unsigned-integer `to_json` overloads become ambiguous), and
|
||||
[`get<std::uint8_t>()`](../../api/basic_json/get.md) on a number throws
|
||||
@@ -506,7 +506,7 @@ Both types are stored **directly** inside `basic_json`'s union.
|
||||
|
||||
- `#!cpp std::is_integral` must be satisfied: `NumberIntegerType` must be a **signed** integer type,
|
||||
`NumberUnsignedType` an **unsigned** integer type or the same type as `NumberIntegerType` (see
|
||||
[below](#same-type-for-both)). Class types are not supported -- among others, the constructors taking integer values
|
||||
[below](#same-type-for-both)). Class types are not supported — among others, the constructors taking integer values
|
||||
are constrained on `#!cpp std::is_integral`.
|
||||
- Trivially default-constructible, trivially copyable, and trivially destructible (union member).
|
||||
- `#!cpp std::numeric_limits` must be specialized for both types.
|
||||
@@ -636,7 +636,7 @@ process deeply nested values without recursion.
|
||||
|
||||
### Always required
|
||||
|
||||
- The template must accept **two** type arguments. It does not have to give the second one a default -- `basic_json`
|
||||
- The template must accept **two** type arguments. It does not have to give the second one a default — `basic_json`
|
||||
declares the parameter as `#!cpp template<typename T, typename SFINAE = void> class JSONSerializer`, so uses such as
|
||||
`#!cpp JSONSerializer<T>` inside the library supply `#!cpp void` themselves. The second parameter exists so that
|
||||
partial specializations can be constrained by SFINAE.
|
||||
@@ -669,7 +669,7 @@ using binary_t = nlohmann::byte_container_with_subtype<BinaryType>;
|
||||
|
||||
### Always required
|
||||
|
||||
- A non-`final` class type -- [`byte_container_with_subtype`](../../api/byte_container_with_subtype/index.md) derives
|
||||
- A non-`final` class type — [`byte_container_with_subtype`](../../api/byte_container_with_subtype/index.md) derives
|
||||
from it publicly.
|
||||
- A member type `value_type` that is **exactly one byte** wide (e.g., `#!cpp std::uint8_t`, `#!cpp char`, or
|
||||
`#!cpp std::byte`). Readers and writers reinterpret the container's storage as raw bytes, so a wider `value_type` is
|
||||
@@ -697,7 +697,7 @@ such a container to a `basic_json` value.
|
||||
!!! tip "Reference implementation"
|
||||
|
||||
`docs/mkdocs/docs/examples/custom_binary_type.hpp` wraps a private `#!cpp std::vector<std::uint8_t>` and satisfies
|
||||
every requirement above -- a good starting point for a custom `BinaryType`.
|
||||
every requirement above — a good starting point for a custom `BinaryType`.
|
||||
|
||||
```cpp
|
||||
--8<-- "examples/custom_binary_type.hpp"
|
||||
@@ -733,7 +733,7 @@ such a container to a `basic_json` value.
|
||||
| `QByteArray` | no `empty()` (it spells that `isEmpty()`); its `insert` takes an index rather than an iterator; and it converts to `string_t`, which makes `to_json` ambiguous between a string and a binary value |
|
||||
| `#!cpp std::string` | `binary_t::container_type` and `string_t` would be the same type, so the two [`swap`](../../api/basic_json/swap.md) overloads collide and `basic_json` cannot be instantiated at all |
|
||||
| `#!cpp std::deque<std::uint8_t>` | storage is not contiguous, so there is no `data()` |
|
||||
| containers whose `value_type` is wider than one byte | see above -- accepted by the compiler, wrong at runtime |
|
||||
| containers whose `value_type` is wider than one byte | see above — accepted by the compiler, wrong at runtime |
|
||||
|
||||
## `CustomBaseClass`
|
||||
|
||||
|
||||
@@ -50,7 +50,7 @@ Defining [`JSON_DIAGNOSTICS`](../api/macros/json_diagnostics.md) before includin
|
||||
`type_error`/`out_of_range`-style exceptions with a JSON Pointer to the offending value, which can help pinpoint
|
||||
where in a large document a runtime error occurred. This only applies to exceptions thrown *after* a value
|
||||
exists (e.g. during element access); parse errors, which happen before any value exists to point at, are not
|
||||
covered by this mechanism -- see [Parsing and exceptions](../features/parsing/parse_exceptions.md) for how parse
|
||||
covered by this mechanism — see [Parsing and exceptions](../features/parsing/parse_exceptions.md) for how parse
|
||||
errors report their own location instead.
|
||||
|
||||
## See also
|
||||
|
||||
@@ -230,7 +230,7 @@ JSON uses the `\uxxxx` format to describe Unicode characters. Code points above
|
||||
!!! failure "Example message"
|
||||
|
||||
```
|
||||
parse error at 14: missing or wrong low surrogate
|
||||
[json.exception.parse_error.102] parse error at 14: missing or wrong low surrogate
|
||||
```
|
||||
|
||||
!!! note
|
||||
@@ -244,7 +244,7 @@ Unicode supports code points up to 0x10FFFF. Code points above 0x10FFFF are inva
|
||||
!!! failure "Example message"
|
||||
|
||||
```
|
||||
parse error: code points above 0x10FFFF are invalid
|
||||
[json.exception.parse_error.103] parse error: code points above 0x10FFFF are invalid
|
||||
```
|
||||
|
||||
!!! note
|
||||
@@ -940,7 +940,7 @@ The provided array index `i` is larger than `size-1`.
|
||||
!!! failure "Example message"
|
||||
|
||||
```
|
||||
array index 3 is out of range
|
||||
[json.exception.out_of_range.401] array index 3 is out of range
|
||||
```
|
||||
|
||||
### json.exception.out_of_range.402
|
||||
@@ -950,7 +950,7 @@ The special array index `-` in a JSON Pointer never describes a valid element of
|
||||
!!! failure "Example message"
|
||||
|
||||
```
|
||||
array index '-' (3) is out of range
|
||||
[json.exception.out_of_range.402] array index '-' (3) is out of range
|
||||
```
|
||||
|
||||
### json.exception.out_of_range.403
|
||||
@@ -960,7 +960,7 @@ The provided key was not found in the JSON object.
|
||||
!!! failure "Example message"
|
||||
|
||||
```
|
||||
key 'foo' not found
|
||||
[json.exception.out_of_range.403] key 'foo' not found
|
||||
```
|
||||
|
||||
### json.exception.out_of_range.404
|
||||
@@ -971,7 +971,7 @@ contains other characters (e.g., `1a`), or `-` where it cannot be used.
|
||||
!!! failure "Example message"
|
||||
|
||||
```
|
||||
unresolved reference token 'foo'
|
||||
[json.exception.out_of_range.404] unresolved reference token 'foo'
|
||||
```
|
||||
|
||||
### json.exception.out_of_range.405
|
||||
@@ -983,7 +983,7 @@ also thrown when the parent or a reference token of an empty JSON Pointer is req
|
||||
!!! failure "Example message"
|
||||
|
||||
```
|
||||
JSON pointer has no parent
|
||||
[json.exception.out_of_range.405] JSON pointer has no parent
|
||||
```
|
||||
|
||||
### json.exception.out_of_range.406
|
||||
@@ -995,7 +995,7 @@ double-precision number when `number_float_t` is `#!cpp float`.
|
||||
!!! failure "Example messages"
|
||||
|
||||
```
|
||||
number overflow parsing '10E1000'
|
||||
[json.exception.out_of_range.406] number overflow parsing '10E1000'
|
||||
```
|
||||
```
|
||||
[json.exception.out_of_range.406] syntax error while parsing CBOR value: number overflow
|
||||
@@ -1030,10 +1030,10 @@ exception, because they serialize integers beyond 64 bits as high-precision numb
|
||||
!!! failure "Example messages"
|
||||
|
||||
```
|
||||
integer number 18446744073709551615 cannot be represented by BON8 as it does not fit int64
|
||||
[json.exception.out_of_range.407] integer number 18446744073709551615 cannot be represented by BON8 as it does not fit int64
|
||||
```
|
||||
```
|
||||
integer number 1267650600228229401496703205376 cannot be represented by CBOR as it does not fit [-2^64, 2^64-1]
|
||||
[json.exception.out_of_range.407] integer number 1267650600228229401496703205376 cannot be represented by CBOR as it does not fit [-2^64, 2^64-1]
|
||||
```
|
||||
|
||||
### json.exception.out_of_range.408
|
||||
@@ -1051,7 +1051,7 @@ so any value it produces can still be read back.
|
||||
!!! failure "Example messages"
|
||||
|
||||
```
|
||||
excessive array size: 8658170730974374167
|
||||
[json.exception.out_of_range.408] excessive array size: 8658170730974374167
|
||||
```
|
||||
```
|
||||
[json.exception.out_of_range.408] syntax error while parsing CBOR size: excessive array size
|
||||
@@ -1070,7 +1070,7 @@ Key identifiers to be serialized to BSON cannot contain code point U+0000, since
|
||||
!!! failure "Example message"
|
||||
|
||||
```
|
||||
BSON key cannot contain code point U+0000 (at byte 2)
|
||||
[json.exception.out_of_range.409] BSON key cannot contain code point U+0000 (at byte 2)
|
||||
```
|
||||
|
||||
### json.exception.out_of_range.410
|
||||
@@ -1082,8 +1082,8 @@ a JSON pointer exceeds the range of `size_type` (e.g., on 32-bit platforms).
|
||||
!!! failure "Example message"
|
||||
|
||||
```
|
||||
enum value out of range
|
||||
array index 18446744073709551615 exceeds size_type
|
||||
[json.exception.out_of_range.410] enum value out of range
|
||||
[json.exception.out_of_range.410] array index 18446744073709551615 exceeds size_type
|
||||
```
|
||||
|
||||
The second message is thrown, for instance, by `#!cpp json::parse("[1, 2]").at("/18446744073709551615"_json_pointer)`
|
||||
@@ -1098,7 +1098,7 @@ A JSON Patch `add` operation cannot be applied because the target location's par
|
||||
!!! failure "Example message"
|
||||
|
||||
```
|
||||
cannot add value: the JSON Patch 'add' target's parent is of type string, but must be an object or array
|
||||
[json.exception.out_of_range.411] cannot add value: the JSON Patch 'add' target's parent is of type string, but must be an object or array
|
||||
```
|
||||
|
||||
!!! note
|
||||
@@ -1116,10 +1116,10 @@ is thrown when a value is too large to be described by such a length field.
|
||||
!!! failure "Example messages"
|
||||
|
||||
```
|
||||
BSON length 2147483661 exceeds maximum of 2147483647
|
||||
[json.exception.out_of_range.412] BSON length 2147483661 exceeds maximum of 2147483647
|
||||
```
|
||||
```
|
||||
MessagePack length 4294967296 exceeds maximum of 4294967295
|
||||
[json.exception.out_of_range.412] MessagePack length 4294967296 exceeds maximum of 4294967295
|
||||
```
|
||||
|
||||
!!! note
|
||||
@@ -1136,7 +1136,7 @@ A JSON Patch `remove` operation cannot be applied because the target location's
|
||||
!!! failure "Example message"
|
||||
|
||||
```
|
||||
cannot remove value: the JSON Patch 'remove' target's parent is of type number, but must be an object or array
|
||||
[json.exception.out_of_range.413] cannot remove value: the JSON Patch 'remove' target's parent is of type number, but must be an object or array
|
||||
```
|
||||
|
||||
!!! note
|
||||
@@ -1150,7 +1150,7 @@ A JSON Patch `move` operation's `"from"` location is a proper prefix of its `"pa
|
||||
!!! failure "Example message"
|
||||
|
||||
```
|
||||
cannot move value: 'from' path '/0' is a proper prefix of 'path' '/0/0'
|
||||
[json.exception.out_of_range.414] cannot move value: 'from' path '/0' is a proper prefix of 'path' '/0/0'
|
||||
```
|
||||
|
||||
!!! note
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
|
||||
yield different results (`#!json [true]` vs. `#!json true`)?
|
||||
|
||||
This is a known issue, and -- even worse -- the behavior differs between GCC and Clang. The "culprit" for this is the library's constructor overloads for initializer lists to allow syntax like
|
||||
This is a known issue, and — even worse — the behavior differs between GCC and Clang. The "culprit" for this is the library's constructor overloads for initializer lists to allow syntax like
|
||||
|
||||
```cpp
|
||||
json array = {1, 2, 3, 4};
|
||||
@@ -394,8 +394,8 @@ As described [above](#parse-errors-reading-non-ascii-characters), the library st
|
||||
|
||||
No. `basic_json` provides no built-in synchronization, the same as `std::map` or `std::vector`. Concurrent reads of
|
||||
the same value from multiple threads are safe, as are concurrent (non-overlapping) accesses to independent `json`
|
||||
objects. However, any concurrent write to a `json` object -- or a concurrent read while another thread writes to the
|
||||
same object -- is a data race and requires external synchronization (e.g., a `std::mutex`) by the caller.
|
||||
objects. However, any concurrent write to a `json` object — or a concurrent read while another thread writes to the
|
||||
same object — is a data race and requires external synchronization (e.g., a `std::mutex`) by the caller.
|
||||
|
||||
### Schema validation
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ All releases at a glance (hover a marker for its version and date):
|
||||
--8<-- "images/release_timeline.svg"
|
||||
</div>
|
||||
|
||||
<p class="nj-caption" markdown>Releases from 1.0.0 to the latest one, on a time axis by year. Filled dots with a version label are minor or major releases, rings are patch releases.</p>
|
||||
<p class="nj-caption" markdown>From the first commit (diamond) in 2013 to the latest release, on a time axis by year. Filled dots with a version label are minor or major releases, rings are patch releases.</p>
|
||||
|
||||
## Unreleased
|
||||
|
||||
@@ -32,124 +32,124 @@ All releases at a glance (hover a marker for its version and date):
|
||||
|
||||
| Release | Date | Summary |
|
||||
|---------|------|---------|
|
||||
| [v3.12.0](v3.12.0.md) | 2025-04-11 | Fixes bugs found in 3.11.3 and adds several features. No public API was removed or renamed. |
|
||||
| [v3.12.0](v3.12.0.md) | 2025-04-11 | Fixes bugs found in 3.11.3 and adds several features. No public API was removed or renamed. **Highlights:** diagnostic byte positions (`start_pos`/`end_pos`); templated conversion macros and `NLOHMANN_DEFINE_DERIVED_TYPE`; `std::optional` support. |
|
||||
|
||||
## Version 3.11.x
|
||||
|
||||
| Release | Date | Summary |
|
||||
|---------|------|---------|
|
||||
| [v3.11.3](v3.11.3.md) | 2023-11-28 | Adds features and fixes bugs found in 3.11.2. All changes are backward-compatible. |
|
||||
| [v3.11.2](v3.11.2.md) | 2022-08-12 | Fixes bugs found in 3.11.1 and restructures the namespace. All changes are backward-compatible. |
|
||||
| [v3.11.1](v3.11.1.md) | 2022-08-01 | Fixes a regression from 3.11.0. All changes are backward-compatible. |
|
||||
| [v3.11.0](v3.11.0.md) | 2022-08-01 | One of the largest releases ever. All changes are backward-compatible. |
|
||||
| [v3.11.3](v3.11.3.md) | 2023-11-28 | Adds features and fixes bugs found in 3.11.2. All changes are backward-compatible. **Highlights:** custom base class for `basic_json`; serialization-only conversion macros; Bazel and Swift Package Manager support. |
|
||||
| [v3.11.2](v3.11.2.md) | 2022-08-12 | Fixes bugs found in 3.11.1 and restructures the namespace. All changes are backward-compatible. **Highlights:** fixes `value` for strings and size types; restores `json_pointer` as associative-container key; restructured inline namespace. |
|
||||
| [v3.11.1](v3.11.1.md) | 2022-08-01 | Fixes a regression from 3.11.0. All changes are backward-compatible. **Highlights:** restores the global `_json` and `_json_pointer` literals. |
|
||||
| [v3.11.0](v3.11.0.md) | 2022-08-01 | One of the largest releases ever. All changes are backward-compatible. **Highlights:** `std::string_view` keys; BJData binary format; C++20 support including `operator<=>`. |
|
||||
|
||||
## Version 3.10.x
|
||||
|
||||
| Release | Date | Summary |
|
||||
|---------|------|---------|
|
||||
| [v3.10.5](v3.10.5.md) | 2022-01-03 | Bug-fix release. All changes are backward-compatible. |
|
||||
| [v3.10.4](v3.10.4.md) | 2021-10-16 | Fixes regressions introduced in 3.10.0. All changes are backward-compatible. |
|
||||
| [v3.10.3](v3.10.3.md) | 2021-10-08 | Fixes more regressions from 3.10.0. All changes are backward-compatible. |
|
||||
| [v3.10.2](v3.10.2.md) | 2021-08-26 | Re-release of 3.10.1, whose Git tag pointed at the wrong commit due to a bug in the release script. All changes are backward-compatible. |
|
||||
| [v3.10.1](v3.10.1.md) | 2021-08-24 | Fixes a regression from 3.10.0. All changes are backward-compatible. |
|
||||
| [v3.10.0](v3.10.0.md) | 2021-08-17 | Feature release. All changes are backward-compatible. |
|
||||
| [v3.10.5](v3.10.5.md) | 2022-01-03 | Bug-fix release. All changes are backward-compatible. **Highlights:** guards the `std::filesystem` conversions with `JSON_HAS_FILESYSTEM`. |
|
||||
| [v3.10.4](v3.10.4.md) | 2021-10-16 | Fixes regressions introduced in 3.10.0. All changes are backward-compatible. **Highlights:** fixes the `std::filesystem::path` conversion; fixes types with explicit defaulted constructors; fixes `std::find`/`std::remove` return values. |
|
||||
| [v3.10.3](v3.10.3.md) | 2021-10-08 | Fixes more regressions from 3.10.0. All changes are backward-compatible. **Highlights:** fixes extended-diagnostics assertions in `update` and array insertion; custom allocators for binary output; conversion from `begin()`/`end()`-only types. |
|
||||
| [v3.10.2](v3.10.2.md) | 2021-08-26 | Re-release of 3.10.1, whose Git tag pointed at the wrong commit due to a bug in the release script. All changes are backward-compatible. **Highlights:** re-release of 3.10.1 with the correct Git tag. |
|
||||
| [v3.10.1](v3.10.1.md) | 2021-08-24 | Fixes a regression from 3.10.0. All changes are backward-compatible. **Highlights:** fixes an extended-diagnostics assertion with `ordered_json`; hardens the GDB pretty-printer. |
|
||||
| [v3.10.0](v3.10.0.md) | 2021-08-17 | Feature release. All changes are backward-compatible. **Highlights:** extended diagnostic messages (`JSON_DIAGNOSTICS`); GDB pretty-printer; CBOR tag storage. |
|
||||
|
||||
## Version 3.9.x
|
||||
|
||||
| Release | Date | Summary |
|
||||
|---------|------|---------|
|
||||
| [v3.9.1](v3.9.1.md) | 2020-08-06 | Fixes two regressions from 3.9.0. All changes are backward-compatible. |
|
||||
| [v3.9.0](v3.9.0.md) | 2020-07-27 | Feature release adding four long-requested features. All changes are backward-compatible. |
|
||||
| [v3.9.1](v3.9.1.md) | 2020-08-06 | Fixes two regressions from 3.9.0. All changes are backward-compatible. **Highlights:** accepts consecutive comments; completes the `ordered_json` interface. |
|
||||
| [v3.9.0](v3.9.0.md) | 2020-07-27 | Feature release adding four long-requested features. All changes are backward-compatible. **Highlights:** comment parsing; `ordered_json`; switch to disable implicit conversions. |
|
||||
|
||||
## Version 3.8.x
|
||||
|
||||
| Release | Date | Summary |
|
||||
|---------|------|---------|
|
||||
| [v3.8.0](v3.8.0.md) | 2020-06-14 | Feature release. All changes are backward-compatible. |
|
||||
| [v3.8.0](v3.8.0.md) | 2020-06-14 | Feature release. All changes are backward-compatible. **Highlights:** binary value type for CBOR, BSON, and MessagePack; input adapters for any `LegacyInputIterator` container; fixes `contains` for JSON pointers. |
|
||||
|
||||
## Version 3.7.x
|
||||
|
||||
| Release | Date | Summary |
|
||||
|---------|------|---------|
|
||||
| [v3.7.3](v3.7.3.md) | 2019-11-17 | Fixes a regression from 3.7.2 that could yield quadratic complexity in destructor calls. All changes are backward-compatible. |
|
||||
| [v3.7.2](v3.7.2.md) | 2019-11-10 | Fixes a stack overflow for deeply nested input by making the destructor iterative; parsing of JSON text is now bounded only by available memory (the binary-format parsers still recurse). All changes are backward-compatible. |
|
||||
| [v3.7.1](v3.7.1.md) | 2019-11-06 | Bug-fix release. All changes are backward-compatible. |
|
||||
| [v3.7.0](v3.7.0.md) | 2019-07-28 | Convenience features and house-keeping. All changes are backward-compatible. |
|
||||
| [v3.7.3](v3.7.3.md) | 2019-11-17 | Fixes a regression from 3.7.2 that could yield quadratic complexity in destructor calls. All changes are backward-compatible. **Highlights:** fixes quadratic complexity in destructor calls. |
|
||||
| [v3.7.2](v3.7.2.md) | 2019-11-10 | Fixes a stack overflow for deeply nested input by making the destructor iterative; parsing of JSON text is now bounded only by available memory (the binary-format parsers still recurse). All changes are backward-compatible. **Highlights:** iterative destructor fixes a stack overflow on deeply nested input. |
|
||||
| [v3.7.1](v3.7.1.md) | 2019-11-06 | Bug-fix release. All changes are backward-compatible. **Highlights:** fixes a crash when serializing the minimum `std::int64_t`; fixes `contains` for JSON pointers; `items` with custom string types. |
|
||||
| [v3.7.0](v3.7.0.md) | 2019-07-28 | Convenience features and house-keeping. All changes are backward-compatible. **Highlights:** `contains` overload for JSON pointers; generic `to_string`; return value for `emplace_back`. |
|
||||
|
||||
## Version 3.6.x
|
||||
|
||||
| Release | Date | Summary |
|
||||
|---------|------|---------|
|
||||
| [v3.6.1](v3.6.1.md) | 2019-03-20 | Fixes a regression (GCC 7/8 compilation) and a `<Windows.h>` build error introduced in 3.6.0. All changes are backward-compatible. |
|
||||
| [v3.6.0](v3.6.0.md) | 2019-03-20 | Feature release. All changes are backward-compatible. |
|
||||
| [v3.6.1](v3.6.1.md) | 2019-03-20 | Fixes a regression (GCC 7/8 compilation) and a `<Windows.h>` build error introduced in 3.6.0. All changes are backward-compatible. **Highlights:** fixes a GCC 7/8 compilation regression; fixes a `<Windows.h>` build error. |
|
||||
| [v3.6.0](v3.6.0.md) | 2019-03-20 | Feature release. All changes are backward-compatible. **Highlights:** reworked JSON pointer interface; `contains` function; faster integer serialization. |
|
||||
|
||||
## Version 3.5.x
|
||||
|
||||
| Release | Date | Summary |
|
||||
|---------|------|---------|
|
||||
| [v3.5.0](v3.5.0.md) | 2018-12-22 | Feature release. All changes are backward-compatible. |
|
||||
| [v3.5.0](v3.5.0.md) | 2018-12-22 | Feature release. All changes are backward-compatible. **Highlights:** structured bindings via `items`; reading from `FILE*`; fixes `eofbit` handling on streams. |
|
||||
|
||||
## Version 3.4.x
|
||||
|
||||
| Release | Date | Summary |
|
||||
|---------|------|---------|
|
||||
| [v3.4.0](v3.4.0.md) | 2018-10-30 | Feature release. All changes are backward-compatible. |
|
||||
| [v3.4.0](v3.4.0.md) | 2018-10-30 | Feature release. All changes are backward-compatible. **Highlights:** BSON support; Unicode error handlers for `dump`; `NLOHMANN_JSON_SERIALIZE_ENUM`. |
|
||||
|
||||
## Version 3.3.x
|
||||
|
||||
| Release | Date | Summary |
|
||||
|---------|------|---------|
|
||||
| [v3.3.0](v3.3.0.md) | 2018-10-05 | Feature release. All changes are backward-compatible. |
|
||||
| [v3.3.0](v3.3.0.md) | 2018-10-05 | Feature release. All changes are backward-compatible. **Highlights:** GCC 4.8 support; `get_to`; overhauled CMake integration. |
|
||||
|
||||
## Version 3.2.x
|
||||
|
||||
| Release | Date | Summary |
|
||||
|---------|------|---------|
|
||||
| [v3.2.0](v3.2.0.md) | 2018-08-20 | Feature release. All changes are backward-compatible. |
|
||||
| [v3.2.0](v3.2.0.md) | 2018-08-20 | Feature release. All changes are backward-compatible. **Highlights:** SAX interface and non-recursive parser; parsing from wide strings; conversion to `std::string_view`. |
|
||||
|
||||
## Version 3.1.x
|
||||
|
||||
| Release | Date | Summary |
|
||||
|---------|------|---------|
|
||||
| [v3.1.2](v3.1.2.md) | 2018-03-14 | Bug-fix release. All changes are backward-compatible. |
|
||||
| [v3.1.1](v3.1.1.md) | 2018-02-13 | Bug-fix release. All changes are backward-compatible. |
|
||||
| [v3.1.0](v3.1.0.md) | 2018-02-01 | Feature release. All changes are backward-compatible. |
|
||||
| [v3.1.2](v3.1.2.md) | 2018-03-14 | Bug-fix release. All changes are backward-compatible. **Highlights:** fixes a memory leak in the parser callback; user-defined string types in parser and serializer. |
|
||||
| [v3.1.1](v3.1.1.md) | 2018-02-13 | Bug-fix release. All changes are backward-compatible. **Highlights:** fixes parsing of indefinite-length CBOR strings; fixes a user-defined conversion to vector types; fixes UBJSON overflow detection. |
|
||||
| [v3.1.0](v3.1.0.md) | 2018-02-01 | Feature release. All changes are backward-compatible. **Highlights:** UBJSON support; JSON Merge Patch; Grisu2 floating-point output. |
|
||||
|
||||
## Version 3.0.x
|
||||
|
||||
| Release | Date | Summary |
|
||||
|---------|------|---------|
|
||||
| [v3.0.1](v3.0.1.md) | 2017-12-29 | Fixes small issues in the [JSON Pointer](../../features/json_pointer.md) and [JSON Patch](../../features/json_patch.md) implementations (invalid "copy" targets and non-integer array indices). All changes are backward-compatible. |
|
||||
| [v3.0.0](v3.0.0.md) | 2017-12-17 | First 3.x release — a major release with breaking changes (see the [migration guide](../../integration/migration_guide.md)). |
|
||||
| [v3.0.1](v3.0.1.md) | 2017-12-29 | Fixes small issues in the [JSON Pointer](../../features/json_pointer.md) and [JSON Patch](../../features/json_patch.md) implementations (invalid "copy" targets and non-integer array indices). All changes are backward-compatible. **Highlights:** fixes invalid JSON Patch "copy" targets; fixes non-integer array indices in JSON Pointer. |
|
||||
| [v3.0.0](v3.0.0.md) | 2017-12-17 | First 3.x release — a major release with breaking changes (see the [migration guide](../../integration/migration_guide.md)). **Highlights:** user-defined exceptions with identifiers; non-throwing `accept` and `allow_exceptions`; `update` to merge objects. |
|
||||
|
||||
## Version 2.1.x
|
||||
|
||||
| Release | Date | Summary |
|
||||
|---------|------|---------|
|
||||
| [v2.1.1](v2.1.1.md) | 2017-02-25 | Bug-fix release. All changes are backward-compatible. |
|
||||
| [v2.1.0](v2.1.0.md) | 2017-01-28 | Feature release. All changes are backward-compatible. |
|
||||
| [v2.1.1](v2.1.1.md) | 2017-02-25 | Bug-fix release. All changes are backward-compatible. **Highlights:** locale-independent number parsing and serialization; correct floating-point round-tripping; GPG-signed commits and files. |
|
||||
| [v2.1.0](v2.1.0.md) | 2017-01-28 | Feature release. All changes are backward-compatible. **Highlights:** conversions from and to arbitrary user-defined types; `meta` function; `JSON_NOEXCEPTION`. |
|
||||
|
||||
## Version 2.0.x
|
||||
|
||||
| Release | Date | Summary |
|
||||
|---------|------|---------|
|
||||
| [v2.0.10](v2.0.10.md) | 2017-01-02 | Fixes several security-relevant bugs in the CBOR and MessagePack parsers found by OSS-Fuzz. All changes are backward-compatible. |
|
||||
| [v2.0.9](v2.0.9.md) | 2016-12-16 | Adds the [CBOR](../../features/binary_formats/cbor.md) and [MessagePack](../../features/binary_formats/messagepack.md) binary formats. All changes are backward-compatible. |
|
||||
| [v2.0.8](v2.0.8.md) | 2016-12-02 | Adds the [`emplace`](../../api/basic_json/emplace.md) and [`emplace_back`](../../api/basic_json/emplace_back.md) functions and improves parsing and serialization performance. All changes are backward-compatible. |
|
||||
| [v2.0.7](v2.0.7.md) | 2016-11-02 | Fixes several parser bugs found through the "Parsing JSON is a Minefield" study (short files, encoding detection, surrogate pairs). All changes are backward-compatible. |
|
||||
| [v2.0.6](v2.0.6.md) | 2016-10-15 | Fixes [`operator[]`](../../api/basic_json/operator%5B%5D.md) for [JSON pointers](../../features/json_pointer.md) so that it creates missing values like the other overloads. All changes are backward-compatible. |
|
||||
| [v2.0.5](v2.0.5.md) | 2016-09-14 | Fixes a remaining stream end-of-file detection bug in the parser. All changes are backward-compatible. |
|
||||
| [v2.0.4](v2.0.4.md) | 2016-09-11 | Fixes stream end-of-file detection in the parser. All changes are backward-compatible. |
|
||||
| [v2.0.3](v2.0.3.md) | 2016-08-31 | Generalizes the parser to accept any contiguous sequence of one-byte elements and deprecates the input-stream constructor in favor of the [`parse`](../../api/basic_json/parse.md) function. All changes are backward-compatible. |
|
||||
| [v2.0.2](v2.0.2.md) | 2016-07-31 | Overhauls the parser (now rejecting unescaped control characters), tightens the class invariants, and cleans up the code. All changes are backward-compatible. |
|
||||
| [v2.0.1](v2.0.1.md) | 2016-06-28 | Fixes a performance regression in the [`dump`](../../api/basic_json/dump.md) function by adjusting the stream locale once per serialization. All changes are backward-compatible. |
|
||||
| [v2.0.0](v2.0.0.md) | 2016-06-24 | Feature release with a minor (potentially non-backward-compatible) API change from added `noexcept` and `constexpr` specifiers. |
|
||||
| [v2.0.10](v2.0.10.md) | 2017-01-02 | Fixes several security-relevant bugs in the CBOR and MessagePack parsers found by OSS-Fuzz. All changes are backward-compatible. **Highlights:** fixes security-relevant bugs in the CBOR parser; fixes security-relevant bugs in the MessagePack parser. |
|
||||
| [v2.0.9](v2.0.9.md) | 2016-12-16 | Adds the [CBOR](../../features/binary_formats/cbor.md) and [MessagePack](../../features/binary_formats/messagepack.md) binary formats. All changes are backward-compatible. **Highlights:** CBOR support; MessagePack support. |
|
||||
| [v2.0.8](v2.0.8.md) | 2016-12-02 | Adds the [`emplace`](../../api/basic_json/emplace.md) and [`emplace_back`](../../api/basic_json/emplace_back.md) functions and improves parsing and serialization performance. All changes are backward-compatible. **Highlights:** `emplace` and `emplace_back`; faster parsing; faster serialization. |
|
||||
| [v2.0.7](v2.0.7.md) | 2016-11-02 | Fixes several parser bugs found through the "Parsing JSON is a Minefield" study (short files, encoding detection, surrogate pairs). All changes are backward-compatible. **Highlights:** fixes short-file handling; fixes encoding detection; fixes surrogate pairs. |
|
||||
| [v2.0.6](v2.0.6.md) | 2016-10-15 | Fixes [`operator[]`](../../api/basic_json/operator%5B%5D.md) for [JSON pointers](../../features/json_pointer.md) so that it creates missing values like the other overloads. All changes are backward-compatible. **Highlights:** `operator[]` creates missing values for JSON pointers. |
|
||||
| [v2.0.5](v2.0.5.md) | 2016-09-14 | Fixes a remaining stream end-of-file detection bug in the parser. All changes are backward-compatible. **Highlights:** fixes a remaining stream end-of-file bug. |
|
||||
| [v2.0.4](v2.0.4.md) | 2016-09-11 | Fixes stream end-of-file detection in the parser. All changes are backward-compatible. **Highlights:** fixes stream end-of-file detection. |
|
||||
| [v2.0.3](v2.0.3.md) | 2016-08-31 | Generalizes the parser to accept any contiguous sequence of one-byte elements and deprecates the input-stream constructor in favor of the [`parse`](../../api/basic_json/parse.md) function. All changes are backward-compatible. **Highlights:** parser accepts any contiguous sequence of one-byte elements; deprecates the input-stream constructor in favor of `parse`. |
|
||||
| [v2.0.2](v2.0.2.md) | 2016-07-31 | Overhauls the parser (now rejecting unescaped control characters), tightens the class invariants, and cleans up the code. All changes are backward-compatible. **Highlights:** overhauled parser rejecting unescaped control characters; tighter class invariants; code cleanup. |
|
||||
| [v2.0.1](v2.0.1.md) | 2016-06-28 | Fixes a performance regression in the [`dump`](../../api/basic_json/dump.md) function by adjusting the stream locale once per serialization. All changes are backward-compatible. **Highlights:** fixes a performance regression in `dump`. |
|
||||
| [v2.0.0](v2.0.0.md) | 2016-06-24 | Feature release with a minor (potentially non-backward-compatible) API change from added `noexcept` and `constexpr` specifiers. **Highlights:** JSON Pointer support in `at` and `operator[]`, plus `flatten` and `unflatten`; JSON Patch via `diff` and `patch`; unsigned 64-bit integers. |
|
||||
|
||||
## Version 1.1.x
|
||||
|
||||
| Release | Date | Summary |
|
||||
|---------|------|---------|
|
||||
| [v1.1.0](v1.1.0.md) | 2016-01-24 | Bug-fix and feature release. All changes are backward-compatible. |
|
||||
| [v1.1.0](v1.1.0.md) | 2016-01-24 | Bug-fix and feature release. All changes are backward-compatible. **Highlights:** improved floating-point round-tripping; `get_ref`; runtime assertions. |
|
||||
|
||||
## Version 1.0.x
|
||||
|
||||
@@ -161,3 +161,5 @@ All releases at a glance (hover a marker for its version and date):
|
||||
|
||||
- [Migration Guide](../../integration/migration_guide.md) — how to future-proof your code for the next
|
||||
major version and replace deprecated functions.
|
||||
- [Roadmap: Version 4.0](../../community/roadmap.md#version-40) — what the next major version will change and how to
|
||||
try it today.
|
||||
@@ -1,18 +1,31 @@
|
||||
# Sponsors
|
||||
|
||||
You can sponsor this library at [GitHub Sponsors](https://github.com/sponsors/nlohmann).
|
||||
You can sponsor this library at [GitHub Sponsors](https://github.com/sponsors/nlohmann). Thanks to everyone who
|
||||
supports the project!
|
||||
|
||||
## Priority Sponsor
|
||||
## Priority Sponsors
|
||||
|
||||
- [Martti Laine](https://github.com/codeclown)
|
||||
- [Paul Harrington](https://github.com/phrrngtn)
|
||||
- [Mercedes-Benz](https://github.com/mercedes-benz)
|
||||
- [FastNetMon](https://github.com/FastNetMon)
|
||||
|
||||
## Named Sponsors
|
||||
|
||||
- [Paul Harrington](https://github.com/phrrngtn)
|
||||
- [Steve Wagner](https://github.com/ciroque)
|
||||
- [mccaffers](https://github.com/mccaffers)
|
||||
- [jambolo](https://github.com/jambolo)
|
||||
|
||||
## Further Sponsors
|
||||
|
||||
- [Grisha Kirilin](https://github.com/GrishaKirilin)
|
||||
- [zimmerman-dev](https://github.com/zimmerman-dev)
|
||||
- [WAAutoMaton](https://github.com/WAAutoMaton)
|
||||
- [F3D](https://github.com/f3d-app)
|
||||
- [David Alvarez Rosa](https://github.com/david-alvarez-rosa)
|
||||
- [Alex Kong](https://github.com/alex-lt-kong)
|
||||
- [Mark Oates](https://github.com/MarkOates)
|
||||
- [Martti Laine](https://github.com/codeclown)
|
||||
- Michael Hartmann
|
||||
- [Stefan Hagen](https://github.com/sthagen)
|
||||
- [Steve Sperandeo](https://github.com/homer6)
|
||||
- [Robert Jefe Lindstädt](https://github.com/eljefedelrodeodeljefe)
|
||||
- [Steve Wagner](https://github.com/ciroque)
|
||||
|
||||
Thanks everyone!
|
||||
@@ -1,109 +1,116 @@
|
||||
<svg class="nj-fig nj-fig--timeline" viewBox="0 0 880 147" role="img" aria-labelledby="nj-int-tl-title" xmlns="http://www.w3.org/2000/svg">
|
||||
<title id="nj-int-tl-title">Timeline of the 44 releases from v1.0.0 (2015-12-28) to v3.12.0 (2025-04-11): 17 minor or major releases, drawn as filled dots with their version above the axis, and 27 patch releases, drawn as rings.</title>
|
||||
<line class="nj-int-grid" x1="24.0" y1="61" x2="24.0" y2="85"/>
|
||||
<text class="nj-int-year" x="61.5" y="101">2015</text>
|
||||
<line class="nj-int-grid" x1="99.6" y1="61" x2="99.6" y2="85"/>
|
||||
<text class="nj-int-year" x="137.3" y="101">2016</text>
|
||||
<line class="nj-int-grid" x1="175.4" y1="61" x2="175.4" y2="85"/>
|
||||
<text class="nj-int-year" x="212.8" y="101">2017</text>
|
||||
<line class="nj-int-grid" x1="250.9" y1="61" x2="250.9" y2="85"/>
|
||||
<text class="nj-int-year" x="288.4" y="101">2018</text>
|
||||
<line class="nj-int-grid" x1="326.5" y1="61" x2="326.5" y2="85"/>
|
||||
<text class="nj-int-year" x="364.0" y="101">2019</text>
|
||||
<line class="nj-int-grid" x1="402.1" y1="61" x2="402.1" y2="85"/>
|
||||
<text class="nj-int-year" x="439.8" y="101">2020</text>
|
||||
<line class="nj-int-grid" x1="477.9" y1="61" x2="477.9" y2="85"/>
|
||||
<text class="nj-int-year" x="515.4" y="101">2021</text>
|
||||
<line class="nj-int-grid" x1="553.5" y1="61" x2="553.5" y2="85"/>
|
||||
<text class="nj-int-year" x="591.0" y="101">2022</text>
|
||||
<line class="nj-int-grid" x1="629.1" y1="61" x2="629.1" y2="85"/>
|
||||
<text class="nj-int-year" x="666.5" y="101">2023</text>
|
||||
<line class="nj-int-grid" x1="704.6" y1="61" x2="704.6" y2="85"/>
|
||||
<text class="nj-int-year" x="742.3" y="101">2024</text>
|
||||
<line class="nj-int-grid" x1="780.4" y1="61" x2="780.4" y2="85"/>
|
||||
<text class="nj-int-year" x="817.9" y="101">2025</text>
|
||||
<line class="nj-int-grid" x1="856.0" y1="61" x2="856.0" y2="85"/>
|
||||
<line class="nj-int-axis" x1="24" y1="77" x2="856" y2="77"/>
|
||||
<path class="nj-int-axis" fill="none" d="M98.8 114 V119 H104.3 V114"/>
|
||||
<text class="nj-int-major" x="98.8" y="136" text-anchor="start">1.x</text>
|
||||
<path class="nj-int-axis" fill="none" d="M135.8 114 V119 H186.8 V114"/>
|
||||
<text class="nj-int-major" x="161.3" y="136" text-anchor="middle">2.x</text>
|
||||
<path class="nj-int-axis" fill="none" d="M247.8 114 V119 H801.1 V114"/>
|
||||
<text class="nj-int-major" x="524.5" y="136" text-anchor="middle">3.x</text>
|
||||
<line class="nj-int-leader" x1="98.8" y1="68" x2="98.8" y2="70"/>
|
||||
<text class="nj-int-label" x="98.8" y="65">1.0</text>
|
||||
<line class="nj-int-leader" x1="104.3" y1="51" x2="104.3" y2="70"/>
|
||||
<text class="nj-int-label" x="104.3" y="48">1.1</text>
|
||||
<line class="nj-int-leader" x1="135.8" y1="68" x2="135.8" y2="70"/>
|
||||
<text class="nj-int-label" x="135.8" y="65">2.0</text>
|
||||
<line class="nj-int-leader" x1="181.0" y1="68" x2="181.0" y2="70"/>
|
||||
<text class="nj-int-label" x="181.0" y="65">2.1</text>
|
||||
<line class="nj-int-leader" x1="247.8" y1="68" x2="247.8" y2="70"/>
|
||||
<text class="nj-int-label" x="247.8" y="65">3.0</text>
|
||||
<line class="nj-int-leader" x1="257.4" y1="51" x2="257.4" y2="70"/>
|
||||
<text class="nj-int-label" x="257.4" y="48">3.1</text>
|
||||
<line class="nj-int-leader" x1="298.8" y1="68" x2="298.8" y2="70"/>
|
||||
<text class="nj-int-label" x="298.8" y="65">3.2</text>
|
||||
<line class="nj-int-leader" x1="308.3" y1="51" x2="308.3" y2="70"/>
|
||||
<text class="nj-int-label" x="308.3" y="48">3.3</text>
|
||||
<line class="nj-int-leader" x1="313.5" y1="34" x2="313.5" y2="70"/>
|
||||
<text class="nj-int-label" x="313.5" y="31">3.4</text>
|
||||
<line class="nj-int-leader" x1="324.5" y1="68" x2="324.5" y2="70"/>
|
||||
<text class="nj-int-label" x="324.5" y="65">3.5</text>
|
||||
<line class="nj-int-leader" x1="342.7" y1="51" x2="342.7" y2="70"/>
|
||||
<text class="nj-int-label" x="342.7" y="48">3.6</text>
|
||||
<line class="nj-int-leader" x1="369.6" y1="68" x2="369.6" y2="70"/>
|
||||
<text class="nj-int-label" x="369.6" y="65">3.7</text>
|
||||
<line class="nj-int-leader" x1="436.3" y1="68" x2="436.3" y2="70"/>
|
||||
<text class="nj-int-label" x="436.3" y="65">3.8</text>
|
||||
<line class="nj-int-leader" x1="445.2" y1="51" x2="445.2" y2="70"/>
|
||||
<text class="nj-int-label" x="445.2" y="48">3.9</text>
|
||||
<line class="nj-int-leader" x1="525.1" y1="68" x2="525.1" y2="70"/>
|
||||
<text class="nj-int-label" x="525.1" y="65">3.10</text>
|
||||
<line class="nj-int-leader" x1="597.4" y1="68" x2="597.4" y2="70"/>
|
||||
<text class="nj-int-label" x="597.4" y="65">3.11</text>
|
||||
<line class="nj-int-leader" x1="801.1" y1="68" x2="801.1" y2="70"/>
|
||||
<text class="nj-int-label" x="801.1" y="65">3.12</text>
|
||||
<g><title>v2.0.1 released 2016-06-28</title><circle class="nj-int-hit" cx="136.6" cy="77" r="9"/><circle class="nj-int-patch" cx="136.6" cy="77" r="3.5"/></g>
|
||||
<g><title>v2.0.2 released 2016-07-31</title><circle class="nj-int-hit" cx="143.5" cy="77" r="9"/><circle class="nj-int-patch" cx="143.5" cy="77" r="3.5"/></g>
|
||||
<g><title>v2.0.3 released 2016-08-31</title><circle class="nj-int-hit" cx="149.9" cy="77" r="9"/><circle class="nj-int-patch" cx="149.9" cy="77" r="3.5"/></g>
|
||||
<g><title>v2.0.4 released 2016-09-11</title><circle class="nj-int-hit" cx="152.2" cy="77" r="9"/><circle class="nj-int-patch" cx="152.2" cy="77" r="3.5"/></g>
|
||||
<g><title>v2.0.5 released 2016-09-14</title><circle class="nj-int-hit" cx="152.8" cy="77" r="9"/><circle class="nj-int-patch" cx="152.8" cy="77" r="3.5"/></g>
|
||||
<g><title>v2.0.6 released 2016-10-15</title><circle class="nj-int-hit" cx="159.2" cy="77" r="9"/><circle class="nj-int-patch" cx="159.2" cy="77" r="3.5"/></g>
|
||||
<g><title>v2.0.7 released 2016-11-02</title><circle class="nj-int-hit" cx="162.9" cy="77" r="9"/><circle class="nj-int-patch" cx="162.9" cy="77" r="3.5"/></g>
|
||||
<g><title>v2.0.8 released 2016-12-02</title><circle class="nj-int-hit" cx="169.2" cy="77" r="9"/><circle class="nj-int-patch" cx="169.2" cy="77" r="3.5"/></g>
|
||||
<g><title>v2.0.9 released 2016-12-16</title><circle class="nj-int-hit" cx="172.1" cy="77" r="9"/><circle class="nj-int-patch" cx="172.1" cy="77" r="3.5"/></g>
|
||||
<g><title>v2.0.10 released 2017-01-02</title><circle class="nj-int-hit" cx="175.6" cy="77" r="9"/><circle class="nj-int-patch" cx="175.6" cy="77" r="3.5"/></g>
|
||||
<g><title>v2.1.1 released 2017-02-25</title><circle class="nj-int-hit" cx="186.8" cy="77" r="9"/><circle class="nj-int-patch" cx="186.8" cy="77" r="3.5"/></g>
|
||||
<g><title>v3.0.1 released 2017-12-29</title><circle class="nj-int-hit" cx="250.3" cy="77" r="9"/><circle class="nj-int-patch" cx="250.3" cy="77" r="3.5"/></g>
|
||||
<g><title>v3.1.1 released 2018-02-13</title><circle class="nj-int-hit" cx="259.9" cy="77" r="9"/><circle class="nj-int-patch" cx="259.9" cy="77" r="3.5"/></g>
|
||||
<g><title>v3.1.2 released 2018-03-14</title><circle class="nj-int-hit" cx="265.9" cy="77" r="9"/><circle class="nj-int-patch" cx="265.9" cy="77" r="3.5"/></g>
|
||||
<g><title>v3.7.1 released 2019-11-06</title><circle class="nj-int-hit" cx="390.5" cy="77" r="9"/><circle class="nj-int-patch" cx="390.5" cy="77" r="3.5"/></g>
|
||||
<g><title>v3.7.2 released 2019-11-10</title><circle class="nj-int-hit" cx="391.3" cy="77" r="9"/><circle class="nj-int-patch" cx="391.3" cy="77" r="3.5"/></g>
|
||||
<g><title>v3.7.3 released 2019-11-17</title><circle class="nj-int-hit" cx="392.8" cy="77" r="9"/><circle class="nj-int-patch" cx="392.8" cy="77" r="3.5"/></g>
|
||||
<g><title>v3.9.1 released 2020-08-06</title><circle class="nj-int-hit" cx="447.2" cy="77" r="9"/><circle class="nj-int-patch" cx="447.2" cy="77" r="3.5"/></g>
|
||||
<g><title>v3.10.1 released 2021-08-24</title><circle class="nj-int-hit" cx="526.6" cy="77" r="9"/><circle class="nj-int-patch" cx="526.6" cy="77" r="3.5"/></g>
|
||||
<g><title>v3.10.2 released 2021-08-26</title><circle class="nj-int-hit" cx="527.0" cy="77" r="9"/><circle class="nj-int-patch" cx="527.0" cy="77" r="3.5"/></g>
|
||||
<g><title>v3.10.3 released 2021-10-08</title><circle class="nj-int-hit" cx="535.9" cy="77" r="9"/><circle class="nj-int-patch" cx="535.9" cy="77" r="3.5"/></g>
|
||||
<g><title>v3.10.4 released 2021-10-16</title><circle class="nj-int-hit" cx="537.5" cy="77" r="9"/><circle class="nj-int-patch" cx="537.5" cy="77" r="3.5"/></g>
|
||||
<g><title>v3.10.5 released 2022-01-03</title><circle class="nj-int-hit" cx="553.9" cy="77" r="9"/><circle class="nj-int-patch" cx="553.9" cy="77" r="3.5"/></g>
|
||||
<g><title>v3.11.2 released 2022-08-12</title><circle class="nj-int-hit" cx="599.6" cy="77" r="9"/><circle class="nj-int-patch" cx="599.6" cy="77" r="3.5"/></g>
|
||||
<g><title>v3.11.3 released 2023-11-28</title><circle class="nj-int-hit" cx="697.6" cy="77" r="9"/><circle class="nj-int-patch" cx="697.6" cy="77" r="3.5"/></g>
|
||||
<g><title>v1.0.0 released 2015-12-28</title><circle class="nj-int-hit" cx="98.8" cy="77" r="9"/><circle class="nj-int-minor" cx="98.8" cy="77" r="6"/></g>
|
||||
<g><title>v1.1.0 released 2016-01-24</title><circle class="nj-int-hit" cx="104.3" cy="77" r="9"/><circle class="nj-int-minor" cx="104.3" cy="77" r="6"/></g>
|
||||
<g><title>v2.0.0 released 2016-06-24</title><circle class="nj-int-hit" cx="135.8" cy="77" r="9"/><circle class="nj-int-minor" cx="135.8" cy="77" r="6"/></g>
|
||||
<g><title>v2.1.0 released 2017-01-28</title><circle class="nj-int-hit" cx="181.0" cy="77" r="9"/><circle class="nj-int-minor" cx="181.0" cy="77" r="6"/></g>
|
||||
<g><title>v3.0.0 released 2017-12-17</title><circle class="nj-int-hit" cx="247.8" cy="77" r="9"/><circle class="nj-int-minor" cx="247.8" cy="77" r="6"/></g>
|
||||
<g><title>v3.1.0 released 2018-02-01</title><circle class="nj-int-hit" cx="257.4" cy="77" r="9"/><circle class="nj-int-minor" cx="257.4" cy="77" r="6"/></g>
|
||||
<g><title>v3.2.0 released 2018-08-20</title><circle class="nj-int-hit" cx="298.8" cy="77" r="9"/><circle class="nj-int-minor" cx="298.8" cy="77" r="6"/></g>
|
||||
<g><title>v3.3.0 released 2018-10-05</title><circle class="nj-int-hit" cx="308.3" cy="77" r="9"/><circle class="nj-int-minor" cx="308.3" cy="77" r="6"/></g>
|
||||
<g><title>v3.4.0 released 2018-10-30</title><circle class="nj-int-hit" cx="313.5" cy="77" r="9"/><circle class="nj-int-minor" cx="313.5" cy="77" r="6"/></g>
|
||||
<g><title>v3.5.0 released 2018-12-22</title><circle class="nj-int-hit" cx="324.5" cy="77" r="9"/><circle class="nj-int-minor" cx="324.5" cy="77" r="6"/></g>
|
||||
<g><title>v3.6.0, v3.6.1 released 2019-03-20</title><circle class="nj-int-hit" cx="342.7" cy="77" r="9"/><circle class="nj-int-minor" cx="342.7" cy="77" r="6"/></g>
|
||||
<g><title>v3.7.0 released 2019-07-28</title><circle class="nj-int-hit" cx="369.6" cy="77" r="9"/><circle class="nj-int-minor" cx="369.6" cy="77" r="6"/></g>
|
||||
<g><title>v3.8.0 released 2020-06-14</title><circle class="nj-int-hit" cx="436.3" cy="77" r="9"/><circle class="nj-int-minor" cx="436.3" cy="77" r="6"/></g>
|
||||
<g><title>v3.9.0 released 2020-07-27</title><circle class="nj-int-hit" cx="445.2" cy="77" r="9"/><circle class="nj-int-minor" cx="445.2" cy="77" r="6"/></g>
|
||||
<g><title>v3.10.0 released 2021-08-17</title><circle class="nj-int-hit" cx="525.1" cy="77" r="9"/><circle class="nj-int-minor" cx="525.1" cy="77" r="6"/></g>
|
||||
<g><title>v3.11.0, v3.11.1 released 2022-08-01</title><circle class="nj-int-hit" cx="597.4" cy="77" r="9"/><circle class="nj-int-minor" cx="597.4" cy="77" r="6"/></g>
|
||||
<g><title>v3.12.0 released 2025-04-11</title><circle class="nj-int-hit" cx="801.1" cy="77" r="9"/><circle class="nj-int-minor" cx="801.1" cy="77" r="6"/></g>
|
||||
<svg class="nj-fig nj-fig--timeline" viewBox="0 0 880 164" role="img" aria-labelledby="nj-int-tl-title" xmlns="http://www.w3.org/2000/svg">
|
||||
<title id="nj-int-tl-title">Timeline from the first commit (2013-07-04) and the 44 releases from v1.0.0 (2015-12-28) to v3.12.0 (2025-04-11): 17 minor or major releases, drawn as filled dots with their version above the axis, and 27 patch releases, drawn as rings. The first commit is drawn as a diamond.</title>
|
||||
<line class="nj-int-grid" x1="24.0" y1="78" x2="24.0" y2="102"/>
|
||||
<text class="nj-int-year" x="55.7" y="118">2013</text>
|
||||
<line class="nj-int-grid" x1="88.0" y1="78" x2="88.0" y2="102"/>
|
||||
<text class="nj-int-year" x="119.7" y="118">2014</text>
|
||||
<line class="nj-int-grid" x1="151.9" y1="78" x2="151.9" y2="102"/>
|
||||
<text class="nj-int-year" x="183.6" y="118">2015</text>
|
||||
<line class="nj-int-grid" x1="215.9" y1="78" x2="215.9" y2="102"/>
|
||||
<text class="nj-int-year" x="247.8" y="118">2016</text>
|
||||
<line class="nj-int-grid" x1="280.0" y1="78" x2="280.0" y2="102"/>
|
||||
<text class="nj-int-year" x="311.7" y="118">2017</text>
|
||||
<line class="nj-int-grid" x1="344.0" y1="78" x2="344.0" y2="102"/>
|
||||
<text class="nj-int-year" x="375.7" y="118">2018</text>
|
||||
<line class="nj-int-grid" x1="407.9" y1="78" x2="407.9" y2="102"/>
|
||||
<text class="nj-int-year" x="439.6" y="118">2019</text>
|
||||
<line class="nj-int-grid" x1="471.9" y1="78" x2="471.9" y2="102"/>
|
||||
<text class="nj-int-year" x="503.8" y="118">2020</text>
|
||||
<line class="nj-int-grid" x1="536.0" y1="78" x2="536.0" y2="102"/>
|
||||
<text class="nj-int-year" x="567.7" y="118">2021</text>
|
||||
<line class="nj-int-grid" x1="600.0" y1="78" x2="600.0" y2="102"/>
|
||||
<text class="nj-int-year" x="631.7" y="118">2022</text>
|
||||
<line class="nj-int-grid" x1="663.9" y1="78" x2="663.9" y2="102"/>
|
||||
<text class="nj-int-year" x="695.7" y="118">2023</text>
|
||||
<line class="nj-int-grid" x1="727.9" y1="78" x2="727.9" y2="102"/>
|
||||
<text class="nj-int-year" x="759.8" y="118">2024</text>
|
||||
<line class="nj-int-grid" x1="792.0" y1="78" x2="792.0" y2="102"/>
|
||||
<text class="nj-int-year" x="823.8" y="118">2025</text>
|
||||
<line class="nj-int-grid" x1="856.0" y1="78" x2="856.0" y2="102"/>
|
||||
<line class="nj-int-axis" x1="24" y1="94" x2="856" y2="94"/>
|
||||
<path class="nj-int-axis" fill="none" d="M215.2 131 V136 H219.9 V131"/>
|
||||
<text class="nj-int-major" x="215.2" y="153" text-anchor="start">1.x</text>
|
||||
<path class="nj-int-axis" fill="none" d="M246.5 131 V136 H289.7 V131"/>
|
||||
<text class="nj-int-major" x="268.1" y="153" text-anchor="middle">2.x</text>
|
||||
<path class="nj-int-axis" fill="none" d="M341.3 131 V136 H809.6 V131"/>
|
||||
<text class="nj-int-major" x="575.5" y="153" text-anchor="middle">3.x</text>
|
||||
<line class="nj-int-leader" x1="56.2" y1="85" x2="56.2" y2="87"/>
|
||||
<text class="nj-int-label" x="56.2" y="82">first commit</text>
|
||||
<line class="nj-int-leader" x1="215.2" y1="85" x2="215.2" y2="87"/>
|
||||
<text class="nj-int-label" x="215.2" y="82">1.0</text>
|
||||
<line class="nj-int-leader" x1="219.9" y1="68" x2="219.9" y2="87"/>
|
||||
<text class="nj-int-label" x="219.9" y="65">1.1</text>
|
||||
<line class="nj-int-leader" x1="246.5" y1="85" x2="246.5" y2="87"/>
|
||||
<text class="nj-int-label" x="246.5" y="82">2.0</text>
|
||||
<line class="nj-int-leader" x1="284.7" y1="85" x2="284.7" y2="87"/>
|
||||
<text class="nj-int-label" x="284.7" y="82">2.1</text>
|
||||
<line class="nj-int-leader" x1="341.3" y1="85" x2="341.3" y2="87"/>
|
||||
<text class="nj-int-label" x="341.3" y="82">3.0</text>
|
||||
<line class="nj-int-leader" x1="349.4" y1="68" x2="349.4" y2="87"/>
|
||||
<text class="nj-int-label" x="349.4" y="65">3.1</text>
|
||||
<line class="nj-int-leader" x1="384.5" y1="85" x2="384.5" y2="87"/>
|
||||
<text class="nj-int-label" x="384.5" y="82">3.2</text>
|
||||
<line class="nj-int-leader" x1="392.5" y1="68" x2="392.5" y2="87"/>
|
||||
<text class="nj-int-label" x="392.5" y="65">3.3</text>
|
||||
<line class="nj-int-leader" x1="396.9" y1="51" x2="396.9" y2="87"/>
|
||||
<text class="nj-int-label" x="396.9" y="48">3.4</text>
|
||||
<line class="nj-int-leader" x1="406.2" y1="34" x2="406.2" y2="87"/>
|
||||
<text class="nj-int-label" x="406.2" y="31">3.5</text>
|
||||
<line class="nj-int-leader" x1="421.6" y1="85" x2="421.6" y2="87"/>
|
||||
<text class="nj-int-label" x="421.6" y="82">3.6</text>
|
||||
<line class="nj-int-leader" x1="444.4" y1="68" x2="444.4" y2="87"/>
|
||||
<text class="nj-int-label" x="444.4" y="65">3.7</text>
|
||||
<line class="nj-int-leader" x1="500.8" y1="85" x2="500.8" y2="87"/>
|
||||
<text class="nj-int-label" x="500.8" y="82">3.8</text>
|
||||
<line class="nj-int-leader" x1="508.3" y1="68" x2="508.3" y2="87"/>
|
||||
<text class="nj-int-label" x="508.3" y="65">3.9</text>
|
||||
<line class="nj-int-leader" x1="576.0" y1="85" x2="576.0" y2="87"/>
|
||||
<text class="nj-int-label" x="576.0" y="82">3.10</text>
|
||||
<line class="nj-int-leader" x1="637.1" y1="85" x2="637.1" y2="87"/>
|
||||
<text class="nj-int-label" x="637.1" y="82">3.11</text>
|
||||
<line class="nj-int-leader" x1="809.6" y1="85" x2="809.6" y2="87"/>
|
||||
<text class="nj-int-label" x="809.6" y="82">3.12</text>
|
||||
<g><title>First commit 2013-07-04</title><circle class="nj-int-hit" cx="56.2" cy="94" r="9"/><path class="nj-int-minor" d="M56.2 94 l7 -7 l7 7 l-7 7z" transform="translate(-7 0)"/></g>
|
||||
<g><title>v2.0.1 released 2016-06-28</title><circle class="nj-int-hit" cx="247.2" cy="94" r="9"/><circle class="nj-int-patch" cx="247.2" cy="94" r="3.5"/></g>
|
||||
<g><title>v2.0.2 released 2016-07-31</title><circle class="nj-int-hit" cx="253.0" cy="94" r="9"/><circle class="nj-int-patch" cx="253.0" cy="94" r="3.5"/></g>
|
||||
<g><title>v2.0.3 released 2016-08-31</title><circle class="nj-int-hit" cx="258.5" cy="94" r="9"/><circle class="nj-int-patch" cx="258.5" cy="94" r="3.5"/></g>
|
||||
<g><title>v2.0.4 released 2016-09-11</title><circle class="nj-int-hit" cx="260.4" cy="94" r="9"/><circle class="nj-int-patch" cx="260.4" cy="94" r="3.5"/></g>
|
||||
<g><title>v2.0.5 released 2016-09-14</title><circle class="nj-int-hit" cx="260.9" cy="94" r="9"/><circle class="nj-int-patch" cx="260.9" cy="94" r="3.5"/></g>
|
||||
<g><title>v2.0.6 released 2016-10-15</title><circle class="nj-int-hit" cx="266.3" cy="94" r="9"/><circle class="nj-int-patch" cx="266.3" cy="94" r="3.5"/></g>
|
||||
<g><title>v2.0.7 released 2016-11-02</title><circle class="nj-int-hit" cx="269.5" cy="94" r="9"/><circle class="nj-int-patch" cx="269.5" cy="94" r="3.5"/></g>
|
||||
<g><title>v2.0.8 released 2016-12-02</title><circle class="nj-int-hit" cx="274.8" cy="94" r="9"/><circle class="nj-int-patch" cx="274.8" cy="94" r="3.5"/></g>
|
||||
<g><title>v2.0.9 released 2016-12-16</title><circle class="nj-int-hit" cx="277.2" cy="94" r="9"/><circle class="nj-int-patch" cx="277.2" cy="94" r="3.5"/></g>
|
||||
<g><title>v2.0.10 released 2017-01-02</title><circle class="nj-int-hit" cx="280.2" cy="94" r="9"/><circle class="nj-int-patch" cx="280.2" cy="94" r="3.5"/></g>
|
||||
<g><title>v2.1.1 released 2017-02-25</title><circle class="nj-int-hit" cx="289.7" cy="94" r="9"/><circle class="nj-int-patch" cx="289.7" cy="94" r="3.5"/></g>
|
||||
<g><title>v3.0.1 released 2017-12-29</title><circle class="nj-int-hit" cx="343.4" cy="94" r="9"/><circle class="nj-int-patch" cx="343.4" cy="94" r="3.5"/></g>
|
||||
<g><title>v3.1.1 released 2018-02-13</title><circle class="nj-int-hit" cx="351.5" cy="94" r="9"/><circle class="nj-int-patch" cx="351.5" cy="94" r="3.5"/></g>
|
||||
<g><title>v3.1.2 released 2018-03-14</title><circle class="nj-int-hit" cx="356.6" cy="94" r="9"/><circle class="nj-int-patch" cx="356.6" cy="94" r="3.5"/></g>
|
||||
<g><title>v3.7.1 released 2019-11-06</title><circle class="nj-int-hit" cx="462.1" cy="94" r="9"/><circle class="nj-int-patch" cx="462.1" cy="94" r="3.5"/></g>
|
||||
<g><title>v3.7.2 released 2019-11-10</title><circle class="nj-int-hit" cx="462.8" cy="94" r="9"/><circle class="nj-int-patch" cx="462.8" cy="94" r="3.5"/></g>
|
||||
<g><title>v3.7.3 released 2019-11-17</title><circle class="nj-int-hit" cx="464.0" cy="94" r="9"/><circle class="nj-int-patch" cx="464.0" cy="94" r="3.5"/></g>
|
||||
<g><title>v3.9.1 released 2020-08-06</title><circle class="nj-int-hit" cx="510.1" cy="94" r="9"/><circle class="nj-int-patch" cx="510.1" cy="94" r="3.5"/></g>
|
||||
<g><title>v3.10.1 released 2021-08-24</title><circle class="nj-int-hit" cx="577.2" cy="94" r="9"/><circle class="nj-int-patch" cx="577.2" cy="94" r="3.5"/></g>
|
||||
<g><title>v3.10.2 released 2021-08-26</title><circle class="nj-int-hit" cx="577.6" cy="94" r="9"/><circle class="nj-int-patch" cx="577.6" cy="94" r="3.5"/></g>
|
||||
<g><title>v3.10.3 released 2021-10-08</title><circle class="nj-int-hit" cx="585.1" cy="94" r="9"/><circle class="nj-int-patch" cx="585.1" cy="94" r="3.5"/></g>
|
||||
<g><title>v3.10.4 released 2021-10-16</title><circle class="nj-int-hit" cx="586.5" cy="94" r="9"/><circle class="nj-int-patch" cx="586.5" cy="94" r="3.5"/></g>
|
||||
<g><title>v3.10.5 released 2022-01-03</title><circle class="nj-int-hit" cx="600.3" cy="94" r="9"/><circle class="nj-int-patch" cx="600.3" cy="94" r="3.5"/></g>
|
||||
<g><title>v3.11.2 released 2022-08-12</title><circle class="nj-int-hit" cx="639.1" cy="94" r="9"/><circle class="nj-int-patch" cx="639.1" cy="94" r="3.5"/></g>
|
||||
<g><title>v3.11.3 released 2023-11-28</title><circle class="nj-int-hit" cx="721.9" cy="94" r="9"/><circle class="nj-int-patch" cx="721.9" cy="94" r="3.5"/></g>
|
||||
<g><title>v1.0.0 released 2015-12-28</title><circle class="nj-int-hit" cx="215.2" cy="94" r="9"/><circle class="nj-int-minor" cx="215.2" cy="94" r="6"/></g>
|
||||
<g><title>v1.1.0 released 2016-01-24</title><circle class="nj-int-hit" cx="219.9" cy="94" r="9"/><circle class="nj-int-minor" cx="219.9" cy="94" r="6"/></g>
|
||||
<g><title>v2.0.0 released 2016-06-24</title><circle class="nj-int-hit" cx="246.5" cy="94" r="9"/><circle class="nj-int-minor" cx="246.5" cy="94" r="6"/></g>
|
||||
<g><title>v2.1.0 released 2017-01-28</title><circle class="nj-int-hit" cx="284.7" cy="94" r="9"/><circle class="nj-int-minor" cx="284.7" cy="94" r="6"/></g>
|
||||
<g><title>v3.0.0 released 2017-12-17</title><circle class="nj-int-hit" cx="341.3" cy="94" r="9"/><circle class="nj-int-minor" cx="341.3" cy="94" r="6"/></g>
|
||||
<g><title>v3.1.0 released 2018-02-01</title><circle class="nj-int-hit" cx="349.4" cy="94" r="9"/><circle class="nj-int-minor" cx="349.4" cy="94" r="6"/></g>
|
||||
<g><title>v3.2.0 released 2018-08-20</title><circle class="nj-int-hit" cx="384.5" cy="94" r="9"/><circle class="nj-int-minor" cx="384.5" cy="94" r="6"/></g>
|
||||
<g><title>v3.3.0 released 2018-10-05</title><circle class="nj-int-hit" cx="392.5" cy="94" r="9"/><circle class="nj-int-minor" cx="392.5" cy="94" r="6"/></g>
|
||||
<g><title>v3.4.0 released 2018-10-30</title><circle class="nj-int-hit" cx="396.9" cy="94" r="9"/><circle class="nj-int-minor" cx="396.9" cy="94" r="6"/></g>
|
||||
<g><title>v3.5.0 released 2018-12-22</title><circle class="nj-int-hit" cx="406.2" cy="94" r="9"/><circle class="nj-int-minor" cx="406.2" cy="94" r="6"/></g>
|
||||
<g><title>v3.6.0, v3.6.1 released 2019-03-20</title><circle class="nj-int-hit" cx="421.6" cy="94" r="9"/><circle class="nj-int-minor" cx="421.6" cy="94" r="6"/></g>
|
||||
<g><title>v3.7.0 released 2019-07-28</title><circle class="nj-int-hit" cx="444.4" cy="94" r="9"/><circle class="nj-int-minor" cx="444.4" cy="94" r="6"/></g>
|
||||
<g><title>v3.8.0 released 2020-06-14</title><circle class="nj-int-hit" cx="500.8" cy="94" r="9"/><circle class="nj-int-minor" cx="500.8" cy="94" r="6"/></g>
|
||||
<g><title>v3.9.0 released 2020-07-27</title><circle class="nj-int-hit" cx="508.3" cy="94" r="9"/><circle class="nj-int-minor" cx="508.3" cy="94" r="6"/></g>
|
||||
<g><title>v3.10.0 released 2021-08-17</title><circle class="nj-int-hit" cx="576.0" cy="94" r="9"/><circle class="nj-int-minor" cx="576.0" cy="94" r="6"/></g>
|
||||
<g><title>v3.11.0, v3.11.1 released 2022-08-01</title><circle class="nj-int-hit" cx="637.1" cy="94" r="9"/><circle class="nj-int-minor" cx="637.1" cy="94" r="6"/></g>
|
||||
<g><title>v3.12.0 released 2025-04-11</title><circle class="nj-int-hit" cx="809.6" cy="94" r="9"/><circle class="nj-int-minor" cx="809.6" cy="94" r="6"/></g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
@@ -12,8 +12,8 @@ hide:
|
||||
|
||||
---
|
||||
|
||||
Creating, parsing, accessing, and serializing JSON values, JSON Pointer/Patch, binary formats, zero-copy views,
|
||||
and more.
|
||||
Creating, parsing, accessing, and serializing JSON values, converting your own C++ types, JSON Pointer/Patch/Merge
|
||||
Patch, binary formats, zero-copy views, and more.
|
||||
|
||||
[:octicons-arrow-right-24: Features](features/index.md)
|
||||
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Marks links that leave the site with the class "nj-external", which brand.css turns into a small icon in front of
|
||||
* the link. A link is external when its host is neither the current one nor the production site. Links in the page
|
||||
* actions (edit, raw), buttons, header anchors, and links that only wrap an image (badges) are left alone.
|
||||
* Runs through Material's document$ (navigation.instant), so it also applies after an instant page switch.
|
||||
*/
|
||||
(function () {
|
||||
"use strict";
|
||||
|
||||
function mark() {
|
||||
var links = document.querySelectorAll(".md-typeset a[href]");
|
||||
for (var i = 0; i < links.length; i++) {
|
||||
var a = links[i];
|
||||
if (a.hostname === "" || a.hostname === location.hostname || a.hostname === "json.nlohmann.me") {
|
||||
continue;
|
||||
}
|
||||
if (a.protocol !== "http:" && a.protocol !== "https:") {
|
||||
continue;
|
||||
}
|
||||
if (a.matches(".md-button, .md-content__button, .headerlink") || a.querySelector("img, svg")) {
|
||||
continue;
|
||||
}
|
||||
a.classList.add("nj-external");
|
||||
}
|
||||
}
|
||||
|
||||
if (window.document$ && window.document$.subscribe) {
|
||||
window.document$.subscribe(mark);
|
||||
} else {
|
||||
document.addEventListener("DOMContentLoaded", mark);
|
||||
}
|
||||
})();
|
||||
@@ -642,6 +642,7 @@ extra_css:
|
||||
|
||||
extra_javascript:
|
||||
- js/mermaid-brand.js
|
||||
- js/external-links.js
|
||||
- js/fig-sax.js
|
||||
- js/fig-jsonview.js
|
||||
- js/fig-exceptions.js
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
<p class="nj-hero__actions">
|
||||
<a href="{{ 'integration/' | url }}" class="md-button md-button--primary nj-hero__button">Get started</a>
|
||||
<a href="{{ 'api/basic_json/' | url }}" class="md-button nj-hero__button">API documentation</a>
|
||||
<a href="{{ 'home/releases/v3.12.0/' | url }}" class="md-button nj-hero__button">Latest release</a>
|
||||
</p>
|
||||
</div>
|
||||
<div class="nj-hero__code" aria-hidden="true">
|
||||
|
||||
@@ -5,7 +5,7 @@ so after adding a release to the page, run `python3 scripts/figures/release_time
|
||||
the regenerated docs/images/release_timeline.svg. The page includes the SVG text with
|
||||
`--8<-- "images/release_timeline.svg"`, so it follows the light/dark toggle (see the `nj-fig` rules in
|
||||
docs/css/brand.css and the `nj-int-*` rules in docs/css/fig-integration.css). Every marker has a <title> tooltip.
|
||||
Rows without a date (the "Unreleased" row) are skipped; any other release row that cannot be parsed stops the script.
|
||||
The timeline also marks the first commit of the repository (FIRST_COMMIT) as a diamond. Rows without a date (the "Unreleased" row) are skipped; any other release row that cannot be parsed stops the script.
|
||||
"""
|
||||
import datetime
|
||||
import re
|
||||
@@ -19,6 +19,7 @@ PAGE = DOCS / "home" / "releases" / "index.md"
|
||||
ROW = re.compile(r"^\|\s*\[v(\d+)\.(\d+)\.(\d+)\]\([^)]*\)\s*\|\s*([^|]*?)\s*\|")
|
||||
W, LEFT, RIGHT = 880, 24, 856
|
||||
LABEL_ROW, CHAR_W = 17, 7.0
|
||||
FIRST_COMMIT = datetime.date(2013, 7, 4) # "- initial commit" of the repository
|
||||
|
||||
|
||||
def parse(markdown):
|
||||
@@ -46,7 +47,7 @@ def name(version):
|
||||
|
||||
|
||||
def draw(releases):
|
||||
first, last = releases[0][1], releases[-1][1]
|
||||
first, last = FIRST_COMMIT, releases[-1][1]
|
||||
start, end = datetime.date(first.year, 1, 1), datetime.date(last.year + 1, 1, 1)
|
||||
span = (end - start).days
|
||||
|
||||
@@ -55,10 +56,10 @@ def draw(releases):
|
||||
|
||||
# minor labels, placed greedily into the lowest free row above the axis
|
||||
rows_end, labels = [], []
|
||||
for version, date in releases:
|
||||
if version[2] != 0:
|
||||
for version, date in [(None, FIRST_COMMIT)] + releases:
|
||||
if version is not None and version[2] != 0:
|
||||
continue
|
||||
text = "%d.%d" % version[:2]
|
||||
text = "first commit" if version is None else "%d.%d" % version[:2]
|
||||
x, half = xof(date), len(text) * CHAR_W / 2 + 2
|
||||
row = next((i for i, e in enumerate(rows_end) if e < x - half), None)
|
||||
if row is None:
|
||||
@@ -73,10 +74,11 @@ def draw(releases):
|
||||
s = ['<svg class="nj-fig nj-fig--timeline" viewBox="0 0 %d %d" role="img" aria-labelledby="nj-int-tl-title" '
|
||||
'xmlns="http://www.w3.org/2000/svg">' % (W, height)]
|
||||
minors = sum(1 for v, _ in releases if v[2] == 0)
|
||||
s.append('<title id="nj-int-tl-title">Timeline of the %d releases from %s (%s) to %s (%s): %d minor or major '
|
||||
'releases, drawn as filled dots with their version above the axis, and %d patch releases, drawn as '
|
||||
'rings.</title>' % (len(releases), name(releases[0][0]), first.isoformat(), name(releases[-1][0]),
|
||||
last.isoformat(), minors, len(releases) - minors))
|
||||
s.append('<title id="nj-int-tl-title">Timeline from the first commit (%s) and the %d releases from %s (%s) to %s '
|
||||
'(%s): %d minor or major releases, drawn as filled dots with their version above the axis, and %d patch '
|
||||
'releases, drawn as rings. The first commit is drawn as a diamond.</title>'
|
||||
% (first.isoformat(), len(releases), name(releases[0][0]), releases[0][1].isoformat(),
|
||||
name(releases[-1][0]), last.isoformat(), minors, len(releases) - minors))
|
||||
# year grid
|
||||
for year in range(start.year, end.year + 1):
|
||||
x = xof(datetime.date(year, 1, 1))
|
||||
@@ -100,7 +102,11 @@ def draw(releases):
|
||||
y = top - row * LABEL_ROW
|
||||
s.append('<line class="nj-int-leader" x1="%.1f" y1="%d" x2="%.1f" y2="%d"/>' % (x, y + 3, x, axis - 7))
|
||||
s.append('<text class="nj-int-label" x="%.1f" y="%d">%s</text>' % (x, y, text))
|
||||
# markers: one per date, patch rings first so that minor dots stay on top
|
||||
# markers: the first commit, then one per date, patch rings first so that minor dots stay on top
|
||||
x = xof(FIRST_COMMIT)
|
||||
s.append('<g><title>First commit %s</title><circle class="nj-int-hit" cx="%.1f" cy="%d" r="9"/>'
|
||||
'<path class="nj-int-minor" d="M%.1f %d l7 -7 l7 7 l-7 7z" transform="translate(-7 0)"/></g>'
|
||||
% (FIRST_COMMIT.isoformat(), x, axis, x, axis))
|
||||
by_date = {}
|
||||
for version, date in releases:
|
||||
by_date.setdefault(date, []).append(version)
|
||||
|
||||
Reference in new issue
Block a user