mirror of
https://github.com/nlohmann/json.git
synced 2026-10-17 11:38:14 +00:00
Apply the review's wording fixes to the json_view documentation
- Copying is disabled because of its cost, not because of two documents borrowing the same buffer; the unique_ptr follows from move-only. - Inputs: streams, FILE*, and wide characters (strings, arrays, pointers) are all supported and owned; point to parse_copy() for owned copies. - The error replay only runs for failing input, builds no values, and is skipped with allow_exceptions = false. - read() writes copied inputs into the previous owned copy. - Views can dangle like std::string_view, and why there is no shared/weak pointer design. - The 4 GiB limit (16-byte nodes, 16-byte scanner steps), streams being read to the end first, which macros apply, why materialize() has no source positions, and wording nits (accept() vs basic_json::accept(), is_binary, is_discarded, see-also lists, size table, "back into"). Signed-off-by: Niels Lohmann <mail@nlohmann.me>
This commit is contained in:
15 files changed
+84
-55
No files matched your search
@@ -12,6 +12,11 @@ Checks whether the input is valid JSON, accepting and rejecting exactly what
|
|||||||
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.
|
is returned.
|
||||||
|
|
||||||
|
The result is the same as that of `BasicJsonType::accept()` by design; the difference is how the check is made. This
|
||||||
|
function runs the document's index builder (and discards the index), while `BasicJsonType::accept()` runs the SAX
|
||||||
|
parser with a handler that ignores every event. Use this one if you go on to parse the same input with
|
||||||
|
[`parse()`](parse.md) anyway, so that both use the same code; either is fine for a plain yes/no answer.
|
||||||
|
|
||||||
## Template parameters
|
## Template parameters
|
||||||
|
|
||||||
`InputType`
|
`InputType`
|
||||||
|
|||||||
@@ -16,8 +16,8 @@ basic_json_document(const basic_json_document&) = delete;
|
|||||||
2. Move constructor. Takes over `other`'s index and, if owned, its text; `other` is left as an empty document. Views
|
2. Move constructor. Takes over `other`'s index and, if owned, its text; `other` is left as an empty document. Views
|
||||||
taken from `other` before the move remain valid, because the index is heap-allocated independently of the
|
taken from `other` before the move remain valid, because the index is heap-allocated independently of the
|
||||||
`basic_json_document` object.
|
`basic_json_document` object.
|
||||||
3. `basic_json_document` is move-only. Copying is disabled because it would either duplicate a potentially large index
|
3. `basic_json_document` is move-only. Copying is disabled because of its cost: a copy would duplicate the whole
|
||||||
and text, or leave two documents claiming to borrow the same buffer.
|
index, the decoded-string buffer, and the owned text, while a move is enough in every use we know of.
|
||||||
|
|
||||||
## Parameters
|
## Parameters
|
||||||
|
|
||||||
@@ -30,7 +30,7 @@ No-throw guarantee: the default and move constructors never throw exceptions.
|
|||||||
|
|
||||||
## Complexity
|
## Complexity
|
||||||
|
|
||||||
Constant, for the default and move constructors.
|
Constant.
|
||||||
|
|
||||||
## Examples
|
## Examples
|
||||||
|
|
||||||
|
|||||||
@@ -11,13 +11,14 @@ A parsed JSON text, held as a flat index of its values
|
|||||||
([16 bytes per value](../../home/architecture.md#node-index-of-json-views)) instead of a tree of `BasicJsonType` values.
|
([16 bytes per value](../../home/architecture.md#node-index-of-json-views)) instead of a tree of `BasicJsonType` values.
|
||||||
Strings and numbers stay in the source text; only strings that contain escapes are decoded, into one buffer owned by
|
Strings and numbers stay in the source text; only strings that contain escapes are decoded, into one buffer owned by
|
||||||
the document. [`basic_json_view`](../basic_json_view/index.md) is a read-only handle to one value of a
|
the document. [`basic_json_view`](../basic_json_view/index.md) is a read-only handle to one value of a
|
||||||
`basic_json_document`; [`materialize()`](../basic_json_view/materialize.md) turns a subtree back into the
|
`basic_json_document`; [`materialize()`](../basic_json_view/materialize.md) turns a subtree into the
|
||||||
`BasicJsonType` value that [`BasicJsonType::parse()`](../basic_json/parse.md) would have produced for it.
|
`BasicJsonType` value that [`BasicJsonType::parse()`](../basic_json/parse.md) would have produced for it.
|
||||||
|
|
||||||
A document may **borrow** the text it was parsed from (the caller's buffer must then outlive the document) or **own**
|
A document may **borrow** the text it was parsed from (the caller's buffer must then outlive the document) or **own**
|
||||||
it (a copy, or an rvalue `#!cpp std::string` that was moved in); see [`owns_source`](owns_source.md). `basic_json_document`
|
it (a copy, or an rvalue `#!cpp std::string` that was moved in); see [`owns_source`](owns_source.md). `basic_json_document`
|
||||||
is move-only: copying a document would either duplicate a potentially large index and text, or leave two documents
|
is move-only: a copy would duplicate the whole index, the decoded-string buffer, and the owned text, and a move is
|
||||||
claiming to borrow the same buffer, so it is disabled.
|
enough in every use we know of. The index, the decoded strings, and the owned text live in one heap block that the
|
||||||
|
document holds through a `#!cpp std::unique_ptr`; this is also why views survive a move of the document.
|
||||||
|
|
||||||
## Template parameters
|
## Template parameters
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
bool owns_source() const noexcept;
|
bool owns_source() const noexcept;
|
||||||
```
|
```
|
||||||
|
|
||||||
Returns whether the document holds its own copy of the parsed text, as opposed to borrowing the caller's buffer.
|
Returns whether the document holds its own copy of the parsed text or is borrowing the caller's buffer.
|
||||||
|
|
||||||
## Return value
|
## Return value
|
||||||
|
|
||||||
|
|||||||
@@ -21,13 +21,15 @@ static basic_json_document parse(IteratorType first, IteratorType last,
|
|||||||
|
|
||||||
Both overloads accept the same JSON text as [`BasicJsonType::parse()`](../basic_json/parse.md), with the same
|
Both overloads accept the same JSON text as [`BasicJsonType::parse()`](../basic_json/parse.md), with the same
|
||||||
`ignore_comments`/`ignore_trailing_commas` options, but build a [`basic_json_document`](index.md) (a flat index into
|
`ignore_comments`/`ignore_trailing_commas` options, but build a [`basic_json_document`](index.md) (a flat index into
|
||||||
the input) instead of a tree of `BasicJsonType` values. The input must be byte-oriented (see the template parameters
|
the input) instead of a tree of `BasicJsonType` values. They take the same inputs as `BasicJsonType::parse()`. Byte
|
||||||
below): not every input type of `BasicJsonType::parse()` is supported.
|
inputs that stay alive can be borrowed; all others (streams, `#!cpp FILE*`, wide characters, 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.
|
||||||
|
|
||||||
## Template parameters
|
## Template parameters
|
||||||
|
|
||||||
`InputType`
|
`InputType`
|
||||||
: A byte-oriented input, one of:
|
: A compatible input, for instance:
|
||||||
|
|
||||||
- a `#!cpp std::string`, `#!cpp std::string_view`, or a C-style array of single-byte characters
|
- a `#!cpp std::string`, `#!cpp std::string_view`, or a C-style array of single-byte characters
|
||||||
- a pointer to a null-terminated string of single-byte characters (`#!cpp char`, `#!cpp signed char`,
|
- a pointer to a null-terminated string of single-byte characters (`#!cpp char`, `#!cpp signed char`,
|
||||||
@@ -35,12 +37,10 @@ below): not every input type of `BasicJsonType::parse()` is supported.
|
|||||||
- a container for which `#!cpp obj.data()` and `#!cpp obj.size()` give contiguous single-byte access, e.g.
|
- a container for which `#!cpp obj.data()` and `#!cpp obj.size()` give contiguous single-byte access, e.g.
|
||||||
`#!cpp std::vector<char>` or `#!cpp std::vector<std::uint8_t>`
|
`#!cpp std::vector<char>` or `#!cpp std::vector<std::uint8_t>`
|
||||||
- an `#!cpp std::istream` object
|
- an `#!cpp std::istream` object
|
||||||
- a wide string object (`#!cpp std::wstring`, `#!cpp std::u16string`, `#!cpp std::u32string`), which is converted
|
- a `#!cpp FILE*` pointer
|
||||||
to UTF-8
|
- wide characters (`#!cpp wchar_t`, `#!cpp char16_t`, `#!cpp char32_t`), which are converted to UTF-8: a wide
|
||||||
|
string object (`#!cpp std::wstring`, `#!cpp std::u16string`, `#!cpp std::u32string`), an array (e.g. a wide
|
||||||
Other inputs are not supported: a `#!cpp FILE*`, and pointers to or arrays of wide characters (`#!cpp wchar_t`,
|
string literal), or a pointer to a null-terminated wide string
|
||||||
`#!cpp char16_t`, `#!cpp char32_t`) are rejected at compile time by a `#!cpp static_assert`. (Use
|
|
||||||
[`BasicJsonType::parse()`](../basic_json/parse.md) for these.)
|
|
||||||
|
|
||||||
`IteratorType`
|
`IteratorType`
|
||||||
: an input iterator type, for instance a pair of pointers such as `ptr` and `ptr + len`, or a pair of
|
: an input iterator type, for instance a pair of pointers such as `ptr` and `ptr + len`, or a pair of
|
||||||
@@ -78,7 +78,9 @@ discarded; see [`is_discarded`](is_discarded.md).
|
|||||||
|
|
||||||
Throws the same exception [`BasicJsonType::parse()`](../basic_json/parse.md) throws for the same input and options --
|
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
|
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. Additionally throws
|
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
|
||||||
[`out_of_range.416`](../../home/exceptions.md#jsonexceptionout_of_range416) if the input is 4294967280 bytes (4 GiB
|
[`out_of_range.416`](../../home/exceptions.md#jsonexceptionout_of_range416) if the input is 4294967280 bytes (4 GiB
|
||||||
minus 16 bytes) or larger, a size [`BasicJsonType::parse()`](../basic_json/parse.md) does not reject.
|
minus 16 bytes) or larger, a size [`BasicJsonType::parse()`](../basic_json/parse.md) does not reject.
|
||||||
|
|
||||||
@@ -95,7 +97,7 @@ Linear in the length of the input.
|
|||||||
| 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 |
|
| 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 |
|
| other rvalue byte container (including a `#!cpp const` rvalue `#!cpp std::string`) | **owned**, copied |
|
||||||
| stream, wide string, or anything else read through the general input adapter | **owned**, read into a buffer (a stream is read to its end) |
|
| 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) |
|
||||||
|
|
||||||
For overload (2), a pair of pointers to single-byte integers (e.g. `#!cpp const char*`, `#!cpp std::uint8_t*`) is
|
For overload (2), a pair of pointers to single-byte integers (e.g. `#!cpp const char*`, `#!cpp std::uint8_t*`) is
|
||||||
borrowed. From C++20 on, so is any other contiguous iterator over single bytes, such as
|
borrowed. From C++20 on, so is any other contiguous iterator over single bytes, such as
|
||||||
|
|||||||
@@ -47,7 +47,9 @@ Every view taken from `#!cpp *this` before the call -- including the previous [`
|
|||||||
whether or not the new parse succeeds; take fresh views from [`root()`](root.md) afterward.
|
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
|
`input` is borrowed or owned by the same rules as [`parse()`](parse.md#notes); a document can borrow on one call and
|
||||||
own on the next, since ownership is decided freshly each time.
|
own on the next, since ownership is decided freshly each time. An input that is copied (see the table in
|
||||||
|
[`parse()`](parse.md#notes)) is written into the document's previous owned copy, reusing its memory; a moved-in
|
||||||
|
`#!cpp std::string` replaces it.
|
||||||
|
|
||||||
An integer argument that is not a `#!cpp bool` where the flags are expected, such as `#!cpp read(ptr, len)`, does not
|
An integer argument that is not a `#!cpp bool` where the flags are expected, such as `#!cpp read(ptr, len)`, does not
|
||||||
compile; see [`parse`](parse.md#notes).
|
compile; see [`parse`](parse.md#notes).
|
||||||
|
|||||||
@@ -39,7 +39,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
|
`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
|
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
|
[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.
|
[`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).
|
||||||
|
|
||||||
## Examples
|
## Examples
|
||||||
|
|
||||||
|
|||||||
@@ -38,7 +38,8 @@ Constant.
|
|||||||
## See also
|
## See also
|
||||||
|
|
||||||
- [is_structured](is_structured.md) - return whether the type is structured
|
- [is_structured](is_structured.md) - return whether the type is structured
|
||||||
- [size](size.md), [empty](empty.md) - the number of elements, and whether there are none
|
- [size](size.md) - the number of elements
|
||||||
|
- [empty](empty.md) - whether there are no elements
|
||||||
- [`BasicJsonType::is_array`](../basic_json/is_array.md) - the corresponding function of `basic_json`
|
- [`BasicJsonType::is_array`](../basic_json/is_array.md) - the corresponding function of `basic_json`
|
||||||
|
|
||||||
## Version history
|
## Version history
|
||||||
|
|||||||
@@ -4,8 +4,9 @@
|
|||||||
bool is_binary() const noexcept;
|
bool is_binary() const noexcept;
|
||||||
```
|
```
|
||||||
|
|
||||||
This function always returns `#!cpp false`: a JSON text has no binary values, so a view can never refer to one. The
|
This function always returns `#!cpp false`: a document is only ever parsed from JSON text, never from CBOR or the other
|
||||||
function exists for interface parity with [`BasicJsonType::is_binary`](../basic_json/is_binary.md).
|
binary formats, and a JSON text has no binary values, so a view can never refer to one. The function exists for
|
||||||
|
interface parity with [`BasicJsonType::is_binary`](../basic_json/is_binary.md).
|
||||||
|
|
||||||
## Return value
|
## Return value
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ that is itself [discarded](../basic_json_document/is_discarded.md) -- in particu
|
|||||||
|
|
||||||
## Return value
|
## Return value
|
||||||
|
|
||||||
`#!cpp true` if the view is discarded, `#!cpp false` otherwise.
|
`#!cpp true` if the view or its document is discarded, `#!cpp false` otherwise.
|
||||||
|
|
||||||
## Exception safety
|
## Exception safety
|
||||||
|
|
||||||
|
|||||||
@@ -38,7 +38,8 @@ Constant.
|
|||||||
## See also
|
## See also
|
||||||
|
|
||||||
- [is_structured](is_structured.md) - return whether the type is structured
|
- [is_structured](is_structured.md) - return whether the type is structured
|
||||||
- [size](size.md), [empty](empty.md) - the number of elements, and whether there are none
|
- [size](size.md) - the number of elements
|
||||||
|
- [empty](empty.md) - whether there are no elements
|
||||||
- [`BasicJsonType::is_object`](../basic_json/is_object.md) - the corresponding function of `basic_json`
|
- [`BasicJsonType::is_object`](../basic_json/is_object.md) - the corresponding function of `basic_json`
|
||||||
|
|
||||||
## Version history
|
## Version history
|
||||||
|
|||||||
@@ -37,7 +37,8 @@ Constant.
|
|||||||
|
|
||||||
## See also
|
## See also
|
||||||
|
|
||||||
- [source_offset](source_offset.md) - byte offset of this value in the document's source text
|
- [source_offset](source_offset.md) - byte offset of this value in the source text, which differs for strings: an
|
||||||
|
escaped string has none
|
||||||
- [`BasicJsonType::is_string`](../basic_json/is_string.md) - the corresponding function of `basic_json`
|
- [`BasicJsonType::is_string`](../basic_json/is_string.md) - the corresponding function of `basic_json`
|
||||||
|
|
||||||
## Version history
|
## Version history
|
||||||
|
|||||||
@@ -14,8 +14,8 @@ if the view is [discarded](is_discarded.md).
|
|||||||
|
|
||||||
## Exception safety
|
## Exception safety
|
||||||
|
|
||||||
Strong guarantee: if an exception is thrown, there are no changes to the view or the document it refers to (nothing
|
Strong guarantee: there are no changes to the view or the document it refers to (nothing about either is mutated by
|
||||||
about either is mutated by this function).
|
this function).
|
||||||
|
|
||||||
## Exceptions
|
## Exceptions
|
||||||
|
|
||||||
@@ -28,12 +28,13 @@ Linear in the size of the subtree.
|
|||||||
## Notes
|
## Notes
|
||||||
|
|
||||||
`materialize()` replays the subtree through the same SAX builder [`BasicJsonType::parse()`](../basic_json/parse.md)
|
`materialize()` replays the subtree through the same SAX builder [`BasicJsonType::parse()`](../basic_json/parse.md)
|
||||||
uses internally, 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
|
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.
|
would be; the JSON nesting depth is limited only by available memory, as for `BasicJsonType::parse()` itself.
|
||||||
|
|
||||||
Unlike parsing with [`JSON_DIAGNOSTIC_POSITIONS`](../macros/json_diagnostic_positions.md) enabled, the values
|
Unlike parsing with [`JSON_DIAGNOSTIC_POSITIONS`](../macros/json_diagnostic_positions.md) enabled, the values
|
||||||
produced by `materialize()` do not carry source positions: there is no lexer run during the replay to record them.
|
produced by `materialize()` do not carry source positions. The index has the start offset of every value, but not the
|
||||||
|
end of arrays, objects, and escaped strings, which the positions also need.
|
||||||
|
|
||||||
Calling `materialize()` on the same view repeatedly builds a new, independent `BasicJsonType` value each time; it
|
Calling `materialize()` on the same view repeatedly builds a new, independent `BasicJsonType` value each time; it
|
||||||
never caches the result.
|
never caches the result.
|
||||||
|
|||||||
@@ -10,15 +10,15 @@ Returns the number of elements, as [`BasicJsonType::size()`](../basic_json/size.
|
|||||||
|
|
||||||
The return value depends on the type and is defined as follows:
|
The return value depends on the type and is defined as follows:
|
||||||
|
|
||||||
| Value type | return value |
|
| Value type | return value |
|
||||||
|----------------------|-----------------------------|
|
|------------|---------------------------|
|
||||||
| null | `0` |
|
| null | `0` |
|
||||||
| discarded | `0` |
|
| discarded | `0` |
|
||||||
| boolean | `1` |
|
| boolean | `1` |
|
||||||
| string | `1` |
|
| string | `1` |
|
||||||
| number | `1` |
|
| number | `1` |
|
||||||
| object | number of key/value pairs |
|
| object | number of key/value pairs |
|
||||||
| array | number of elements |
|
| array | number of elements |
|
||||||
|
|
||||||
## Exception safety
|
## Exception safety
|
||||||
|
|
||||||
|
|||||||
@@ -16,8 +16,8 @@ most of the resulting tree is thrown away almost immediately.
|
|||||||
[`basic_json_document::parse()`](../api/basic_json_document/parse.md) parses the same JSON grammar, with the same
|
[`basic_json_document::parse()`](../api/basic_json_document/parse.md) parses the same JSON grammar, with the same
|
||||||
options, but instead of a tree it builds a flat index of the values it found: one
|
options, but instead of a tree it builds a flat index of the values it found: one
|
||||||
[16-byte entry](../home/architecture.md#node-index-of-json-views) per value (and one per object key), in document
|
[16-byte entry](../home/architecture.md#node-index-of-json-views) per value (and one per object key), in document
|
||||||
order. Strings and numbers are not copied out of the input; they stay in the source text, and are only decoded when
|
order. Strings and numbers are referenced in place in the source text; only strings that contain escape sequences
|
||||||
actually needed (for a string, only if it contains escape sequences, into one shared buffer owned by the document).
|
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
|
[`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 --
|
||||||
@@ -31,7 +31,8 @@ index. It gives you the read-only, type-inspection part of the `basic_json` inte
|
|||||||
|
|
||||||
Include `<nlohmann/json_view.hpp>` in addition to (or instead of) `<nlohmann/json.hpp>`. Parse into a
|
Include `<nlohmann/json_view.hpp>` in addition to (or instead of) `<nlohmann/json.hpp>`. Parse into a
|
||||||
[`json_document`](../api/json_document.md), inspect its [`root()`](../api/basic_json_document/root.md), and
|
[`json_document`](../api/json_document.md), inspect its [`root()`](../api/basic_json_document/root.md), and
|
||||||
`materialize()` when you need a real value:
|
`materialize()` when you need a real value. `materialize()` works on any view, not just the root, so you can turn just
|
||||||
|
the subtree you need into a value:
|
||||||
|
|
||||||
??? example "Example: parse a document, inspect its root, and materialize it"
|
??? example "Example: parse a document, inspect its root, and materialize it"
|
||||||
|
|
||||||
@@ -68,15 +69,19 @@ A view is valid only while all of the following hold:
|
|||||||
|
|
||||||
- the document is alive,
|
- the document is alive,
|
||||||
- the document has not been re-parsed since the view was taken (with [`read()`](../api/basic_json_document/read.md)
|
- the document has not been re-parsed since the view was taken (with [`read()`](../api/basic_json_document/read.md)
|
||||||
or [`parse()`](../api/basic_json_document/parse.md) into it), and has not had
|
or [`parse()`](../api/basic_json_document/parse.md) into it),
|
||||||
[`shrink_to_fit()`](../api/basic_json_document/shrink_to_fit.md) called on it since, and
|
- the document has not had [`shrink_to_fit()`](../api/basic_json_document/shrink_to_fit.md) called on it since, and
|
||||||
- if the document borrows its source text, that text is still alive.
|
- if the document borrows its source text, that text is still alive.
|
||||||
|
|
||||||
Moving the document itself is fine and does **not** invalidate its views: the index is a separate heap allocation
|
Moving the `basic_json_document<>` itself is fine and does **not** invalidate its views: the index is a separate heap
|
||||||
that keeps its address across the move. Take a fresh view from [`root()`](../api/basic_json_document/root.md)
|
allocation that keeps its address across the move. Take a fresh view from [`root()`](../api/basic_json_document/root.md)
|
||||||
whenever any of the other conditions above was not met.
|
whenever any of the other conditions above was not met.
|
||||||
|
|
||||||
Because a view dies with its document, [`root()`](../api/basic_json_document/root.md) is not callable on a temporary
|
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:
|
||||||
|
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.
|
document: `#!cpp auto v = json_document::parse(text).root();` does not compile. Give the document a name first.
|
||||||
|
|
||||||
??? example "Example: borrowed and owned documents, and when views become invalid"
|
??? example "Example: borrowed and owned documents, and when views become invalid"
|
||||||
@@ -98,14 +103,19 @@ document: `#!cpp auto v = json_document::parse(text).root();` does not compile.
|
|||||||
[`basic_json::accept()`](../api/basic_json/accept.md)/[`basic_json::parse()`](../api/basic_json/parse.md), with the
|
[`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.
|
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.
|
the library's own parser is run on the same bytes to produce the diagnostic. Valid input never pays for this, and
|
||||||
`#!cpp allow_exceptions == false` gives a [discarded](../api/basic_json_document/is_discarded.md) document instead
|
the replay builds no values: it costs about a lexing pass up to the error.
|
||||||
of throwing, just as it gives a discarded value for `#!cpp basic_json::parse()`.
|
`#!cpp allow_exceptions == false` skips the replay and gives a
|
||||||
|
[discarded](../api/basic_json_document/is_discarded.md) document instead of throwing, just as it gives a discarded
|
||||||
|
value for `#!cpp basic_json::parse()`.
|
||||||
- **Number classification.** An integer literal that does not fit into the 64-bit integer type becomes a
|
- **Number classification.** An integer literal that does not fit into the 64-bit integer type becomes a
|
||||||
floating-point value, exactly as it does for `#!cpp basic_json::parse()`.
|
floating-point value, exactly as it does for `#!cpp basic_json::parse()`.
|
||||||
- **Macros.** [`JSON_STRICT_NUL_HANDLING`](../api/macros/json_strict_nul_handling.md) and
|
- **Macros.** [`JSON_STRICT_NUL_HANDLING`](../api/macros/json_strict_nul_handling.md) and
|
||||||
[`JSON_NOEXCEPTION`](../api/macros/json_noexception.md)/[`JSON_THROW_USER`](../api/macros/json_throw_user.md)
|
[`JSON_NOEXCEPTION`](../api/macros/json_noexception.md)/[`JSON_THROW_USER`](../api/macros/json_throw_user.md)
|
||||||
behave the same way they do for `<nlohmann/json.hpp>`.
|
behave the same way they do for `<nlohmann/json.hpp>`. These are the macros that change what the parser accepts or
|
||||||
|
how it reports errors. The others either do not apply ([`JSON_DIAGNOSTICS`](../api/macros/json_diagnostics.md)
|
||||||
|
needs parent pointers in `basic_json` values) or only affect the values `materialize()` produces, through
|
||||||
|
`BasicJsonType`.
|
||||||
|
|
||||||
## What is different
|
## What is different
|
||||||
|
|
||||||
@@ -113,12 +123,15 @@ document: `#!cpp auto v = json_document::parse(text).root();` does not compile.
|
|||||||
`number_unsigned_t` to both be 64 bits wide; this is a compile-time `#!cpp static_assert`.
|
`number_unsigned_t` to both be 64 bits wide; this is a compile-time `#!cpp static_assert`.
|
||||||
- **A 4 GiB input limit.** An input of 4294967280 bytes (4 GiB minus 16 bytes) or more throws
|
- **A 4 GiB input limit.** An input of 4294967280 bytes (4 GiB minus 16 bytes) or more throws
|
||||||
[`out_of_range.416`](../home/exceptions.md#jsonexceptionout_of_range416), a limit
|
[`out_of_range.416`](../home/exceptions.md#jsonexceptionout_of_range416), a limit
|
||||||
`#!cpp basic_json::parse()` does not have.
|
`#!cpp basic_json::parse()` does not have. It keeps an index entry at 16 bytes: offsets and counts are 32 bits
|
||||||
- **A stream is always read to its end.** There is no partial/streaming read of an `#!cpp std::istream`.
|
wide. The limit is 16 bytes below 2^32, because the parser reads in 16-byte steps, and a position one step past the
|
||||||
|
end must still fit.
|
||||||
|
- **A stream is always read to its end.** There is no partial/streaming read of an `#!cpp std::istream`: the stream
|
||||||
|
is read to its end into a buffer the document owns, and parsing starts after that.
|
||||||
- **No source positions on `materialize()`.** Even with
|
- **No source positions on `materialize()`.** Even with
|
||||||
[`JSON_DIAGNOSTIC_POSITIONS`](../api/macros/json_diagnostic_positions.md) enabled,
|
[`JSON_DIAGNOSTIC_POSITIONS`](../api/macros/json_diagnostic_positions.md) enabled,
|
||||||
[`materialize()`](../api/basic_json_view/materialize.md) does not set them: there is no lexer run during the
|
[`materialize()`](../api/basic_json_view/materialize.md) does not set them. The index has the start offset of every
|
||||||
replay to record them.
|
value, but not the end of arrays, objects, and escaped strings, which the positions also need.
|
||||||
- **Element access, iteration, `get<T>()`, JSON Pointer, `dump()`, and comparison are not (yet) provided** by
|
- **Element access, iteration, `get<T>()`, JSON Pointer, `dump()`, and comparison are not (yet) provided** by
|
||||||
`basic_json_view`. For now, [`materialize()`](../api/basic_json_view/materialize.md) is the way to get a value you
|
`basic_json_view`. For now, [`materialize()`](../api/basic_json_view/materialize.md) is the way to get a value you
|
||||||
can do those things with.
|
can do those things with.
|
||||||
|
|||||||
Reference in new issue
Block a user