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:
Niels Lohmann committed 2026-10-26 21:15:53 +01:00
1 parent c586beb22c
commit 7f591adb55
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
+2 -2
View File
@@ -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
+1 -1
View File
@@ -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
+1 -1
View File
@@ -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
+1 -1
View File
@@ -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
+1 -1
View File
@@ -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
+1 -1
View File
@@ -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
+1 -1
View File
@@ -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
+1 -1
View File
@@ -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
+1 -1
View File
@@ -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.
+1 -1
View File
@@ -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
+1 -1
View File
@@ -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
+1 -1
View File
@@ -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
+1 -1
View File
@@ -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
+1 -1
View File
@@ -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
+1 -1
View File
@@ -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
+1 -1
View File
@@ -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
+16 -16
View File
@@ -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.
+5 -5
View File
@@ -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
+1 -1
View File
@@ -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
+5 -5
View File
@@ -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
+1 -1
View File
@@ -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
+3 -3
View File
@@ -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
+11 -11
View File
@@ -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
+2 -2
View File
@@ -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
+1 -1
View File
@@ -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.
+2 -2
View File
@@ -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"
+1 -1
View File
@@ -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
+1 -1
View File
@@ -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
+21
View File
@@ -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 ---- */
+4 -4
View File
@@ -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)
+1 -1
View File
@@ -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).
+4 -4
View File
@@ -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};
+5 -1
View File
@@ -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.
+32 -32
View File
@@ -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>
+49 -6
View File
@@ -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>
+1 -1
View File
@@ -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`.
+18 -18
View File
@@ -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`
+1 -1
View File
@@ -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
+19 -19
View File
@@ -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
+3 -3
View File
@@ -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
+46 -44
View File
@@ -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.
+20 -7
View File
@@ -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!
+115 -108
View File
@@ -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

+2 -2
View File
@@ -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)
+32
View File
@@ -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);
}
})();
+1
View File
@@ -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
+1
View File
@@ -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">
+16 -10
View File
@@ -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)