From 7e577fb2d4d437e1680ff7871b281ecf01497a8c Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Tue, 29 Sep 2026 00:40:49 +0200 Subject: [PATCH] Document editable json_documents - API pages for set and push_back of basic_json_document and for the editable aliases; the class overviews name the Editable parameter - type_error.319 on the exceptions page - the feature page explains editing, and the examples show when it helps: a configuration file changed without reformatting it Signed-off-by: Niels Lohmann --- docs/docset/docSet.sql | 6 + .../docs/api/basic_json_document/index.md | 52 ++++- .../docs/api/basic_json_document/push_back.md | 100 +++++++++ .../docs/api/basic_json_document/set.md | 192 ++++++++++++++++++ docs/mkdocs/docs/api/basic_json_view/index.md | 16 +- .../mkdocs/docs/api/json_editable_document.md | 43 ++++ docs/mkdocs/docs/api/json_editable_view.md | 41 ++++ .../api/ordered_json_editable_document.md | 47 +++++ .../docs/api/ordered_json_editable_view.md | 40 ++++ .../basic_json_document__push_back.cpp | 24 +++ .../basic_json_document__push_back.output | 23 +++ .../examples/basic_json_document__set.cpp | 41 ++++ .../examples/basic_json_document__set.output | 25 +++ .../docs/examples/json_editable_document.cpp | 30 +++ .../examples/json_editable_document.output | 4 + .../ordered_json_editable_document.cpp | 15 ++ .../ordered_json_editable_document.output | 1 + docs/mkdocs/docs/features/index.md | 1 + docs/mkdocs/docs/features/json_view.md | 70 ++++++- docs/mkdocs/docs/home/exceptions.md | 28 ++- docs/mkdocs/mkdocs.yml | 6 + 21 files changed, 792 insertions(+), 13 deletions(-) create mode 100644 docs/mkdocs/docs/api/basic_json_document/push_back.md create mode 100644 docs/mkdocs/docs/api/basic_json_document/set.md create mode 100644 docs/mkdocs/docs/api/json_editable_document.md create mode 100644 docs/mkdocs/docs/api/json_editable_view.md create mode 100644 docs/mkdocs/docs/api/ordered_json_editable_document.md create mode 100644 docs/mkdocs/docs/api/ordered_json_editable_view.md create mode 100644 docs/mkdocs/docs/examples/basic_json_document__push_back.cpp create mode 100644 docs/mkdocs/docs/examples/basic_json_document__push_back.output create mode 100644 docs/mkdocs/docs/examples/basic_json_document__set.cpp create mode 100644 docs/mkdocs/docs/examples/basic_json_document__set.output create mode 100644 docs/mkdocs/docs/examples/json_editable_document.cpp create mode 100644 docs/mkdocs/docs/examples/json_editable_document.output create mode 100644 docs/mkdocs/docs/examples/ordered_json_editable_document.cpp create mode 100644 docs/mkdocs/docs/examples/ordered_json_editable_document.output diff --git a/docs/docset/docSet.sql b/docs/docset/docSet.sql index f45936b27..ee2f3c95a 100644 --- a/docs/docset/docSet.sql +++ b/docs/docset/docSet.sql @@ -137,8 +137,10 @@ INSERT INTO searchIndex(name, type, path) VALUES ('basic_json_document::node_cou INSERT INTO searchIndex(name, type, path) VALUES ('basic_json_document::owns_source', 'Method', 'api/basic_json_document/owns_source/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('basic_json_document::parse', 'Function', 'api/basic_json_document/parse/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('basic_json_document::parse_copy', 'Function', 'api/basic_json_document/parse_copy/index.html'); +INSERT INTO searchIndex(name, type, path) VALUES ('basic_json_document::push_back', 'Method', 'api/basic_json_document/push_back/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('basic_json_document::read', 'Method', 'api/basic_json_document/read/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('basic_json_document::root', 'Method', 'api/basic_json_document/root/index.html'); +INSERT INTO searchIndex(name, type, path) VALUES ('basic_json_document::set', 'Method', 'api/basic_json_document/set/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('basic_json_document::shrink_to_fit', 'Method', 'api/basic_json_document/shrink_to_fit/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('basic_json_document::source', 'Method', 'api/basic_json_document/source/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('basic_json_view', 'Class', 'api/basic_json_view/index.html'); @@ -187,6 +189,8 @@ INSERT INTO searchIndex(name, type, path) VALUES ('basic_json_view::type_name', INSERT INTO searchIndex(name, type, path) VALUES ('basic_json_view::value', 'Method', 'api/basic_json_view/value/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('json', 'Class', 'api/json/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('json_document', 'Class', 'api/json_document/index.html'); +INSERT INTO searchIndex(name, type, path) VALUES ('json_editable_document', 'Class', 'api/json_editable_document/index.html'); +INSERT INTO searchIndex(name, type, path) VALUES ('json_editable_view', 'Class', 'api/json_editable_view/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('json_view', 'Class', 'api/json_view/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('json_pointer', 'Class', 'api/json_pointer/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('json_pointer::back', 'Method', 'api/json_pointer/back/index.html'); @@ -222,6 +226,8 @@ INSERT INTO searchIndex(name, type, path) VALUES ('operator<<', 'Operator', 'api INSERT INTO searchIndex(name, type, path) VALUES ('operator>>', 'Operator', 'api/operator_gtgt/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('ordered_json', 'Class', 'api/ordered_json/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('ordered_json_document', 'Class', 'api/ordered_json_document/index.html'); +INSERT INTO searchIndex(name, type, path) VALUES ('ordered_json_editable_document', 'Class', 'api/ordered_json_editable_document/index.html'); +INSERT INTO searchIndex(name, type, path) VALUES ('ordered_json_editable_view', 'Class', 'api/ordered_json_editable_view/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('ordered_json_view', 'Class', 'api/ordered_json_view/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('ordered_map', 'Class', 'api/ordered_map/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('std::hash', 'Class', 'api/basic_json/std_hash/index.html'); diff --git a/docs/mkdocs/docs/api/basic_json_document/index.md b/docs/mkdocs/docs/api/basic_json_document/index.md index 89564369a..a5ffbe73a 100644 --- a/docs/mkdocs/docs/api/basic_json_document/index.md +++ b/docs/mkdocs/docs/api/basic_json_document/index.md @@ -3,7 +3,7 @@ Defined in header `` ```cpp -template +template class basic_json_document; ``` @@ -19,6 +19,11 @@ it (a copy, or an rvalue `#!cpp std::string` that was moved in); see [`owns_sour is move-only: copying a document would either duplicate a potentially large index and text, or leave two documents claiming to borrow the same buffer, so it is disabled. +With `#!cpp Editable == true`, the document also offers [`set`](set.md) and [`push_back`](push_back.md) to change +values in place, see [Edits](#edits) below. The source text itself is never written; a read-only document +(`#!cpp Editable == false`, the default) does not carry any of the bookkeeping edits need, and calling `set` or +`push_back` on one fails to compile (`#!cpp static_assert`). + ## Template parameters `BasicJsonType` @@ -26,14 +31,22 @@ claiming to borrow the same buffer, so it is disabled. [`ordered_json`](../ordered_json.md). Only 64-bit `number_integer_t`/`number_unsigned_t` types are supported; this is checked with a `static_assert`. +`Editable` +: whether the document supports [`set`](set.md) and [`push_back`](push_back.md) (optional, `#!cpp false` by + default). See [Edits](#edits) below. + ## Specializations -- [**json_document**](../json_document.md) - documents of the default specialization [`json`](../json.md) -- [**ordered_json_document**](../ordered_json_document.md) - documents of [`ordered_json`](../ordered_json.md) +- [**json_document**](../json_document.md) - read-only documents of the default specialization [`json`](../json.md) +- [**ordered_json_document**](../ordered_json_document.md) - read-only documents of + [`ordered_json`](../ordered_json.md) +- [**json_editable_document**](../json_editable_document.md) - editable documents of [`json`](../json.md) +- [**ordered_json_editable_document**](../ordered_json_editable_document.md) - editable documents of + [`ordered_json`](../ordered_json.md) ## Member types -- **view_type** - the type of view returned by [`root()`](root.md) (`#!cpp basic_json_view`) +- **view_type** - the type of view returned by [`root()`](root.md) (`#!cpp basic_json_view`) - **value_t** - the JSON type enumeration, see [`basic_json::value_t`](../basic_json/value_t.md) ## Member functions @@ -50,6 +63,37 @@ claiming to borrow the same buffer, so it is disabled. - [**node_count**](node_count.md) - the number of index entries (values plus object keys) - [**memory_usage**](memory_usage.md) - the number of bytes held by the document - [**shrink_to_fit**](shrink_to_fit.md) - release unused index capacity +- [**set**](set.md) - replace a value, or set an object member, an array element, or the value a JSON pointer refers + to (`#!cpp Editable` documents only) +- [**push_back**](push_back.md) - append to an array (`#!cpp Editable` documents only) + +## Edits + +An editable document (`#!cpp Editable == true`) can be changed after parsing, with [`set`](set.md) and +[`push_back`](push_back.md); [`json_editable_document`](../json_editable_document.md) and +[`ordered_json_editable_document`](../ordered_json_editable_document.md) are the corresponding specializations. A few +points apply to every edit: + +- **The source text is never written**, and the parsed index never moves: every value keeps the node it was parsed + into, so [views](../basic_json_view/index.md) taken before an edit stay valid, including + [`root()`](root.md). New values (and the element sequences of an edited array/object) go to storage owned by the + document, allocated on demand. +- **A view keeps referring to the same value.** After [`set`](set.md) replaces the value a view refers to, that view + sees the new value; a view of a value that a later edit replaces or drops keeps showing what it last held. An edit + of an array or object, however, **invalidates the iterators taken over it** (its members may now live in a + different sequence), and a string obtained with [`get_string()`](../basic_json_view/get_string.md) stays valid even + as further edits happen (earlier buffers of edited text are kept alive, not overwritten). +- **Values are accepted three ways:** a [`basic_json_view`](../basic_json_view/index.md) of *any* document + (read-only or editable; it is copied, nothing is shared with the source document), a `BasicJsonType` value, or + 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 + 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. + [`source_offset()`](../basic_json_view/source_offset.md) of a value introduced by an edit is + `#!cpp static_cast(-1)`, the same value it reports for a decoded string. ## Version history diff --git a/docs/mkdocs/docs/api/basic_json_document/push_back.md b/docs/mkdocs/docs/api/basic_json_document/push_back.md new file mode 100644 index 000000000..b50f6a347 --- /dev/null +++ b/docs/mkdocs/docs/api/basic_json_document/push_back.md @@ -0,0 +1,100 @@ +# nlohmann::basic_json_document::push_back + +```cpp +template +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 +source document afterward; a `BasicJsonType` value; or anything `BasicJsonType` can be constructed from (numbers, +strings, `#!cpp bool`, `#!cpp nullptr`, containers, ...). + +Only an **editable** document (`#!cpp Editable == true`, e.g. [`json_editable_document`](../json_editable_document.md)) +has `push_back`; calling it on a read-only `basic_json_document` fails to compile (`#!cpp static_assert`). + +## Template parameters + +`V` +: the type of `value`, deduced; see above for what is accepted. + +## Parameters + +`array` (in) +: the array (or null value) to append to + +`value` (in) +: the value to append + +## Return value + +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 +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 +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 +[`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 +[`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. + +## Complexity + +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 +[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 +`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. + +## Examples + +??? example + + The example below appends records to an array one at a time, as they might arrive from a stream of events, + without ever building a `BasicJsonType` value for the array or for the records already in it, and shows that a + view taken from an earlier `push_back` still refers to the same element once later ones have run. + + ```cpp + --8<-- "examples/basic_json_document__push_back.cpp" + ``` + + Output: + + ```json + --8<-- "examples/basic_json_document__push_back.output" + ``` + +## See also + +- [set](set.md) - replace a value, or set an object member, an array element, or the value a JSON pointer refers to +- [root](root.md) - the view of the root value +- [`BasicJsonType::push_back`](../basic_json/push_back.md) - the corresponding function of `basic_json` +- [Edits](index.md#edits) - what an edit guarantees, for every overload + +## Version history + +- Added in version 3.13.0. diff --git a/docs/mkdocs/docs/api/basic_json_document/set.md b/docs/mkdocs/docs/api/basic_json_document/set.md new file mode 100644 index 000000000..3741cf44a --- /dev/null +++ b/docs/mkdocs/docs/api/basic_json_document/set.md @@ -0,0 +1,192 @@ +# nlohmann::basic_json_document::set + +```cpp +// (1) +template +view_type set(view_type target, V&& value); + +// (2) +template +view_type set(view_type object, string_view_t key, V&& value); + +// (3) +template +view_type set(view_type array, I idx, V&& value); + +// (4) +template +view_type set(const json_pointer& ptr, V&& value); +``` + +Only an **editable** document (`#!cpp Editable == true`, e.g. [`json_editable_document`](../json_editable_document.md)) +has `set`; calling it on a read-only `basic_json_document` fails to compile (`#!cpp static_assert`). + +1. Replaces the value `target` refers to with `value`. +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) + `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()`). +4. Sets the value the JSON pointer `ptr` refers to, relative to [`root()`](root.md), to `value`. The *parent* of the + target must already exist: an object member is set as in 2. (added if it does not exist yet), an array element is + assigned as in 3., and a last reference token of `#!cpp "-"`, or equal to the size of the array, appends `value` + instead, exactly as [`push_back`](push_back.md) would. 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 +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, ...). + +## Template parameters + +`V` +: the type of `value`, deduced; see above for what is accepted. + +`I` +: an integral type other than `#!cpp bool`, deduced (overloads taking a `#!cpp bool` or a non-integral type for + `idx` do not participate in overload resolution). + +## Parameters + +`target` (in) +: the value to replace + +`object` (in) +: the object (or null value) whose member to set + +`array` (in) +: the array whose element to assign + +`key` (in) +: the key of the member to set + +`idx` (in) +: the index of the element to assign; a negative value throws (see [Exceptions](#exceptions)) + +`ptr` (in) +: a JSON pointer to the value to set, relative to `root()` + +`value` (in) +: the new value + +## Return value + +1. a view of `target`, now holding `value` +2. a view of the member `key` of `object`, now holding `value` +3. a view of the element `idx` of `array`, now holding `value` +4. a view of the value `ptr` refers to, now holding `value` + +## Exception safety + +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 +[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. + +## Exceptions + +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 + 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 + 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 + 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 + missing object member or an array index equal to the array's size at the very last reference token is not an + error there (it becomes a new member or an appended element) instead of + [`out_of_range.403`](../../home/exceptions.md#jsonexceptionout_of_range403)/[`out_of_range.402`](../../home/exceptions.md#jsonexceptionout_of_range402). + For the last reference token itself: if the parent is an object (or a primitive value, where it throws + `type_error.305`), throws what 2. throws; if the parent is an array, throws what 3. throws for an index that is + out of range, or, for a token that is not a valid array index, + [`parse_error.106`](../../home/exceptions.md#jsonexceptionparse_error106) (a leading `#!cpp '0'`), + [`parse_error.109`](../../home/exceptions.md#jsonexceptionparse_error109) (not a number), + [`out_of_range.410`](../../home/exceptions.md#jsonexceptionout_of_range410) (too large for `size_type`), or + [`out_of_range.404`](../../home/exceptions.md#jsonexceptionout_of_range404) (an empty token). 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 +[`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)). + +## Complexity + +1. Linear in the size of `value` (encoding it into the document's storage): constant for a scalar, linear in the + 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 number of elements of that parent, the *first* time -- see [Notes](#notes). +2. Linear in the number of members of `object`, to find an existing member with `key`, plus the complexity of 1. for + `value`. +3. Constant, plus the complexity of 1. for `value`. +4. 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 [`at`](../basic_json_view/at.md)), plus the complexity of 2. or 3. for + the last token. + +## Notes + +!!! 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 + [`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 + `operator[]`. + +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 +invalidated, since it was walking the old layout. See [Edits](index.md#edits) for what stays valid across an edit in +general. + +The same switch happens, for the same reason, when overload 1. replaces a multi-node array/object value with a +scalar: the *parent's* element sequence is what has to switch to links, not `target` itself, because the parent +originally stepped over `target`'s whole subtree by its node count, which no longer applies once `target` is a +one-node scalar. + +## Examples + +??? 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 + [`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. + + ```cpp + --8<-- "examples/basic_json_document__set.cpp" + ``` + + Output: + + ```json + --8<-- "examples/basic_json_document__set.output" + ``` + +## See also + +- [push_back](push_back.md) - append to an array +- [root](root.md) - the view of the root value, the starting point of overload 4 +- [`basic_json_view::dump`](../basic_json_view/dump.md) - serialize the document, keeping an untouched number's + spelling with `#!cpp number_format::source` +- [Edits](index.md#edits) - what an edit guarantees, for every overload +- [Editing a document](../../features/json_view.md#editing-a-document) - why editable documents keep the source + text's order and number spelling + +## Version history + +- Added in version 3.13.0. diff --git a/docs/mkdocs/docs/api/basic_json_view/index.md b/docs/mkdocs/docs/api/basic_json_view/index.md index 56760db2f..98f8ce9eb 100644 --- a/docs/mkdocs/docs/api/basic_json_view/index.md +++ b/docs/mkdocs/docs/api/basic_json_view/index.md @@ -3,7 +3,7 @@ Defined in header `` ```cpp -template +template class basic_json_view; ``` @@ -27,16 +27,30 @@ subtree on demand. [`operator[]`](operator%5B%5D.md), [`at`](at.md), [`contains` [`operator!=`](operator_ne.md) compare two views, or a view and a `BasicJsonType` value, without ever building a `BasicJsonType` value for a view; no ordering comparison (`#!cpp operator<`) is provided. +`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 +[Edits](../basic_json_document/index.md#edits). + ## Template parameters `BasicJsonType` : a specialization of [`basic_json`](../basic_json/index.md), matching the [`basic_json_document`](../basic_json_document/index.md) the view was taken from. +`Editable` +: whether the view is of an editable document, matching the [`basic_json_document`](../basic_json_document/index.md) + it was taken from (optional, `#!cpp false` by default). See [Edits](../basic_json_document/index.md#edits). + ## Specializations - [**json_view**](../json_view.md) - views of a [`json_document`](../json_document.md) - [**ordered_json_view**](../ordered_json_view.md) - views of an [`ordered_json_document`](../ordered_json_document.md) +- [**json_editable_view**](../json_editable_view.md) - views of a [`json_editable_document`](../json_editable_document.md) +- [**ordered_json_editable_view**](../ordered_json_editable_view.md) - views of an + [`ordered_json_editable_document`](../ordered_json_editable_document.md) ## Member types diff --git a/docs/mkdocs/docs/api/json_editable_document.md b/docs/mkdocs/docs/api/json_editable_document.md new file mode 100644 index 000000000..ab3fc3868 --- /dev/null +++ b/docs/mkdocs/docs/api/json_editable_document.md @@ -0,0 +1,43 @@ +# nlohmann::json_editable_document + +Defined in header `` + +```cpp +using json_editable_document = basic_json_document; +``` + +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 +[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 -- + 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. + + ```cpp + --8<-- "examples/json_editable_document.cpp" + ``` + + Output: + + ```json + --8<-- "examples/json_editable_document.output" + ``` + +## See also + +- [json_editable_view](json_editable_view.md) - a view of a value of a `json_editable_document` +- [json_document](json_document.md) - the read-only document this type adds edits to +- [ordered_json_editable_document](ordered_json_editable_document.md) - the corresponding editable document for + `ordered_json` +- [Edits](basic_json_document/index.md#edits) - what an edit guarantees + +## Version history + +Since version 3.13.0. diff --git a/docs/mkdocs/docs/api/json_editable_view.md b/docs/mkdocs/docs/api/json_editable_view.md new file mode 100644 index 000000000..f5fa59e57 --- /dev/null +++ b/docs/mkdocs/docs/api/json_editable_view.md @@ -0,0 +1,41 @@ +# nlohmann::json_editable_view + +Defined in header `` + +```cpp +using json_editable_view = basic_json_view; +``` + +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 +[`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). + +## Examples + +??? 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`. + + ```cpp + --8<-- "examples/json_editable_document.cpp" + ``` + + Output: + + ```json + --8<-- "examples/json_editable_document.output" + ``` + +## See also + +- [json_editable_document](json_editable_document.md) - the document type this view refers into +- [json_view](json_view.md) - the corresponding read-only view +- [ordered_json_editable_view](ordered_json_editable_view.md) - the corresponding view for + `ordered_json_editable_document` + +## Version history + +Since version 3.13.0. diff --git a/docs/mkdocs/docs/api/ordered_json_editable_document.md b/docs/mkdocs/docs/api/ordered_json_editable_document.md new file mode 100644 index 000000000..3127eea70 --- /dev/null +++ b/docs/mkdocs/docs/api/ordered_json_editable_document.md @@ -0,0 +1,47 @@ +# nlohmann::ordered_json_editable_document + +Defined in header `` + +```cpp +using ordered_json_editable_document = basic_json_document; +``` + +This type is an **editable** [`basic_json_document`](basic_json_document/index.md) of the +[`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 +[`json_editable_document`](json_editable_document.md) does. + +## Examples + +??? example + + The example below edits a document with `set`, then shows that `materialize()` keeps the member order of the + source text (with the new member at the end) for `ordered_json_editable_document`, where it would sort the + members alphabetically for [`json_editable_document`](json_editable_document.md). + + ```cpp + --8<-- "examples/ordered_json_editable_document.cpp" + ``` + + Output: + + ```json + --8<-- "examples/ordered_json_editable_document.output" + ``` + +## See also + +- [ordered_json_editable_view](ordered_json_editable_view.md) - a view of a value of an + `ordered_json_editable_document` +- [ordered_json_document](ordered_json_document.md) - the read-only document this type adds edits to +- [json_editable_document](json_editable_document.md) - the corresponding editable document for the default `json` + specialization +- [Object Order](../features/object_order.md) +- [Edits](basic_json_document/index.md#edits) - what an edit guarantees + +## Version history + +Since version 3.13.0. diff --git a/docs/mkdocs/docs/api/ordered_json_editable_view.md b/docs/mkdocs/docs/api/ordered_json_editable_view.md new file mode 100644 index 000000000..78351121e --- /dev/null +++ b/docs/mkdocs/docs/api/ordered_json_editable_view.md @@ -0,0 +1,40 @@ +# nlohmann::ordered_json_editable_view + +Defined in header `` + +```cpp +using ordered_json_editable_view = basic_json_view; +``` + +This type is a [`basic_json_view`](basic_json_view/index.md) of a value of an +[`ordered_json_editable_document`](ordered_json_editable_document.md), the corresponding view for +[`ordered_json_view`](ordered_json_view.md) the way [`json_editable_view`](json_editable_view.md) is for +[`json_view`](json_view.md). + +## Examples + +??? example + + The example below is the same as [`ordered_json_editable_document`'s](ordered_json_editable_document.md): the + views `set` returns see the document's member order preserved on `materialize()`, unlike for a + [`json_editable_document`](json_editable_document.md). + + ```cpp + --8<-- "examples/ordered_json_editable_document.cpp" + ``` + + Output: + + ```json + --8<-- "examples/ordered_json_editable_document.output" + ``` + +## See also + +- [ordered_json_editable_document](ordered_json_editable_document.md) - the document type this view refers into +- [ordered_json_view](ordered_json_view.md) - the corresponding read-only view +- [json_editable_view](json_editable_view.md) - the corresponding view for `json_editable_document` + +## Version history + +Since version 3.13.0. diff --git a/docs/mkdocs/docs/examples/basic_json_document__push_back.cpp b/docs/mkdocs/docs/examples/basic_json_document__push_back.cpp new file mode 100644 index 000000000..16385ea99 --- /dev/null +++ b/docs/mkdocs/docs/examples/basic_json_document__push_back.cpp @@ -0,0 +1,24 @@ +#include +#include + +using json = nlohmann::json; +using json_editable_document = nlohmann::json_editable_document; + +int main() +{ + // "events" starts out null -- the first push_back() turns it into an + // array, exactly like set() turns a null object member into an object + json_editable_document doc = json_editable_document::parse(R"({"source": "sensor-1", "events": null})"); + + const auto first = doc.push_back(doc.root()["events"], json{{"type", "start"}, {"t", 0}}); + for (int t = 1; t <= 3; ++t) + { + doc.push_back(doc.root()["events"], json{{"type", "tick"}, {"t", t}}); + } + + // push_back() never moves an existing element: a view taken from an + // earlier call still refers to the same element after later ones + std::cout << first.dump() << '\n'; + std::cout << doc.root()["events"].size() << '\n'; + std::cout << doc.root().dump(2) << '\n'; +} diff --git a/docs/mkdocs/docs/examples/basic_json_document__push_back.output b/docs/mkdocs/docs/examples/basic_json_document__push_back.output new file mode 100644 index 000000000..5a7307aa4 --- /dev/null +++ b/docs/mkdocs/docs/examples/basic_json_document__push_back.output @@ -0,0 +1,23 @@ +{"t":0,"type":"start"} +4 +{ + "source": "sensor-1", + "events": [ + { + "t": 0, + "type": "start" + }, + { + "t": 1, + "type": "tick" + }, + { + "t": 2, + "type": "tick" + }, + { + "t": 3, + "type": "tick" + } + ] +} diff --git a/docs/mkdocs/docs/examples/basic_json_document__set.cpp b/docs/mkdocs/docs/examples/basic_json_document__set.cpp new file mode 100644 index 000000000..7631a7b1b --- /dev/null +++ b/docs/mkdocs/docs/examples/basic_json_document__set.cpp @@ -0,0 +1,41 @@ +#include +#include + +using json = nlohmann::json; +using json_editable_document = nlohmann::json_editable_document; +using json_editable_view = nlohmann::json_editable_view; + +int main() +{ + // a configuration file, as it might be read from disk -- "price" is + // written with a trailing zero that has no effect on its value + const std::string text = R"({ + "name": "cache", + "host": "db1", + "port": 6379, + "price": 19.90, + "replicas": ["db2", "db3"], + "timeout": 30 +})"; + + json_editable_document doc = json_editable_document::parse(text); + + doc.set(doc.root()["port"], 6380); // (1) replace a value + doc.set(doc.root(), "region", "us-east"); // (2) add a member + doc.set(doc.root()["replicas"], 0, "db4"); // (3) assign an element + doc.set(json::json_pointer("/timeout"), 45); // (4) via a JSON pointer + + // members stay in document order (the new one at the end), and a number + // that was not itself edited keeps its exact spelling + std::cout << doc.root().dump(2, ' ', false, json_editable_view::number_format::source) << "\n\n"; + + // the same edits on a plain json value: object_t is a std::map, so + // parsing already sorted the keys, and dump() rewrites every number to + // its shortest form, even "price", which was never touched + json plain = json::parse(text); + plain["port"] = 6380; + plain["region"] = "us-east"; + plain["replicas"][0] = "db4"; + plain[json::json_pointer("/timeout")] = 45; + std::cout << plain.dump(2) << '\n'; +} diff --git a/docs/mkdocs/docs/examples/basic_json_document__set.output b/docs/mkdocs/docs/examples/basic_json_document__set.output new file mode 100644 index 000000000..74392692e --- /dev/null +++ b/docs/mkdocs/docs/examples/basic_json_document__set.output @@ -0,0 +1,25 @@ +{ + "name": "cache", + "host": "db1", + "port": 6380, + "price": 19.90, + "replicas": [ + "db4", + "db3" + ], + "timeout": 45, + "region": "us-east" +} + +{ + "host": "db1", + "name": "cache", + "port": 6380, + "price": 19.9, + "region": "us-east", + "replicas": [ + "db4", + "db3" + ], + "timeout": 45 +} diff --git a/docs/mkdocs/docs/examples/json_editable_document.cpp b/docs/mkdocs/docs/examples/json_editable_document.cpp new file mode 100644 index 000000000..bf08c0d9b --- /dev/null +++ b/docs/mkdocs/docs/examples/json_editable_document.cpp @@ -0,0 +1,30 @@ +#include +#include + +using json = nlohmann::json; +using json_editable_document = nlohmann::json_editable_document; +using json_editable_view = nlohmann::json_editable_view; + +int main() +{ + // a configuration file, as it might be read from disk + const std::string text = R"({"name": "cache", "host": "db1", "port": 6379, "price": 19.90})"; + std::cout << text << "\n\n"; + + // patch two fields -- "price" is never touched + json_editable_document doc = json_editable_document::parse(text); + doc.set(doc.root(), "host", "db2"); + doc.set(doc.root(), "retries", 3); + + // member order (the new member at the end) and the untouched number's + // exact spelling survive + std::cout << doc.root().dump(-1, ' ', false, json_editable_view::number_format::source) << '\n'; + + // the same patch on a plain json value: keys are sorted (object_t is a + // std::map), and "price" is rewritten even though the patch never + // touched it + json plain = json::parse(text); + plain["host"] = "db2"; + plain["retries"] = 3; + std::cout << plain.dump() << '\n'; +} diff --git a/docs/mkdocs/docs/examples/json_editable_document.output b/docs/mkdocs/docs/examples/json_editable_document.output new file mode 100644 index 000000000..c949e3828 --- /dev/null +++ b/docs/mkdocs/docs/examples/json_editable_document.output @@ -0,0 +1,4 @@ +{"name": "cache", "host": "db1", "port": 6379, "price": 19.90} + +{"name":"cache","host":"db2","port":6379,"price":19.90,"retries":3} +{"host":"db2","name":"cache","port":6379,"price":19.9,"retries":3} diff --git a/docs/mkdocs/docs/examples/ordered_json_editable_document.cpp b/docs/mkdocs/docs/examples/ordered_json_editable_document.cpp new file mode 100644 index 000000000..c6e7fa08e --- /dev/null +++ b/docs/mkdocs/docs/examples/ordered_json_editable_document.cpp @@ -0,0 +1,15 @@ +#include +#include + +using ordered_json_editable_document = nlohmann::ordered_json_editable_document; + +int main() +{ + // ordered_json_editable_document is basic_json_document + ordered_json_editable_document doc = ordered_json_editable_document::parse(R"({"z": 1, "a": 2, "m": 3})"); + doc.set(doc.root(), "b", 4); // set() always appends a new member at the end + + // materialize() preserves the document order (with "b" at the end), + // instead of sorting the keys the way json_editable_document does + std::cout << doc.root().materialize().dump() << '\n'; +} diff --git a/docs/mkdocs/docs/examples/ordered_json_editable_document.output b/docs/mkdocs/docs/examples/ordered_json_editable_document.output new file mode 100644 index 000000000..a845dbaff --- /dev/null +++ b/docs/mkdocs/docs/examples/ordered_json_editable_document.output @@ -0,0 +1 @@ +{"z":1,"a":2,"m":3,"b":4} diff --git a/docs/mkdocs/docs/features/index.md b/docs/mkdocs/docs/features/index.md index 246e47aee..e17d0dabe 100644 --- a/docs/mkdocs/docs/features/index.md +++ b/docs/mkdocs/docs/features/index.md @@ -13,6 +13,7 @@ C++ types, and finally serialize it again. [SAX interface](parsing/sax_interface.md), and [error handling](parsing/parse_exceptions.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. + [Editable documents](json_view.md#editing-a-document) can also be modified. - [Comments](comments.md) and [trailing commas](trailing_commas.md) — opt-in relaxations of the JSON grammar. ## Accessing and modifying values diff --git a/docs/mkdocs/docs/features/json_view.md b/docs/mkdocs/docs/features/json_view.md index 8030fe115..f863549fa 100644 --- a/docs/mkdocs/docs/features/json_view.md +++ b/docs/mkdocs/docs/features/json_view.md @@ -187,14 +187,72 @@ 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 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`](../api/basic_json_document/index.md) -- more conveniently +spelled [`json_editable_document`](../api/json_editable_document.md) or +[`ordered_json_editable_document`](../api/ordered_json_editable_document.md) -- also lets you +[`set`](../api/basic_json_document/set.md) a value and [`push_back`](../api/basic_json_document/push_back.md) onto +an array, 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 +none of the bookkeeping edits need, and calling `set`/`push_back` on one is a compile error, not a runtime one. + +### Why: editing without reformatting + +The `#!cpp 19.90` price from [above](#writing-a-view-back) is exactly the kind of value that makes editing a `json` +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 + 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. + +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 +inserted -- 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. + +??? example "Example: patch a configuration, keeping member order and number spellings" + + ```cpp + --8<-- "examples/json_editable_document.cpp" + ``` + + Output: + + ```json + --8<-- "examples/json_editable_document.output" + ``` + +### 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 +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 one of its elements is set or +appended to, 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 -- 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 +edits. See [`basic_json_document`'s Edits](../api/basic_json_document/index.md#edits) for the details, and +[`set`'s Exception safety](../api/basic_json_document/set.md#exception-safety) for what an edit guarantees if it +throws (the *basic* guarantee, not the strong one `dump()` and the read-only functions provide). + ## Choosing between `json`, `ordered_json`, the SAX interface, and `json_view` -| | [`json`](../api/json.md) / [`ordered_json`](../api/ordered_json.md) | [SAX interface](parsing/sax_interface.md) | [`json_document`](../api/json_document.md) / [`json_view`](../api/json_view.md) | -|---|---|---|---| -| **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 | -| **Mutability** | freely mutable | not applicable (a one-shot event stream) | read-only | -| **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 | -| **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 | +| | [`json`](../api/json.md) / [`ordered_json`](../api/ordered_json.md) | [SAX interface](parsing/sax_interface.md) | [`json_document`](../api/json_document.md) / [`json_view`](../api/json_view.md) | [`json_editable_document`](../api/json_editable_document.md) / [`json_editable_view`](../api/json_editable_view.md) | +|---|---|---|---|---| +| **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) 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 | ## Version history diff --git a/docs/mkdocs/docs/home/exceptions.md b/docs/mkdocs/docs/home/exceptions.md index d3c01a681..5ba54acfc 100644 --- a/docs/mkdocs/docs/home/exceptions.md +++ b/docs/mkdocs/docs/home/exceptions.md @@ -782,6 +782,24 @@ The dynamic type of the object cannot be represented in the requested serializat Encapsulate the JSON value in an object. That is, instead of serializing `#!json true`, serialize `#!json {"value": true}` +### json.exception.type_error.319 + +[`basic_json_document::set`](../api/basic_json_document/set.md) and +[`basic_json_document::push_back`](../api/basic_json_document/push_back.md) can store any `basic_json` value except +a binary one: a `json_document` has no representation for [binary values](../features/binary_values.md), which only +ever arise from parsing a binary format or from an explicit [`json::binary`](../api/basic_json/binary.md) value, not +from JSON text. + +!!! failure "Example message" + + ``` + [json.exception.type_error.319] cannot store a binary value in a json_document + ``` + +!!! note + + This exception was added in version 3.13.0, together with editable [`json_document`s](../features/json_view.md). + ## Out of range This exception is thrown in case a library function is called on an input parameter that exceeds the expected range, for instance, in the case of array indices or nonexisting object keys. @@ -1006,13 +1024,19 @@ MessagePack's ext type and BSON's binary subtype are each stored in a single byt [`basic_json_document::parse()`](../api/basic_json_document/parse.md) and the other parsing functions of [`basic_json_document`](../api/basic_json_document/index.md) index a value's position in the source text in 32 bits, -so they do not support an input of 4 GiB or more. +so they do not support an input of 4 GiB or more. The same 32-bit limit applies to an **editable** document's own +storage: [`set`](../api/basic_json_document/set.md) and [`push_back`](../api/basic_json_document/push_back.md) throw +this exception once the strings and number tokens written by edits reach 4 GiB in total, or once more than +4294967295 arrays/objects have had an element set or appended to them. -!!! failure "Example message" +!!! failure "Example messages" ``` [json.exception.out_of_range.416] input of 4 GiB or more is not supported by json_document ``` + ``` + [json.exception.out_of_range.416] edits of 4 GiB or more are not supported by json_document + ``` !!! note diff --git a/docs/mkdocs/mkdocs.yml b/docs/mkdocs/mkdocs.yml index d47429af1..58c3abf36 100644 --- a/docs/mkdocs/mkdocs.yml +++ b/docs/mkdocs/mkdocs.yml @@ -239,8 +239,10 @@ nav: - 'owns_source': api/basic_json_document/owns_source.md - 'parse': api/basic_json_document/parse.md - 'parse_copy': api/basic_json_document/parse_copy.md + - 'push_back': api/basic_json_document/push_back.md - 'read': api/basic_json_document/read.md - 'root': api/basic_json_document/root.md + - 'set': api/basic_json_document/set.md - 'shrink_to_fit': api/basic_json_document/shrink_to_fit.md - 'source': api/basic_json_document/source.md - basic_json_view: @@ -301,6 +303,8 @@ nav: - 'to_json': api/adl_serializer/to_json.md - 'json': api/json.md - 'json_document': api/json_document.md + - 'json_editable_document': api/json_editable_document.md + - 'json_editable_view': api/json_editable_view.md - json_pointer: - 'Overview': api/json_pointer/index.md - '(Constructor)': api/json_pointer/json_pointer.md @@ -341,6 +345,8 @@ nav: - 'operator""_json_pointer': api/operator_literal_json_pointer.md - 'ordered_json': api/ordered_json.md - 'ordered_json_document': api/ordered_json_document.md + - 'ordered_json_editable_document': api/ordered_json_editable_document.md + - 'ordered_json_editable_view': api/ordered_json_editable_view.md - 'ordered_json_view': api/ordered_json_view.md - 'ordered_map': api/ordered_map.md - macros: