mirror of
https://github.com/nlohmann/json.git
synced 2026-09-29 19:20:30 +00:00
Compare commits
4
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
daad8ea9b5 | ||
|
|
5a9f59a688 | ||
|
|
f80a1a17a9 | ||
|
|
857953b39a |
@@ -70,6 +70,8 @@ cc_library(
|
||||
"include/nlohmann/detail/view/document_data.hpp",
|
||||
"include/nlohmann/detail/view/errors.hpp",
|
||||
"include/nlohmann/detail/view/input.hpp",
|
||||
"include/nlohmann/detail/view/iterator.hpp",
|
||||
"include/nlohmann/detail/view/lookup.hpp",
|
||||
"include/nlohmann/detail/view/macro_scope.hpp",
|
||||
"include/nlohmann/detail/view/macro_unscope.hpp",
|
||||
"include/nlohmann/detail/view/materialize.hpp",
|
||||
|
||||
@@ -143,7 +143,17 @@ INSERT INTO searchIndex(name, type, path) VALUES ('basic_json_document::shrink_t
|
||||
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');
|
||||
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json_view::basic_json_view', 'Constructor', 'api/basic_json_view/basic_json_view/index.html');
|
||||
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json_view::at', 'Method', 'api/basic_json_view/at/index.html');
|
||||
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json_view::back', 'Method', 'api/basic_json_view/back/index.html');
|
||||
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json_view::begin', 'Method', 'api/basic_json_view/begin/index.html');
|
||||
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json_view::cbegin', 'Method', 'api/basic_json_view/cbegin/index.html');
|
||||
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json_view::cend', 'Method', 'api/basic_json_view/cend/index.html');
|
||||
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json_view::contains', 'Method', 'api/basic_json_view/contains/index.html');
|
||||
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json_view::count', 'Method', 'api/basic_json_view/count/index.html');
|
||||
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json_view::empty', 'Method', 'api/basic_json_view/empty/index.html');
|
||||
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json_view::end', 'Method', 'api/basic_json_view/end/index.html');
|
||||
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json_view::find', 'Method', 'api/basic_json_view/find/index.html');
|
||||
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json_view::front', 'Method', 'api/basic_json_view/front/index.html');
|
||||
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json_view::is_array', 'Method', 'api/basic_json_view/is_array/index.html');
|
||||
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json_view::is_binary', 'Method', 'api/basic_json_view/is_binary/index.html');
|
||||
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json_view::is_boolean', 'Method', 'api/basic_json_view/is_boolean/index.html');
|
||||
@@ -157,11 +167,14 @@ INSERT INTO searchIndex(name, type, path) VALUES ('basic_json_view::is_object',
|
||||
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json_view::is_primitive', 'Method', 'api/basic_json_view/is_primitive/index.html');
|
||||
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json_view::is_string', 'Method', 'api/basic_json_view/is_string/index.html');
|
||||
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json_view::is_structured', 'Method', 'api/basic_json_view/is_structured/index.html');
|
||||
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json_view::items', 'Method', 'api/basic_json_view/items/index.html');
|
||||
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json_view::materialize', 'Method', 'api/basic_json_view/materialize/index.html');
|
||||
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json_view::operator bool', 'Method', 'api/basic_json_view/operator_bool/index.html');
|
||||
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json_view::operator[]', 'Operator', 'api/basic_json_view/operator[]/index.html');
|
||||
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json_view::size', 'Method', 'api/basic_json_view/size/index.html');
|
||||
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json_view::source_offset', 'Method', 'api/basic_json_view/source_offset/index.html');
|
||||
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json_view::type', 'Method', 'api/basic_json_view/type/index.html');
|
||||
INSERT INTO searchIndex(name, type, path) VALUES ('basic_json_view::type_name', 'Method', 'api/basic_json_view/type_name/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_view', 'Class', 'api/json_view/index.html');
|
||||
|
||||
@@ -219,6 +219,7 @@ Strong exception safety: if an exception occurs, the original value stays intact
|
||||
- documentation on [checked access](../../features/element_access/checked_access.md)
|
||||
- [`operator[]`](operator%5B%5D.md) for unchecked access by reference
|
||||
- [`value`](value.md) for access with default value
|
||||
- [basic_json_view::at](../basic_json_view/at.md) - the same access on a zero-copy view
|
||||
|
||||
## Version history
|
||||
|
||||
|
||||
@@ -58,6 +58,7 @@ Constant.
|
||||
## See also
|
||||
|
||||
- [front](front.md) to access the first element
|
||||
- [basic_json_view::back](../basic_json_view/back.md) - the same access on a zero-copy view
|
||||
|
||||
## Version history
|
||||
|
||||
|
||||
@@ -37,6 +37,12 @@ Constant.
|
||||
--8<-- "examples/begin.output"
|
||||
```
|
||||
|
||||
## See also
|
||||
|
||||
- [end](end.md) - returns an iterator to one past the last element
|
||||
- [basic_json_view::begin](../basic_json_view/begin.md) - the same iteration on a zero-copy view (in document order,
|
||||
not sorted by key)
|
||||
|
||||
## Version history
|
||||
|
||||
- Added in version 1.0.0.
|
||||
|
||||
@@ -36,6 +36,11 @@ Constant.
|
||||
--8<-- "examples/cbegin.output"
|
||||
```
|
||||
|
||||
## See also
|
||||
|
||||
- [cend](cend.md) - returns a const iterator to one past the last element
|
||||
- [basic_json_view::cbegin](../basic_json_view/cbegin.md) - the same iteration on a zero-copy view
|
||||
|
||||
## Version history
|
||||
|
||||
- Added in version 1.0.0.
|
||||
|
||||
@@ -36,6 +36,11 @@ Constant.
|
||||
--8<-- "examples/cend.output"
|
||||
```
|
||||
|
||||
## See also
|
||||
|
||||
- [cbegin](cbegin.md) - returns a const iterator to the first element
|
||||
- [basic_json_view::cend](../basic_json_view/cend.md) - the same iteration on a zero-copy view
|
||||
|
||||
## Version history
|
||||
|
||||
- Added in version 1.0.0.
|
||||
|
||||
@@ -111,6 +111,7 @@ Logarithmic in the size of the JSON object.
|
||||
|
||||
- [find](find.md) find a value in an object
|
||||
- [count](count.md) returns the number of occurrences of a key
|
||||
- [basic_json_view::contains](../basic_json_view/contains.md) - the same check on a zero-copy view
|
||||
|
||||
## Version history
|
||||
|
||||
|
||||
@@ -76,6 +76,7 @@ This method always returns `0` when executed on a JSON type that is not an objec
|
||||
|
||||
- [find](find.md) find a value in an object
|
||||
- [contains](contains.md) checks whether a key exists
|
||||
- [basic_json_view::count](../basic_json_view/count.md) - the same check on a zero-copy view
|
||||
|
||||
## Version history
|
||||
|
||||
|
||||
@@ -37,6 +37,11 @@ Constant.
|
||||
--8<-- "examples/end.output"
|
||||
```
|
||||
|
||||
## See also
|
||||
|
||||
- [begin](begin.md) - returns an iterator to the first element
|
||||
- [basic_json_view::end](../basic_json_view/end.md) - the same iteration on a zero-copy view
|
||||
|
||||
## Version history
|
||||
|
||||
- Added in version 1.0.0.
|
||||
|
||||
@@ -80,6 +80,7 @@ This method always returns `end()` when executed on a JSON type that is not an o
|
||||
|
||||
- [count](count.md) returns the number of occurrences of a key
|
||||
- [contains](contains.md) checks whether a key exists
|
||||
- [basic_json_view::find](../basic_json_view/find.md) - the same lookup on a zero-copy view
|
||||
|
||||
## Version history
|
||||
|
||||
|
||||
@@ -51,6 +51,7 @@ Constant.
|
||||
## See also
|
||||
|
||||
- [back](back.md) to access the last element
|
||||
- [basic_json_view::front](../basic_json_view/front.md) - the same access on a zero-copy view
|
||||
|
||||
## Version history
|
||||
|
||||
|
||||
@@ -99,6 +99,8 @@ When iterating over an array, `key()` will return the index of the element as st
|
||||
|
||||
- [begin](begin.md) returns an iterator to the first element
|
||||
- [end](end.md) returns an iterator to one past the last element
|
||||
- [basic_json_view::items](../basic_json_view/items.md) - the same range on a zero-copy view (`#!cpp const auto`,
|
||||
not `#!cpp const auto&`: items are produced on the fly)
|
||||
|
||||
## Version history
|
||||
|
||||
|
||||
@@ -254,6 +254,8 @@ Strong exception safety: if an exception occurs, the original value stays intact
|
||||
- documentation on [runtime assertions](../../features/assertions.md)
|
||||
- see [`at`](at.md) for access by reference with range checking
|
||||
- see [`value`](value.md) for access with default value
|
||||
- [basic_json_view::operator[]](../basic_json_view/operator%5B%5D.md) - the same access on a zero-copy view (always
|
||||
returns a discarded view instead of assuming undefined behavior)
|
||||
|
||||
## Version history
|
||||
|
||||
|
||||
@@ -52,6 +52,11 @@ Constant.
|
||||
--8<-- "examples/type_name.output"
|
||||
```
|
||||
|
||||
## See also
|
||||
|
||||
- [type](type.md) - return the type of the JSON value
|
||||
- [basic_json_view::type_name](../basic_json_view/type_name.md) - the same function on a zero-copy view
|
||||
|
||||
## Version history
|
||||
|
||||
- Added in version 1.0.0.
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
# <small>nlohmann::basic_json_view::</small>at
|
||||
|
||||
```cpp
|
||||
// (1)
|
||||
basic_json_view at(string_view_t key) const;
|
||||
basic_json_view at(const char* key) const;
|
||||
basic_json_view at(const string_t& key) const;
|
||||
|
||||
// (2)
|
||||
basic_json_view at(size_type idx) const;
|
||||
basic_json_view at(int idx) 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)).
|
||||
2. Returns the array element at index `idx`.
|
||||
|
||||
## Parameters
|
||||
|
||||
`key` (in)
|
||||
: object key of the element to access
|
||||
|
||||
`idx` (in)
|
||||
: index of the element to access
|
||||
|
||||
## Return value
|
||||
|
||||
1. the value of the first member with key `key`
|
||||
2. the element at index `idx`
|
||||
|
||||
## Exception safety
|
||||
|
||||
Strong exception safety: if an exception is thrown, there are no changes to the view or the document it refers to.
|
||||
|
||||
## Exceptions
|
||||
|
||||
1. The function can throw the following exceptions, both with the same message as the corresponding call to
|
||||
[`BasicJsonType::at`](../basic_json/at.md):
|
||||
- Throws [`type_error.304`](../../home/exceptions.md#jsonexceptiontype_error304) if the value is not an object.
|
||||
- Throws [`out_of_range.403`](../../home/exceptions.md#jsonexceptionout_of_range403) if no member has key `key`.
|
||||
2. The function can throw the following exceptions, both with the same message as the corresponding call to
|
||||
[`BasicJsonType::at`](../basic_json/at.md):
|
||||
- Throws [`type_error.304`](../../home/exceptions.md#jsonexceptiontype_error304) if the value is not an array.
|
||||
- Throws [`out_of_range.401`](../../home/exceptions.md#jsonexceptionout_of_range401) if `#!cpp idx >= size()`.
|
||||
|
||||
None of these exceptions carry a [`JSON_DIAGNOSTICS`](../macros/json_diagnostics.md) path: the view has no
|
||||
`BasicJsonType` value to point at, so the exception is created without one, even if `BasicJsonType` was built with
|
||||
`JSON_DIAGNOSTICS` enabled.
|
||||
|
||||
## Complexity
|
||||
|
||||
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.
|
||||
2. Linear in `idx`: elements are skipped one at a time from the first one, since they are not a fixed size in the
|
||||
index (unlike `BasicJsonType`'s array, which is random-access).
|
||||
|
||||
## Notes
|
||||
|
||||
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
|
||||
existing error handling written against `BasicJsonType::at` keeps working unchanged when switched to a view.
|
||||
|
||||
## Examples
|
||||
|
||||
??? example
|
||||
|
||||
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
|
||||
[`BasicJsonType::at`](../basic_json/at.md) would produce for the same JSON text.
|
||||
|
||||
```cpp
|
||||
--8<-- "examples/basic_json_view__at.cpp"
|
||||
```
|
||||
|
||||
Output:
|
||||
|
||||
```json
|
||||
--8<-- "examples/basic_json_view__at.output"
|
||||
```
|
||||
|
||||
## See also
|
||||
|
||||
- [operator[]](operator[].md) - access specified element (returns a discarded view instead of throwing)
|
||||
- [front](front.md), [back](back.md) - access the first or last element
|
||||
- [`BasicJsonType::at`](../basic_json/at.md) - the corresponding function of `basic_json`
|
||||
|
||||
## Version history
|
||||
|
||||
- Added in version 3.13.0.
|
||||
@@ -0,0 +1,64 @@
|
||||
# <small>nlohmann::basic_json_view::</small>back
|
||||
|
||||
```cpp
|
||||
basic_json_view back() const;
|
||||
```
|
||||
|
||||
Returns the last element of an array, the last member value of an object, or the value itself if it is primitive
|
||||
(as for [`BasicJsonType::back()`](../basic_json/back.md), a primitive value is a range of one element).
|
||||
|
||||
## Return value
|
||||
|
||||
The last element or member value. For a primitive value (number, string, boolean), the value itself.
|
||||
|
||||
## Exception safety
|
||||
|
||||
Strong exception safety: if an exception is thrown, there are no changes to the view or the document it refers to.
|
||||
|
||||
## Exceptions
|
||||
|
||||
Throws [`invalid_iterator.214`](../../home/exceptions.md#jsonexceptioninvalid_iterator214) if the view is
|
||||
[null](is_null.md) or [discarded](is_discarded.md), or if it is an empty array or object.
|
||||
|
||||
This exception does not carry a [`JSON_DIAGNOSTICS`](../macros/json_diagnostics.md) path: the view has no
|
||||
`BasicJsonType` value to point at, so the exception is created without one, even if `BasicJsonType` was built with
|
||||
`JSON_DIAGNOSTICS` enabled.
|
||||
|
||||
## Complexity
|
||||
|
||||
Linear in the size of the array or object: unlike [`front()`](front.md), which only ever looks at the first
|
||||
element, `back()` has to walk every element to find where they end, since elements are not a fixed size in the
|
||||
index.
|
||||
|
||||
## Notes
|
||||
|
||||
Unlike [`BasicJsonType::back()`](../basic_json/back.md), which has undefined behavior for an empty array or object,
|
||||
`back()` throws `invalid_iterator.214` in that case -- the same way it already does for `#!json null` and for a
|
||||
discarded view, where `BasicJsonType::back()` also throws.
|
||||
|
||||
## Examples
|
||||
|
||||
??? example
|
||||
|
||||
The example below reads only the final status of a build log with `back()`. Even though `back()` is linear in
|
||||
the number of events (unlike [`front()`](front.md), which is constant), it still avoids building a
|
||||
`BasicJsonType` value for the events that are not needed.
|
||||
|
||||
```cpp
|
||||
--8<-- "examples/basic_json_view__back.cpp"
|
||||
```
|
||||
|
||||
Output:
|
||||
|
||||
```json
|
||||
--8<-- "examples/basic_json_view__back.output"
|
||||
```
|
||||
|
||||
## See also
|
||||
|
||||
- [front](front.md) - access the first element
|
||||
- [`BasicJsonType::back`](../basic_json/back.md) - the corresponding function of `basic_json`
|
||||
|
||||
## Version history
|
||||
|
||||
- Added in version 3.13.0.
|
||||
@@ -8,8 +8,9 @@ Creates an invalid (discarded) view: [`type()`](type.md) is `#!cpp value_t::disc
|
||||
[`is_discarded()`](is_discarded.md) is `#!cpp true`, and `#!cpp explicit operator bool()` is `#!cpp false`.
|
||||
|
||||
This is the only constructor a caller can use directly. Every other view is obtained from a
|
||||
[`basic_json_document`](../basic_json_document/index.md), via [`root()`](../basic_json_document/root.md) or (once
|
||||
element access is added) from navigating into a container.
|
||||
[`basic_json_document`](../basic_json_document/index.md), via [`root()`](../basic_json_document/root.md) or by
|
||||
navigating into a container with [`operator[]`](operator[].md), [`at`](at.md), [`front`](front.md), [`back`](back.md),
|
||||
[`find`](find.md), or iteration.
|
||||
|
||||
## Exception safety
|
||||
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
# <small>nlohmann::basic_json_view::</small>begin
|
||||
|
||||
```cpp
|
||||
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
|
||||
element (itself); `#!json null` and a [discarded](is_discarded.md) view iterate as an empty range.
|
||||
|
||||
## Return value
|
||||
|
||||
Iterator to the first element.
|
||||
|
||||
## Exception safety
|
||||
|
||||
No-throw guarantee: this function never throws exceptions.
|
||||
|
||||
## Complexity
|
||||
|
||||
Constant.
|
||||
|
||||
## Notes
|
||||
|
||||
For an object, iteration visits **every** member, including all occurrences of a duplicate key -- unlike
|
||||
[`operator[]`](operator[].md), [`at`](at.md), [`find`](find.md), [`contains`](contains.md), and [`count`](count.md),
|
||||
which all resolve to the *first* member with a given key. See the
|
||||
[Notes on duplicate keys](operator[].md#notes) of `operator[]`.
|
||||
|
||||
Because objects are iterated in document order rather than sorted by key, the order seen here can differ from what
|
||||
iterating the [`materialize()`](materialize.md)d `BasicJsonType` value would produce: a `#!cpp basic_json` object
|
||||
(`std::map`-backed by default) sorts its keys, while a view does not.
|
||||
|
||||
## Examples
|
||||
|
||||
??? example
|
||||
|
||||
The example below iterates a log record's members with `begin()`/[`end()`](end.md) and prints them in the order
|
||||
they were written. Materializing the record into a `BasicJsonType` object and iterating that would instead print
|
||||
the members sorted by key.
|
||||
|
||||
```cpp
|
||||
--8<-- "examples/basic_json_view__begin.cpp"
|
||||
```
|
||||
|
||||
Output:
|
||||
|
||||
```json
|
||||
--8<-- "examples/basic_json_view__begin.output"
|
||||
```
|
||||
|
||||
## See also
|
||||
|
||||
- [end](end.md) - returns an iterator to one past the last element
|
||||
- [cbegin](cbegin.md) - returns a const iterator to the first element
|
||||
- [items](items.md) - access iterator member functions in range-based for
|
||||
- [`BasicJsonType::begin`](../basic_json/begin.md) - the corresponding function of `basic_json`
|
||||
|
||||
## Version history
|
||||
|
||||
- Added in version 3.13.0.
|
||||
@@ -0,0 +1,49 @@
|
||||
# <small>nlohmann::basic_json_view::</small>cbegin
|
||||
|
||||
```cpp
|
||||
iterator cbegin() const noexcept;
|
||||
```
|
||||
|
||||
Returns an iterator to the first element, in [document order](begin.md). Equivalent to [`begin()`](begin.md): a view
|
||||
is always read-only, so `#!cpp const_iterator` and `#!cpp iterator` are the same type, and `cbegin()` exists only so
|
||||
that generic code that expects a `cbegin()`/`cend()` pair works with a view too.
|
||||
|
||||
## Return value
|
||||
|
||||
Iterator to the first element; identical to what [`begin()`](begin.md) returns.
|
||||
|
||||
## Exception safety
|
||||
|
||||
No-throw guarantee: this function never throws exceptions.
|
||||
|
||||
## Complexity
|
||||
|
||||
Constant.
|
||||
|
||||
## Examples
|
||||
|
||||
??? 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
|
||||
`BasicJsonType` value.
|
||||
|
||||
```cpp
|
||||
--8<-- "examples/basic_json_view__cbegin.cpp"
|
||||
```
|
||||
|
||||
Output:
|
||||
|
||||
```json
|
||||
--8<-- "examples/basic_json_view__cbegin.output"
|
||||
```
|
||||
|
||||
## See also
|
||||
|
||||
- [begin](begin.md) - returns an iterator to the first element
|
||||
- [cend](cend.md) - returns a const iterator to one past the last element
|
||||
- [`BasicJsonType::cbegin`](../basic_json/cbegin.md) - the corresponding function of `basic_json`
|
||||
|
||||
## Version history
|
||||
|
||||
- Added in version 3.13.0.
|
||||
@@ -0,0 +1,49 @@
|
||||
# <small>nlohmann::basic_json_view::</small>cend
|
||||
|
||||
```cpp
|
||||
iterator cend() const noexcept;
|
||||
```
|
||||
|
||||
Returns an iterator to one past the last element, in [document order](begin.md). Equivalent to [`end()`](end.md): a
|
||||
view is always read-only, so `#!cpp const_iterator` and `#!cpp iterator` are the same type, and `cend()` exists only
|
||||
so that generic code that expects a `cbegin()`/`cend()` pair works with a view too.
|
||||
|
||||
## Return value
|
||||
|
||||
Iterator one past the last element; identical to what [`end()`](end.md) returns.
|
||||
|
||||
## Exception safety
|
||||
|
||||
No-throw guarantee: this function never throws exceptions.
|
||||
|
||||
## Complexity
|
||||
|
||||
Constant.
|
||||
|
||||
## Examples
|
||||
|
||||
??? 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
|
||||
materializing any record of the batch.
|
||||
|
||||
```cpp
|
||||
--8<-- "examples/basic_json_view__cend.cpp"
|
||||
```
|
||||
|
||||
Output:
|
||||
|
||||
```json
|
||||
--8<-- "examples/basic_json_view__cend.output"
|
||||
```
|
||||
|
||||
## See also
|
||||
|
||||
- [end](end.md) - returns an iterator to one past the last element
|
||||
- [cbegin](cbegin.md) - returns a const iterator to the first element
|
||||
- [`BasicJsonType::cend`](../basic_json/cend.md) - the corresponding function of `basic_json`
|
||||
|
||||
## Version history
|
||||
|
||||
- Added in version 3.13.0.
|
||||
@@ -0,0 +1,64 @@
|
||||
# <small>nlohmann::basic_json_view::</small>contains
|
||||
|
||||
```cpp
|
||||
bool contains(string_view_t key) const;
|
||||
bool contains(const char* key) const;
|
||||
bool contains(const string_t& key) const;
|
||||
```
|
||||
|
||||
Checks whether the value is an object with a member with key `key`.
|
||||
|
||||
## Parameters
|
||||
|
||||
`key` (in)
|
||||
: key value to check its existence
|
||||
|
||||
## Return value
|
||||
|
||||
`#!cpp true` if the value is an object and has a member with key `key`, `#!cpp false` otherwise.
|
||||
|
||||
## Exception safety
|
||||
|
||||
No-throw guarantee: this function never throws exceptions.
|
||||
|
||||
## Complexity
|
||||
|
||||
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.
|
||||
|
||||
## Notes
|
||||
|
||||
This method always returns `#!cpp false` when the value is not an object -- including a [discarded](is_discarded.md)
|
||||
view.
|
||||
|
||||
!!! info "Postconditions"
|
||||
|
||||
If `#!cpp v.contains(key)` returns `#!cpp true`, then `#!cpp v[key]` is not [discarded](is_discarded.md).
|
||||
|
||||
## Examples
|
||||
|
||||
??? example
|
||||
|
||||
The example below counts how many of a batch of records carry an optional `retry_of` field, using `contains()`
|
||||
to check without ever materializing a single record of the batch.
|
||||
|
||||
```cpp
|
||||
--8<-- "examples/basic_json_view__contains.cpp"
|
||||
```
|
||||
|
||||
Output:
|
||||
|
||||
```json
|
||||
--8<-- "examples/basic_json_view__contains.output"
|
||||
```
|
||||
|
||||
## See also
|
||||
|
||||
- [find](find.md) - find a value in an object
|
||||
- [count](count.md) - returns the number of occurrences of a key
|
||||
- [`BasicJsonType::contains`](../basic_json/contains.md) - the corresponding function of `basic_json`
|
||||
|
||||
## Version history
|
||||
|
||||
- Added in version 3.13.0.
|
||||
@@ -0,0 +1,66 @@
|
||||
# <small>nlohmann::basic_json_view::</small>count
|
||||
|
||||
```cpp
|
||||
size_type count(string_view_t key) const;
|
||||
size_type count(const char* key) const;
|
||||
size_type count(const string_t& key) const;
|
||||
```
|
||||
|
||||
Returns `#!cpp 1` if the value is an object with a member with key `key`, `#!cpp 0` otherwise.
|
||||
|
||||
## Parameters
|
||||
|
||||
`key` (in)
|
||||
: key value of the element to count
|
||||
|
||||
## Return value
|
||||
|
||||
`#!cpp 1` if the value is an object and has a member with key `key`, `#!cpp 0` otherwise.
|
||||
|
||||
## Exception safety
|
||||
|
||||
No-throw guarantee: this function never throws exceptions.
|
||||
|
||||
## Complexity
|
||||
|
||||
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.
|
||||
|
||||
## Notes
|
||||
|
||||
This method always returns `#!cpp 0` when the value is not an object -- including a [discarded](is_discarded.md)
|
||||
view.
|
||||
|
||||
Unlike [`BasicJsonType::count()`](../basic_json/count.md), whose return value can in principle exceed `#!cpp 1` for
|
||||
an `ObjectType` that allows multiple entries per key, `count()` here never does: it is exactly
|
||||
[`contains()`](contains.md) as `#!cpp 0`/`#!cpp 1`. This holds even if the source text has a duplicate key -- see the
|
||||
[Notes on duplicate keys](operator[].md#notes) of `operator[]` -- because a `#!cpp count() > 1` result would require
|
||||
counting every member with a matching key, not just finding the first one.
|
||||
|
||||
## Examples
|
||||
|
||||
??? example
|
||||
|
||||
The example below validates that every transaction of a batch carries a mandatory `amount` field, using
|
||||
`count()` before deciding whether to materialize a transaction at all.
|
||||
|
||||
```cpp
|
||||
--8<-- "examples/basic_json_view__count.cpp"
|
||||
```
|
||||
|
||||
Output:
|
||||
|
||||
```json
|
||||
--8<-- "examples/basic_json_view__count.output"
|
||||
```
|
||||
|
||||
## See also
|
||||
|
||||
- [find](find.md) - find a value in an object
|
||||
- [contains](contains.md) - checks whether a key exists
|
||||
- [`BasicJsonType::count`](../basic_json/count.md) - the corresponding function of `basic_json`
|
||||
|
||||
## Version history
|
||||
|
||||
- Added in version 3.13.0.
|
||||
@@ -0,0 +1,54 @@
|
||||
# <small>nlohmann::basic_json_view::</small>end
|
||||
|
||||
```cpp
|
||||
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);
|
||||
`#!json null` and a [discarded](is_discarded.md) view iterate as an empty range, so `#!cpp begin() == end()` for
|
||||
them.
|
||||
|
||||
## Return value
|
||||
|
||||
Iterator one past the last element.
|
||||
|
||||
## Exception safety
|
||||
|
||||
No-throw guarantee: this function never throws exceptions.
|
||||
|
||||
## Complexity
|
||||
|
||||
Constant.
|
||||
|
||||
## Notes
|
||||
|
||||
`#!cpp iterator` is a forward iterator: unlike `BasicJsonType::iterator`, it cannot be decremented, so there is no
|
||||
way to reach the last element by stepping back from `end()`. Use [`back()`](back.md) instead.
|
||||
|
||||
## Examples
|
||||
|
||||
??? example
|
||||
|
||||
The example below scans a (possibly large) array of readings for the first one over a threshold, stopping the
|
||||
loop at `end()` as soon as one is found. Only the matching reading, if any, is ever materialized.
|
||||
|
||||
```cpp
|
||||
--8<-- "examples/basic_json_view__end.cpp"
|
||||
```
|
||||
|
||||
Output:
|
||||
|
||||
```json
|
||||
--8<-- "examples/basic_json_view__end.output"
|
||||
```
|
||||
|
||||
## See also
|
||||
|
||||
- [begin](begin.md) - returns an iterator to the first element
|
||||
- [cend](cend.md) - returns a const iterator to one past the last element
|
||||
- [`BasicJsonType::end`](../basic_json/end.md) - the corresponding function of `basic_json`
|
||||
|
||||
## Version history
|
||||
|
||||
- Added in version 3.13.0.
|
||||
@@ -0,0 +1,63 @@
|
||||
# <small>nlohmann::basic_json_view::</small>find
|
||||
|
||||
```cpp
|
||||
iterator find(string_view_t key) const;
|
||||
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
|
||||
[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.
|
||||
|
||||
## Parameters
|
||||
|
||||
`key` (in)
|
||||
: key value of the element to search for
|
||||
|
||||
## Return value
|
||||
|
||||
An iterator to the member with key `key`, or [`end()`](end.md) if there is none or the value is not an object.
|
||||
|
||||
## Exception safety
|
||||
|
||||
No-throw guarantee: this function never throws exceptions.
|
||||
|
||||
## Complexity
|
||||
|
||||
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.
|
||||
|
||||
## Notes
|
||||
|
||||
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.
|
||||
|
||||
## Examples
|
||||
|
||||
??? example
|
||||
|
||||
The example below scans a batch of events for those that carry an optional `user_id` field, using `find()`
|
||||
instead of [`operator[]`](operator[].md) (which would throw for the events that are not objects at all) or
|
||||
[`contains()`](contains.md) followed by a second lookup. Events without a match are never materialized.
|
||||
|
||||
```cpp
|
||||
--8<-- "examples/basic_json_view__find.cpp"
|
||||
```
|
||||
|
||||
Output:
|
||||
|
||||
```json
|
||||
--8<-- "examples/basic_json_view__find.output"
|
||||
```
|
||||
|
||||
## See also
|
||||
|
||||
- [count](count.md) - returns the number of occurrences of a key
|
||||
- [contains](contains.md) - checks whether a key exists
|
||||
- [`BasicJsonType::find`](../basic_json/find.md) - the corresponding function of `basic_json`
|
||||
|
||||
## Version history
|
||||
|
||||
- Added in version 3.13.0.
|
||||
@@ -0,0 +1,61 @@
|
||||
# <small>nlohmann::basic_json_view::</small>front
|
||||
|
||||
```cpp
|
||||
basic_json_view front() const;
|
||||
```
|
||||
|
||||
Returns the first element of an array, the first member value of an object, or the value itself if it is primitive
|
||||
(as for [`BasicJsonType::front()`](../basic_json/front.md), a primitive value is a range of one element).
|
||||
|
||||
## Return value
|
||||
|
||||
The first element or member value. For a primitive value (number, string, boolean), the value itself.
|
||||
|
||||
## Exception safety
|
||||
|
||||
Strong exception safety: if an exception is thrown, there are no changes to the view or the document it refers to.
|
||||
|
||||
## Exceptions
|
||||
|
||||
Throws [`invalid_iterator.214`](../../home/exceptions.md#jsonexceptioninvalid_iterator214) if the view is
|
||||
[null](is_null.md) or [discarded](is_discarded.md), or if it is an empty array or object.
|
||||
|
||||
This exception does not carry a [`JSON_DIAGNOSTICS`](../macros/json_diagnostics.md) path: the view has no
|
||||
`BasicJsonType` value to point at, so the exception is created without one, even if `BasicJsonType` was built with
|
||||
`JSON_DIAGNOSTICS` enabled.
|
||||
|
||||
## Complexity
|
||||
|
||||
Constant.
|
||||
|
||||
## Notes
|
||||
|
||||
Unlike [`BasicJsonType::front()`](../basic_json/front.md), which has undefined behavior for an empty array or
|
||||
object, `front()` throws `invalid_iterator.214` in that case -- the same way it already does for `#!json null` and
|
||||
for a discarded view, where `BasicJsonType::front()` also throws.
|
||||
|
||||
## Examples
|
||||
|
||||
??? example
|
||||
|
||||
The example below reads only the earliest entry of a build log with `front()`, without materializing the rest
|
||||
of the (possibly long) log.
|
||||
|
||||
```cpp
|
||||
--8<-- "examples/basic_json_view__front.cpp"
|
||||
```
|
||||
|
||||
Output:
|
||||
|
||||
```json
|
||||
--8<-- "examples/basic_json_view__front.output"
|
||||
```
|
||||
|
||||
## See also
|
||||
|
||||
- [back](back.md) - access the last element
|
||||
- [`BasicJsonType::front`](../basic_json/front.md) - the corresponding function of `basic_json`
|
||||
|
||||
## Version history
|
||||
|
||||
- Added in version 3.13.0.
|
||||
@@ -19,9 +19,9 @@ to the document and a pointer into its index), trivially copyable. A view is val
|
||||
Moving the document itself does not invalidate its views: the index is heap-allocated independently of the
|
||||
`basic_json_document` object.
|
||||
|
||||
`basic_json_view` provides the read-only part of the `BasicJsonType` interface: the type-inspection functions, and
|
||||
[`materialize()`](materialize.md) to build the `BasicJsonType` value of a subtree on demand. It does not (yet) provide
|
||||
element access, iteration, `get<T>()`, JSON Pointer support, `dump()`, or comparison.
|
||||
`basic_json_view` provides the read-only part of the `BasicJsonType` interface: the type-inspection functions, element
|
||||
access, lookup, iteration, and [`materialize()`](materialize.md) to build the `BasicJsonType` value of a subtree on
|
||||
demand. It does not (yet) provide `get<T>()`, JSON Pointer support, `dump()`, or comparison.
|
||||
|
||||
## Template parameters
|
||||
|
||||
@@ -41,6 +41,9 @@ element access, iteration, `get<T>()`, JSON Pointer support, `dump()`, or compar
|
||||
member types of `BasicJsonType`
|
||||
- **size_type** - `#!cpp std::size_t`
|
||||
- **string_view_t** - `#!cpp std::string_view` on C++17 and newer, a minimal internal substitute otherwise
|
||||
- **iterator**, **const_iterator** - a forward iterator over the elements of an array or the member values of an
|
||||
object, in document order; both names refer to the same type, since a view is always read-only
|
||||
- **item** - a (key, value) pair produced by [`items()`](items.md)
|
||||
|
||||
## Member functions
|
||||
|
||||
@@ -49,6 +52,7 @@ element access, iteration, `get<T>()`, JSON Pointer support, `dump()`, or compar
|
||||
### Object inspection
|
||||
|
||||
- [**type**](type.md) - return the type of the value
|
||||
- [**type_name**](type_name.md) - return the type as string
|
||||
- [**is_null**](is_null.md) - return whether the value is null
|
||||
- [**is_boolean**](is_boolean.md) - return whether the value is a boolean
|
||||
- [**is_number**](is_number.md) - return whether the value is a number
|
||||
@@ -64,6 +68,27 @@ element access, iteration, `get<T>()`, JSON Pointer support, `dump()`, or compar
|
||||
- [**is_discarded**](is_discarded.md) - return whether the view is invalid
|
||||
- [**operator bool**](operator_bool.md) - return whether the view refers to a value
|
||||
|
||||
### Element access
|
||||
|
||||
- [**at**](at.md) - access specified element with bounds checking
|
||||
- [**operator[]**](operator[].md) - access specified element
|
||||
- [**front**](front.md) - access the first element
|
||||
- [**back**](back.md) - access the last element
|
||||
|
||||
### Lookup
|
||||
|
||||
- [**find**](find.md) - find an element in an object
|
||||
- [**count**](count.md) - returns the number of occurrences of a key in an object
|
||||
- [**contains**](contains.md) - check the existence of an element in an object
|
||||
|
||||
### Iterators
|
||||
|
||||
- [**begin**](begin.md) - returns an iterator to the first element
|
||||
- [**cbegin**](cbegin.md) - returns a const iterator to the first element
|
||||
- [**end**](end.md) - returns an iterator to one past the last element
|
||||
- [**cend**](cend.md) - returns a const iterator to one past the last element
|
||||
- [**items**](items.md) - wrapper to access iterator member functions in range-based for
|
||||
|
||||
### Capacity
|
||||
|
||||
- [**size**](size.md) - return the number of elements
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
# <small>nlohmann::basic_json_view::</small>items
|
||||
|
||||
```cpp
|
||||
/* unspecified */ items() const noexcept;
|
||||
```
|
||||
|
||||
Returns a range of [`item`](index.md#member-types) values -- (key, value) pairs -- for use in range-based for loops.
|
||||
The key of an array element is its index, converted to a string, as for
|
||||
[`BasicJsonType::items()`](../basic_json/items.md).
|
||||
|
||||
The returned type is not part of the public API and may change between versions; use a range-based for loop (see the
|
||||
example), or `#!cpp decltype(v.items())` if you need to name it.
|
||||
|
||||
```cpp
|
||||
for (const auto& item : v.items())
|
||||
{
|
||||
std::cout << "key: " << item.key() << ", value: " << item.value() << '\n';
|
||||
}
|
||||
```
|
||||
|
||||
On C++17, `item` also supports [structured bindings](https://en.cppreference.com/w/cpp/language/structured_binding):
|
||||
|
||||
```cpp
|
||||
for (const auto [key, value] : v.items())
|
||||
{
|
||||
std::cout << "key: " << key << ", value: " << value << '\n';
|
||||
}
|
||||
```
|
||||
|
||||
Note the `#!cpp const auto` (by value), not `#!cpp const auto&`: unlike `BasicJsonType::items()`, whose elements are
|
||||
references into an existing object, a view's `item` is produced on the fly for each step of the iteration, so there
|
||||
is nothing for a reference to bind to.
|
||||
|
||||
## Return value
|
||||
|
||||
A range whose iterators dereference to [`item`](index.md#member-types) and whose `#!cpp begin()`/`#!cpp end()` are
|
||||
equivalent to [`basic_json_view::begin()`](begin.md)/[`end()`](end.md), in document order.
|
||||
|
||||
## Exception safety
|
||||
|
||||
No-throw guarantee: this function never throws exceptions.
|
||||
|
||||
## Complexity
|
||||
|
||||
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),
|
||||
[`contains`](contains.md), and [`count`](count.md), which resolve to the *first* member with a given key. See the
|
||||
[Notes on duplicate keys](operator[].md#notes) of `operator[]`.
|
||||
|
||||
!!! danger "Lifetime issues"
|
||||
|
||||
As for `BasicJsonType::items()`, calling `items()` on a temporary view (or a temporary document) is dangerous:
|
||||
the range refers back to the document, so the document must outlive the loop. See
|
||||
[#2040](https://github.com/nlohmann/json/issues/2040) for the `BasicJsonType` background.
|
||||
|
||||
## Examples
|
||||
|
||||
??? example
|
||||
|
||||
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*.
|
||||
|
||||
```cpp
|
||||
--8<-- "examples/basic_json_view__items.cpp"
|
||||
```
|
||||
|
||||
Output:
|
||||
|
||||
```json
|
||||
--8<-- "examples/basic_json_view__items.output"
|
||||
```
|
||||
|
||||
## See also
|
||||
|
||||
- [begin](begin.md), [end](end.md) - the iterators `items()` is built on
|
||||
- [`BasicJsonType::items`](../basic_json/items.md) - the corresponding function of `basic_json`
|
||||
|
||||
## Version history
|
||||
|
||||
- Added in version 3.13.0.
|
||||
@@ -0,0 +1,105 @@
|
||||
# <small>nlohmann::basic_json_view::</small>operator[]
|
||||
|
||||
```cpp
|
||||
// (1)
|
||||
basic_json_view operator[](string_view_t key) const;
|
||||
basic_json_view operator[](const char* key) const;
|
||||
basic_json_view operator[](const string_t& key) const;
|
||||
|
||||
// (2)
|
||||
basic_json_view operator[](size_type idx) const;
|
||||
basic_json_view operator[](int idx) 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.
|
||||
2. Returns the array element at index `idx`, or a [discarded](is_discarded.md) view if `idx` is out of range. (The
|
||||
`#!cpp int` overload only exists so that an integer literal is not ambiguous between this overload and 1.)
|
||||
|
||||
## Parameters
|
||||
|
||||
`key` (in)
|
||||
: object key of the element to access
|
||||
|
||||
`idx` (in)
|
||||
: index of the element to access
|
||||
|
||||
## Return value
|
||||
|
||||
1. the value of the first member with key `key`, or a discarded view if `#!cpp is_object()` is `#!cpp false` or no
|
||||
member has this key
|
||||
2. the element at index `idx`, or a discarded view if `#!cpp is_array()` is `#!cpp false` or `#!cpp idx >= size()`
|
||||
|
||||
## Exception safety
|
||||
|
||||
Strong exception safety: if an exception is thrown, 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 --
|
||||
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 --
|
||||
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.
|
||||
|
||||
Neither exception carries a [`JSON_DIAGNOSTICS`](../macros/json_diagnostics.md) path: the view has no `BasicJsonType`
|
||||
value to point at, so the exception is created without one, even if `BasicJsonType` was built with
|
||||
`JSON_DIAGNOSTICS` enabled.
|
||||
|
||||
## Complexity
|
||||
|
||||
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 of a
|
||||
different length than `key` is rejected without touching the source text.
|
||||
2. Linear in `idx`: elements are skipped one at a time from the first one, since they are not a fixed size in the
|
||||
index (unlike `BasicJsonType`'s array, which is random-access).
|
||||
|
||||
## Notes
|
||||
|
||||
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 always
|
||||
returns a safe, testable result: a [discarded](is_discarded.md) view, which is `#!cpp false` in a boolean context.
|
||||
There is also no non-const overload that inserts a missing key or extends an array -- a view never modifies the
|
||||
document.
|
||||
|
||||
!!! info "Duplicate keys"
|
||||
|
||||
If the source text has an object with a duplicate key, `#!cpp operator[]` (and [`at`](at.md), [`find`](find.md),
|
||||
[`contains`](contains.md), [`count`](count.md)) all resolve to the *first* member with that key, because a
|
||||
lookup can stop as soon as it finds a match. This is different from
|
||||
[`materialize()`](materialize.md) (and [`BasicJsonType::parse()`](../basic_json/parse.md)), which replay every
|
||||
member in order and so end up keeping the *last* value for a repeated key -- there is no reason for them to stop
|
||||
early. [`begin()`](begin.md)/[`end()`](end.md) and [`items()`](items.md) iterate over *all* members, including
|
||||
duplicates, in document order. See the example below and [`size()`](size.md#notes).
|
||||
|
||||
## Examples
|
||||
|
||||
??? example
|
||||
|
||||
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
|
||||
`#!cpp if`, instead of relying on undefined behavior.
|
||||
|
||||
```cpp
|
||||
--8<-- "examples/basic_json_view__operator[].cpp"
|
||||
```
|
||||
|
||||
Output:
|
||||
|
||||
```json
|
||||
--8<-- "examples/basic_json_view__operator[].output"
|
||||
```
|
||||
|
||||
## See also
|
||||
|
||||
- [at](at.md) - access specified element with bounds checking (throws instead of returning a discarded view)
|
||||
- [front](front.md), [back](back.md) - access the first or last element
|
||||
- [find](find.md), [contains](contains.md) - look up a member without throwing
|
||||
- [`BasicJsonType::operator[]`](../basic_json/operator%5B%5D.md) - the corresponding function of `basic_json`
|
||||
|
||||
## Version history
|
||||
|
||||
- Added in version 3.13.0.
|
||||
@@ -33,6 +33,12 @@ Constant: for an object or array, the element count is stored in the index, not
|
||||
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
|
||||
[`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
|
||||
members there are.
|
||||
|
||||
## Examples
|
||||
|
||||
??? example
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
# <small>nlohmann::basic_json_view::</small>type_name
|
||||
|
||||
```cpp
|
||||
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
|
||||
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).
|
||||
|
||||
## Return value
|
||||
|
||||
a string representation of the type ([`value_t`](../basic_json/value_t.md)):
|
||||
|
||||
| Value type | return value |
|
||||
|-----------------------------------------------------|---------------|
|
||||
| `#!json null` | `"null"` |
|
||||
| boolean | `"boolean"` |
|
||||
| string | `"string"` |
|
||||
| number (integer, unsigned integer, floating-point) | `"number"` |
|
||||
| object | `"object"` |
|
||||
| array | `"array"` |
|
||||
| discarded | `"discarded"` |
|
||||
|
||||
`type_name()` never returns `#!cpp "binary"`, since a JSON text has no binary values (see
|
||||
[`is_binary()`](is_binary.md)); it also never returns `#!cpp "invalid"`, since a view's `#!cpp kind` always comes
|
||||
from a value the parser actually produced.
|
||||
|
||||
## Exception safety
|
||||
|
||||
No-throw guarantee: this function never throws exceptions.
|
||||
|
||||
## Complexity
|
||||
|
||||
Constant.
|
||||
|
||||
## Examples
|
||||
|
||||
??? example
|
||||
|
||||
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.
|
||||
|
||||
```cpp
|
||||
--8<-- "examples/basic_json_view__type_name.cpp"
|
||||
```
|
||||
|
||||
Output:
|
||||
|
||||
```json
|
||||
--8<-- "examples/basic_json_view__type_name.output"
|
||||
```
|
||||
|
||||
## See also
|
||||
|
||||
- [type](type.md) - return the type of the value
|
||||
- [`BasicJsonType::type_name`](../basic_json/type_name.md) - the corresponding function of `basic_json`
|
||||
|
||||
## Version history
|
||||
|
||||
- Added in version 3.13.0.
|
||||
@@ -0,0 +1,36 @@
|
||||
#include <iostream>
|
||||
#include <nlohmann/json_view.hpp>
|
||||
|
||||
using json_document = nlohmann::json_document;
|
||||
using json_view = nlohmann::json_view;
|
||||
|
||||
int main()
|
||||
{
|
||||
// required fields of a service configuration -- at() reports a missing
|
||||
// or wrong-typed field with the very same exception basic_json::at()
|
||||
// would throw for the equivalent nlohmann::json value, so error
|
||||
// handling written against basic_json::at() keeps working unchanged
|
||||
json_document config = json_document::parse(R"({"name": "cache", "port": "6379"})");
|
||||
const json_view service = config.root();
|
||||
|
||||
std::cout << service.at("port").materialize().dump() << '\n';
|
||||
|
||||
try
|
||||
{
|
||||
// "port" is a string, not an array
|
||||
static_cast<void>(service.at("port").at(0));
|
||||
}
|
||||
catch (const nlohmann::json::type_error& e)
|
||||
{
|
||||
std::cout << e.what() << '\n';
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
static_cast<void>(service.at("timeout"));
|
||||
}
|
||||
catch (const nlohmann::json::out_of_range& e)
|
||||
{
|
||||
std::cout << e.what() << '\n';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
"6379"
|
||||
[json.exception.type_error.304] cannot use at() with string
|
||||
[json.exception.out_of_range.403] key 'timeout' not found
|
||||
@@ -0,0 +1,25 @@
|
||||
#include <iostream>
|
||||
#include <nlohmann/json_view.hpp>
|
||||
|
||||
using json_document = nlohmann::json_document;
|
||||
|
||||
int main()
|
||||
{
|
||||
// the same build log; back() reads only the final status. It is linear
|
||||
// in the number of events (unlike front(), which is constant), but
|
||||
// still far less work than materializing the whole array
|
||||
json_document log = json_document::parse(R"(["queued", "started", "compiling", "linking", "done"])");
|
||||
std::cout << log.root().back().materialize().dump() << '\n';
|
||||
|
||||
// an empty log -- back() throws instead of the undefined behavior
|
||||
// basic_json::back() has for an empty array
|
||||
json_document empty_log = json_document::parse("[]");
|
||||
try
|
||||
{
|
||||
static_cast<void>(empty_log.root().back());
|
||||
}
|
||||
catch (const nlohmann::json::invalid_iterator& e)
|
||||
{
|
||||
std::cout << e.what() << '\n';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
"done"
|
||||
[json.exception.invalid_iterator.214] cannot get value
|
||||
@@ -0,0 +1,18 @@
|
||||
#include <iostream>
|
||||
#include <nlohmann/json_view.hpp>
|
||||
|
||||
using json_document = nlohmann::json_document;
|
||||
|
||||
int main()
|
||||
{
|
||||
// a log record: the fields matter in the order they were written, e.g.
|
||||
// to reproduce the record as it was logged. A nlohmann::json object
|
||||
// sorts its keys, so materializing and iterating it would instead print
|
||||
// them alphabetically ("level", "message", "time")
|
||||
json_document record = json_document::parse(R"({"time": "10:00:01", "level": "info", "message": "started"})");
|
||||
|
||||
for (auto it = record.root().begin(); it != record.root().end(); ++it)
|
||||
{
|
||||
std::cout << it.key() << '=' << it->materialize().dump() << '\n';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
time="10:00:01"
|
||||
level="info"
|
||||
message="started"
|
||||
@@ -0,0 +1,24 @@
|
||||
#include <iostream>
|
||||
#include <numeric>
|
||||
#include <nlohmann/json_view.hpp>
|
||||
|
||||
using json_document = nlohmann::json_document;
|
||||
using json_view = nlohmann::json_view;
|
||||
|
||||
int main()
|
||||
{
|
||||
// sum many measurements with std::accumulate; cbegin()/cend() (identical
|
||||
// to begin()/end() here -- the view is always read-only) let the view be
|
||||
// used with standard algorithms without ever materializing the whole
|
||||
// array into a nlohmann::json value
|
||||
json_document measurements = json_document::parse("[3, 1, 4, 1, 5, 9, 2, 6]");
|
||||
const auto values = measurements.root();
|
||||
|
||||
const int sum = std::accumulate(values.cbegin(), values.cend(), 0,
|
||||
[](int total, const json_view & v)
|
||||
{
|
||||
return total + v.materialize().get<int>();
|
||||
});
|
||||
|
||||
std::cout << sum << '\n';
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
31
|
||||
@@ -0,0 +1,24 @@
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include <nlohmann/json_view.hpp>
|
||||
|
||||
using json_document = nlohmann::json_document;
|
||||
using json_view = nlohmann::json_view;
|
||||
|
||||
int main()
|
||||
{
|
||||
// check that every element of a (possibly large) batch is an object,
|
||||
// before materializing any of them -- cbegin()/cend() (identical to
|
||||
// begin()/end() here) work as the range for std::all_of like they would
|
||||
// for any standard container
|
||||
json_document batch = json_document::parse(R"([{"id": 1}, {"id": 2}, {"id": 3}])");
|
||||
const auto records = batch.root();
|
||||
|
||||
const bool all_objects = std::all_of(records.cbegin(), records.cend(),
|
||||
[](const json_view & v)
|
||||
{
|
||||
return v.is_object();
|
||||
});
|
||||
|
||||
std::cout << std::boolalpha << all_objects << '\n';
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
true
|
||||
@@ -0,0 +1,30 @@
|
||||
#include <iostream>
|
||||
#include <nlohmann/json_view.hpp>
|
||||
|
||||
using json_document = nlohmann::json_document;
|
||||
|
||||
int main()
|
||||
{
|
||||
// count how many of many incoming records carry an optional "retry_of"
|
||||
// field -- contains() only walks the flat index, so scanning a large
|
||||
// batch like this never builds a single nlohmann::json value
|
||||
json_document batch = json_document::parse(R"(
|
||||
[
|
||||
{"id": 1},
|
||||
{"id": 2, "retry_of": 1},
|
||||
{"id": 3},
|
||||
{"id": 4, "retry_of": 3}
|
||||
]
|
||||
)");
|
||||
|
||||
const auto records = batch.root();
|
||||
std::size_t retries = 0;
|
||||
for (std::size_t i = 0; i < records.size(); ++i)
|
||||
{
|
||||
if (records[i].contains("retry_of"))
|
||||
{
|
||||
++retries;
|
||||
}
|
||||
}
|
||||
std::cout << retries << " of " << records.size() << " records are retries\n";
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
2 of 4 records are retries
|
||||
@@ -0,0 +1,29 @@
|
||||
#include <iostream>
|
||||
#include <nlohmann/json_view.hpp>
|
||||
|
||||
using json_document = nlohmann::json_document;
|
||||
|
||||
int main()
|
||||
{
|
||||
// validate that every transaction of a batch carries a mandatory
|
||||
// "amount" field before materializing any of them into a nlohmann::json
|
||||
// value -- count() returns 0 or 1 for an object
|
||||
json_document batch = json_document::parse(R"(
|
||||
[
|
||||
{"id": 1, "amount": 9.99},
|
||||
{"id": 2}
|
||||
]
|
||||
)");
|
||||
|
||||
const auto transactions = batch.root();
|
||||
for (std::size_t i = 0; i < transactions.size(); ++i)
|
||||
{
|
||||
const auto transaction = transactions[i];
|
||||
if (transaction.count("amount") == 0)
|
||||
{
|
||||
std::cout << "transaction " << i << " is missing \"amount\"\n";
|
||||
continue;
|
||||
}
|
||||
std::cout << "transaction " << i << ": " << transaction["amount"].materialize().dump() << '\n';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
transaction 0: 9.99
|
||||
transaction 1 is missing "amount"
|
||||
@@ -0,0 +1,27 @@
|
||||
#include <iostream>
|
||||
#include <nlohmann/json_view.hpp>
|
||||
|
||||
using json_document = nlohmann::json_document;
|
||||
|
||||
int main()
|
||||
{
|
||||
// scan a (possibly large) array of readings for the first one over a
|
||||
// threshold; the loop stops at end() as soon as one is found, and only
|
||||
// the matching reading is ever materialized
|
||||
json_document readings = json_document::parse("[12, 18, 25, 31, 9]");
|
||||
const auto values = readings.root();
|
||||
|
||||
auto it = values.begin();
|
||||
for (; it != values.end(); ++it)
|
||||
{
|
||||
if (it->materialize().get<int>() > 20)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (it != values.end())
|
||||
{
|
||||
std::cout << "first reading over 20: " << it->materialize().dump() << '\n';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
first reading over 20: 25
|
||||
@@ -0,0 +1,29 @@
|
||||
#include <iostream>
|
||||
#include <nlohmann/json_view.hpp>
|
||||
|
||||
using json_document = nlohmann::json_document;
|
||||
|
||||
int main()
|
||||
{
|
||||
// a batch of incoming events; only some carry a "user_id" -- find()
|
||||
// locates it without throwing for the events that turn out to not be
|
||||
// objects, and without materializing an event that does not match
|
||||
json_document batch = json_document::parse(R"(
|
||||
[
|
||||
{"type": "click", "user_id": 42},
|
||||
{"type": "ping"},
|
||||
{"type": "click", "user_id": 7}
|
||||
]
|
||||
)");
|
||||
|
||||
const auto events = batch.root();
|
||||
for (std::size_t i = 0; i < events.size(); ++i)
|
||||
{
|
||||
const auto event = events[i];
|
||||
const auto it = event.find("user_id");
|
||||
if (it != event.end())
|
||||
{
|
||||
std::cout << "user " << it->materialize().dump() << '\n';
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
user 42
|
||||
user 7
|
||||
@@ -0,0 +1,24 @@
|
||||
#include <iostream>
|
||||
#include <nlohmann/json_view.hpp>
|
||||
|
||||
using json_document = nlohmann::json_document;
|
||||
|
||||
int main()
|
||||
{
|
||||
// the build log of a running job; front() reads just the earliest event
|
||||
// without materializing the (possibly long) rest of the log
|
||||
json_document log = json_document::parse(R"(["queued", "started", "compiling", "linking", "done"])");
|
||||
std::cout << log.root().front().materialize().dump() << '\n';
|
||||
|
||||
// an empty log -- front() throws instead of the undefined behavior
|
||||
// basic_json::front() has for an empty array
|
||||
json_document empty_log = json_document::parse("[]");
|
||||
try
|
||||
{
|
||||
static_cast<void>(empty_log.root().front());
|
||||
}
|
||||
catch (const nlohmann::json::invalid_iterator& e)
|
||||
{
|
||||
std::cout << e.what() << '\n';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
"queued"
|
||||
[json.exception.invalid_iterator.214] cannot get value
|
||||
@@ -0,0 +1,22 @@
|
||||
#include <iostream>
|
||||
#include <nlohmann/json_view.hpp>
|
||||
|
||||
using json_document = nlohmann::json_document;
|
||||
|
||||
int main()
|
||||
{
|
||||
// a settings object whose source text records every update to a key as
|
||||
// a duplicate member. items() visits all of them, in document order, so
|
||||
// the update history is visible; operator[] only ever sees the first
|
||||
// one, and materialize() -- like basic_json::parse() -- keeps the last
|
||||
json_document updates = json_document::parse(R"({"retries": 1, "timeout": 30, "retries": 5})");
|
||||
const auto settings = updates.root();
|
||||
|
||||
for (const auto& item : settings.items())
|
||||
{
|
||||
std::cout << item.key() << '=' << item.value().materialize().dump() << '\n';
|
||||
}
|
||||
|
||||
std::cout << "first \"retries\" seen by operator[]: " << settings["retries"].materialize().dump() << '\n';
|
||||
std::cout << "last \"retries\" kept by materialize(): " << settings.materialize()["retries"].dump() << '\n';
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
retries=1
|
||||
timeout=30
|
||||
retries=5
|
||||
first "retries" seen by operator[]: 1
|
||||
last "retries" kept by materialize(): 5
|
||||
@@ -0,0 +1,42 @@
|
||||
#include <iostream>
|
||||
#include <nlohmann/json_view.hpp>
|
||||
|
||||
using json_document = nlohmann::json_document;
|
||||
|
||||
int main()
|
||||
{
|
||||
// two user records from a large API response; only the fields that are
|
||||
// actually read are ever touched, and no nlohmann::json tree is built
|
||||
// for the batch
|
||||
json_document batch = json_document::parse(R"(
|
||||
[
|
||||
{"name": "Alice", "email": "alice@example.com", "tags": ["admin", "ops"]},
|
||||
{"name": "Bob", "tags": []}
|
||||
]
|
||||
)");
|
||||
|
||||
const auto users = batch.root();
|
||||
for (std::size_t i = 0; i < users.size(); ++i)
|
||||
{
|
||||
const auto user = users[i];
|
||||
std::cout << user["name"].materialize().dump();
|
||||
|
||||
// operator[] on a missing object key gives a discarded view -- test
|
||||
// it with a plain "if". The const overload of json::operator[]
|
||||
// would instead be undefined behavior (guarded by an assertion) for
|
||||
// a missing key
|
||||
if (const auto email = user["email"])
|
||||
{
|
||||
std::cout << " <" << email.materialize().dump() << ">";
|
||||
}
|
||||
|
||||
// the same holds for an array index past the end: a discarded view,
|
||||
// not undefined behavior
|
||||
if (const auto first_tag = user["tags"][0])
|
||||
{
|
||||
std::cout << " #" << first_tag.materialize().dump();
|
||||
}
|
||||
|
||||
std::cout << '\n';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
"Alice" <"alice@example.com"> #"admin"
|
||||
"Bob"
|
||||
@@ -0,0 +1,27 @@
|
||||
#include <iostream>
|
||||
#include <nlohmann/json_view.hpp>
|
||||
|
||||
using json_document = nlohmann::json_document;
|
||||
using json_view = nlohmann::json_view;
|
||||
|
||||
int main()
|
||||
{
|
||||
// report why some parsed messages were rejected, using only
|
||||
// type_name() -- no nlohmann::json value is built for the ones that
|
||||
// are wrong
|
||||
json_document good = json_document::parse(R"({"id": 1})");
|
||||
json_document bad = json_document::parse("[1, 2, 3]");
|
||||
json_document failed = json_document::parse("not json", /* allow_exceptions */ false);
|
||||
|
||||
for (const json_view v : { good.root(), bad.root(), failed.root() })
|
||||
{
|
||||
if (v.is_object())
|
||||
{
|
||||
std::cout << "ok\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << "expected an object, got " << v.type_name() << '\n';
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
ok
|
||||
expected an object, got array
|
||||
expected an object, got discarded
|
||||
@@ -22,10 +22,15 @@ actually needed (for a string, only if it contains escape sequences, into one sh
|
||||
[`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 --
|
||||
[`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) -- 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.
|
||||
[`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
|
||||
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.
|
||||
|
||||
## How to use it
|
||||
|
||||
@@ -116,9 +121,26 @@ whenever any of the other conditions above was not met.
|
||||
[`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
|
||||
replay to record them.
|
||||
- **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
|
||||
can do those things with.
|
||||
- **Objects iterate in document order.** [`begin()`](../api/basic_json_view/begin.md)/
|
||||
[`end()`](../api/basic_json_view/end.md) and [`items()`](../api/basic_json_view/items.md) visit an object's
|
||||
members in the order they appear in the source text. `basic_json`'s default `object_t` is a `std::map`, which
|
||||
sorts by key, so iterating a [`materialize()`](../api/basic_json_view/materialize.md)d value can print members in
|
||||
a different order than iterating the view they came from.
|
||||
- **Duplicate keys are visible.** If an object in the source text repeats a key,
|
||||
[`begin()`](../api/basic_json_view/begin.md)/[`end()`](../api/basic_json_view/end.md) and
|
||||
[`items()`](../api/basic_json_view/items.md) visit *every* occurrence (and [`size()`](../api/basic_json_view/size.md)
|
||||
counts all of them), while [`operator[]`](../api/basic_json_view/operator%5B%5D.md),
|
||||
[`at`](../api/basic_json_view/at.md), [`find`](../api/basic_json_view/find.md),
|
||||
[`contains`](../api/basic_json_view/contains.md), and [`count`](../api/basic_json_view/count.md) resolve to the
|
||||
*first* occurrence, since a lookup can stop as soon as it finds a match. `basic_json::parse()` (and so
|
||||
[`materialize()`](../api/basic_json_view/materialize.md)) instead keeps only the *last* value for a repeated key.
|
||||
See the [Notes on duplicate keys](../api/basic_json_view/operator%5B%5D.md#notes) of `operator[]`.
|
||||
- **No [`JSON_DIAGNOSTICS`](../api/macros/json_diagnostics.md) path.** Exceptions thrown by `basic_json_view`'s own
|
||||
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.
|
||||
- **`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 can do those things with.
|
||||
|
||||
## Choosing between `json`, `ordered_json`, the SAX interface, and `json_view`
|
||||
|
||||
|
||||
@@ -246,7 +246,17 @@ nav:
|
||||
- basic_json_view:
|
||||
- 'Overview': api/basic_json_view/index.md
|
||||
- '(Constructor)': api/basic_json_view/basic_json_view.md
|
||||
- 'at': api/basic_json_view/at.md
|
||||
- 'back': api/basic_json_view/back.md
|
||||
- 'begin': api/basic_json_view/begin.md
|
||||
- 'cbegin': api/basic_json_view/cbegin.md
|
||||
- 'cend': api/basic_json_view/cend.md
|
||||
- 'contains': api/basic_json_view/contains.md
|
||||
- 'count': api/basic_json_view/count.md
|
||||
- 'empty': api/basic_json_view/empty.md
|
||||
- 'end': api/basic_json_view/end.md
|
||||
- 'find': api/basic_json_view/find.md
|
||||
- 'front': api/basic_json_view/front.md
|
||||
- 'is_array': api/basic_json_view/is_array.md
|
||||
- 'is_binary': api/basic_json_view/is_binary.md
|
||||
- 'is_boolean': api/basic_json_view/is_boolean.md
|
||||
@@ -260,11 +270,14 @@ nav:
|
||||
- 'is_primitive': api/basic_json_view/is_primitive.md
|
||||
- 'is_string': api/basic_json_view/is_string.md
|
||||
- 'is_structured': api/basic_json_view/is_structured.md
|
||||
- 'items': api/basic_json_view/items.md
|
||||
- 'materialize': api/basic_json_view/materialize.md
|
||||
- 'operator bool': api/basic_json_view/operator_bool.md
|
||||
- 'operator[]': api/basic_json_view/operator[].md
|
||||
- 'size': api/basic_json_view/size.md
|
||||
- 'source_offset': api/basic_json_view/source_offset.md
|
||||
- 'type': api/basic_json_view/type.md
|
||||
- 'type_name': api/basic_json_view/type_name.md
|
||||
- byte_container_with_subtype:
|
||||
- 'Overview': api/byte_container_with_subtype/index.md
|
||||
- '(constructor)': api/byte_container_with_subtype/byte_container_with_subtype.md
|
||||
|
||||
@@ -67,6 +67,39 @@ enum class value_t : std::uint8_t
|
||||
discarded ///< discarded by the parser callback function
|
||||
};
|
||||
|
||||
/*!
|
||||
@brief the name of a JSON type, as returned by basic_json::type_name()
|
||||
|
||||
Used in exception messages; also by code that reports types without a
|
||||
basic_json value at hand (such as the zero-copy view).
|
||||
*/
|
||||
inline const char* value_type_name(const value_t t) noexcept
|
||||
{
|
||||
switch (t)
|
||||
{
|
||||
case value_t::null:
|
||||
return "null";
|
||||
case value_t::object:
|
||||
return "object";
|
||||
case value_t::array:
|
||||
return "array";
|
||||
case value_t::string:
|
||||
return "string";
|
||||
case value_t::boolean:
|
||||
return "boolean";
|
||||
case value_t::binary:
|
||||
return "binary";
|
||||
case value_t::discarded:
|
||||
return "discarded";
|
||||
case value_t::number_integer:
|
||||
case value_t::number_unsigned:
|
||||
case value_t::number_float:
|
||||
return "number";
|
||||
default:
|
||||
return "invalid";
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief comparison operator for JSON types
|
||||
|
||||
|
||||
@@ -0,0 +1,263 @@
|
||||
// __ _____ _____ _____
|
||||
// __| | __| | | | JSON for Modern C++
|
||||
// | | |__ | | | | | | version 3.12.0
|
||||
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2013-2026 Niels Lohmann <https://nlohmann.me>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstddef> // ptrdiff_t, size_t
|
||||
#include <iterator> // forward_iterator_tag
|
||||
#include <string> // string, to_string
|
||||
#include <type_traits> // enable_if
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
#include <nlohmann/detail/view/document_data.hpp>
|
||||
#include <nlohmann/detail/view/errors.hpp>
|
||||
#include <nlohmann/detail/view/macro_scope.hpp>
|
||||
#include <nlohmann/detail/view/node.hpp>
|
||||
|
||||
NLOHMANN_JSON_NAMESPACE_BEGIN
|
||||
namespace detail
|
||||
{
|
||||
namespace view
|
||||
{
|
||||
|
||||
/// the result of view_iterator::operator->: keeps the view alive for the
|
||||
/// duration of the member access
|
||||
template<typename View>
|
||||
class arrow_proxy
|
||||
{
|
||||
public:
|
||||
explicit arrow_proxy(const View& v) noexcept
|
||||
: m_view(v)
|
||||
{}
|
||||
|
||||
const View* operator->() const noexcept
|
||||
{
|
||||
return &m_view;
|
||||
}
|
||||
|
||||
private:
|
||||
View m_view;
|
||||
};
|
||||
|
||||
/*!
|
||||
@brief forward iterator over the elements of a basic_json_view
|
||||
|
||||
Iterates over the elements of an array or the member values of an object, in
|
||||
document order; key() gives the key of an object member. As for basic_json, a
|
||||
primitive value iterates as a range of one element (itself), and null as an
|
||||
empty range.
|
||||
*/
|
||||
template<typename View>
|
||||
class view_iterator
|
||||
{
|
||||
public:
|
||||
using iterator_category = std::forward_iterator_tag;
|
||||
using value_type = View;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using pointer = arrow_proxy<View>;
|
||||
using reference = View;
|
||||
using string_view_t = typename View::string_view_t;
|
||||
|
||||
view_iterator() noexcept = default;
|
||||
|
||||
/// @param[in] pos the element, or the key of the member
|
||||
/// @param[in] object whether pos is a key (its value is the next node)
|
||||
view_iterator(const document_data* d, const node* pos, bool object) noexcept
|
||||
: m_doc(d), m_pos(pos), m_value_offset(object ? 1 : 0)
|
||||
{}
|
||||
|
||||
NLOHMANN_VIEW_ALWAYS_INLINE View operator*() const noexcept
|
||||
{
|
||||
return View(m_doc, m_pos + m_value_offset);
|
||||
}
|
||||
|
||||
pointer operator->() const noexcept
|
||||
{
|
||||
return pointer(**this);
|
||||
}
|
||||
|
||||
NLOHMANN_VIEW_ALWAYS_INLINE view_iterator& operator++() noexcept
|
||||
{
|
||||
m_pos = document_data::after(m_pos + m_value_offset);
|
||||
return *this;
|
||||
}
|
||||
|
||||
view_iterator operator++(int) noexcept
|
||||
{
|
||||
const view_iterator r = *this;
|
||||
++*this;
|
||||
return r;
|
||||
}
|
||||
|
||||
friend bool operator==(const view_iterator& a, const view_iterator& b) noexcept
|
||||
{
|
||||
return a.m_pos == b.m_pos;
|
||||
}
|
||||
|
||||
friend bool operator!=(const view_iterator& a, const view_iterator& b) noexcept
|
||||
{
|
||||
return a.m_pos != b.m_pos;
|
||||
}
|
||||
|
||||
/// the key of the current object member; throws invalid_iterator.207 for
|
||||
/// other iterators, like basic_json's iterators
|
||||
string_view_t key() const
|
||||
{
|
||||
if (NLOHMANN_VIEW_UNLIKELY(m_value_offset == 0))
|
||||
{
|
||||
throw_invalid_iterator(207, "cannot use key() for non-object iterators");
|
||||
}
|
||||
return string_view_t(m_doc->str(*m_pos), m_pos->len);
|
||||
}
|
||||
|
||||
View value() const noexcept
|
||||
{
|
||||
return **this;
|
||||
}
|
||||
|
||||
/// whether the iterator runs over the members of an object
|
||||
bool is_object_iterator() const noexcept
|
||||
{
|
||||
return m_value_offset != 0;
|
||||
}
|
||||
|
||||
private:
|
||||
const document_data* m_doc = nullptr;
|
||||
const node* m_pos = nullptr;
|
||||
std::size_t m_value_offset = 0; ///< 1 for objects: the value follows its key
|
||||
};
|
||||
|
||||
/*!
|
||||
@brief a (key, value) item of basic_json_view::items()
|
||||
|
||||
The key of an array element is its index, as for basic_json::items().
|
||||
Supports structured bindings: for (const auto [key, value] : view.items())
|
||||
*/
|
||||
template<typename View>
|
||||
class view_item
|
||||
{
|
||||
public:
|
||||
using string_view_t = typename View::string_view_t;
|
||||
using iterator = view_iterator<View>;
|
||||
|
||||
view_item(const iterator& it, std::size_t index)
|
||||
: m_it(it)
|
||||
{
|
||||
if (!it.is_object_iterator())
|
||||
{
|
||||
m_index = std::to_string(index);
|
||||
}
|
||||
}
|
||||
|
||||
/// the member key, or the element index for arrays
|
||||
string_view_t key() const
|
||||
{
|
||||
if (m_it.is_object_iterator())
|
||||
{
|
||||
return m_it.key();
|
||||
}
|
||||
return string_view_t(m_index.data(), m_index.size());
|
||||
}
|
||||
|
||||
View value() const noexcept
|
||||
{
|
||||
return *m_it;
|
||||
}
|
||||
|
||||
template<std::size_t N, typename std::enable_if<N == 0, int>::type = 0>
|
||||
string_view_t get() const
|
||||
{
|
||||
return key();
|
||||
}
|
||||
|
||||
template<std::size_t N, typename std::enable_if<N == 1, int>::type = 0>
|
||||
View get() const noexcept
|
||||
{
|
||||
return value();
|
||||
}
|
||||
|
||||
private:
|
||||
iterator m_it;
|
||||
std::string m_index{}; // NOLINT(readability-redundant-member-init)
|
||||
};
|
||||
|
||||
/// the range returned by basic_json_view::items()
|
||||
template<typename View>
|
||||
class view_items
|
||||
{
|
||||
public:
|
||||
using item = view_item<View>;
|
||||
|
||||
class iterator
|
||||
{
|
||||
public:
|
||||
using iterator_category = std::forward_iterator_tag;
|
||||
using value_type = item;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using pointer = void;
|
||||
using reference = item;
|
||||
|
||||
explicit iterator(const view_iterator<View>& it) noexcept
|
||||
: m_it(it)
|
||||
{}
|
||||
|
||||
item operator*() const
|
||||
{
|
||||
return item(m_it, m_index);
|
||||
}
|
||||
|
||||
iterator& operator++() noexcept
|
||||
{
|
||||
++m_it;
|
||||
++m_index;
|
||||
return *this;
|
||||
}
|
||||
|
||||
iterator operator++(int) noexcept
|
||||
{
|
||||
const iterator r = *this;
|
||||
++*this;
|
||||
return r;
|
||||
}
|
||||
|
||||
friend bool operator==(const iterator& a, const iterator& b) noexcept
|
||||
{
|
||||
return a.m_it == b.m_it;
|
||||
}
|
||||
|
||||
friend bool operator!=(const iterator& a, const iterator& b) noexcept
|
||||
{
|
||||
return a.m_it != b.m_it;
|
||||
}
|
||||
|
||||
private:
|
||||
view_iterator<View> m_it;
|
||||
std::size_t m_index = 0;
|
||||
};
|
||||
|
||||
explicit view_items(const View& v) noexcept
|
||||
: m_view(v)
|
||||
{}
|
||||
|
||||
iterator begin() const noexcept
|
||||
{
|
||||
return iterator(m_view.begin());
|
||||
}
|
||||
|
||||
iterator end() const noexcept
|
||||
{
|
||||
return iterator(m_view.end());
|
||||
}
|
||||
|
||||
private:
|
||||
View m_view;
|
||||
};
|
||||
|
||||
} // namespace view
|
||||
} // namespace detail
|
||||
NLOHMANN_JSON_NAMESPACE_END
|
||||
@@ -0,0 +1,139 @@
|
||||
// __ _____ _____ _____
|
||||
// __| | __| | | | JSON for Modern C++
|
||||
// | | |__ | | | | | | version 3.12.0
|
||||
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2013-2026 Niels Lohmann <https://nlohmann.me>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstddef> // size_t
|
||||
#include <cstdint> // uint16_t, uint32_t, uint64_t
|
||||
#include <cstring> // memcmp, memcpy
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
#include <nlohmann/detail/view/document_data.hpp>
|
||||
#include <nlohmann/detail/view/macro_scope.hpp>
|
||||
#include <nlohmann/detail/view/node.hpp>
|
||||
|
||||
NLOHMANN_JSON_NAMESPACE_BEGIN
|
||||
namespace detail
|
||||
{
|
||||
namespace view
|
||||
{
|
||||
|
||||
/// equality test for strings of one length n <= 16: two overlapping loads per
|
||||
/// string (the first and the last 8, 4, or 2 bytes) replace a memcmp, and no
|
||||
/// byte outside [s, s + n) is read
|
||||
class short_key
|
||||
{
|
||||
public:
|
||||
short_key(const unsigned char* k, std::size_t n) noexcept
|
||||
: m_n(n)
|
||||
{
|
||||
load(k, m_a, m_b);
|
||||
}
|
||||
|
||||
NLOHMANN_VIEW_ALWAYS_INLINE bool matches(const unsigned char* s) const noexcept
|
||||
{
|
||||
std::uint64_t a = 0;
|
||||
std::uint64_t b = 0;
|
||||
load(s, a, b);
|
||||
return a == m_a && b == m_b;
|
||||
}
|
||||
|
||||
private:
|
||||
template<typename T>
|
||||
static NLOHMANN_VIEW_ALWAYS_INLINE std::uint64_t load_word(const unsigned char* s) noexcept
|
||||
{
|
||||
T w = 0;
|
||||
std::memcpy(&w, s, sizeof(T));
|
||||
return w;
|
||||
}
|
||||
|
||||
NLOHMANN_VIEW_ALWAYS_INLINE void load(const unsigned char* s, std::uint64_t& a, std::uint64_t& b) const noexcept
|
||||
{
|
||||
if (m_n >= 8)
|
||||
{
|
||||
a = load_word<std::uint64_t>(s);
|
||||
b = load_word<std::uint64_t>(s + m_n - 8);
|
||||
}
|
||||
else if (m_n >= 4)
|
||||
{
|
||||
a = load_word<std::uint32_t>(s);
|
||||
b = load_word<std::uint32_t>(s + m_n - 4);
|
||||
}
|
||||
else if (m_n >= 2)
|
||||
{
|
||||
a = load_word<std::uint16_t>(s);
|
||||
b = load_word<std::uint16_t>(s + m_n - 2);
|
||||
}
|
||||
else
|
||||
{
|
||||
a = m_n == 1 ? s[0] : 0;
|
||||
b = 0;
|
||||
}
|
||||
}
|
||||
|
||||
std::size_t m_n;
|
||||
std::uint64_t m_a = 0;
|
||||
std::uint64_t m_b = 0;
|
||||
};
|
||||
|
||||
/// the key node of the first member of an object with the given key, or
|
||||
/// nullptr; most keys are rejected by their length, from the index alone
|
||||
inline const node* find_member(const document_data& d, const node* object, const char* key, std::size_t n) noexcept
|
||||
{
|
||||
const node* const end = document_data::child_end(object);
|
||||
const auto* const k = reinterpret_cast<const unsigned char*>(key); // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast)
|
||||
if (NLOHMANN_VIEW_LIKELY(n <= 16))
|
||||
{
|
||||
const short_key probe(k, n);
|
||||
for (const node* m = document_data::first_child(object); m != end; m = document_data::after(m + 1))
|
||||
{
|
||||
if (m->len == n && probe.matches(reinterpret_cast<const unsigned char*>(d.str(*m)))) // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast)
|
||||
{
|
||||
return m;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
for (const node* m = document_data::first_child(object); m != end; m = document_data::after(m + 1))
|
||||
{
|
||||
if (m->len == n && std::memcmp(d.str(*m), key, n) == 0)
|
||||
{
|
||||
return m;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/// the element of an array at an index below its size
|
||||
inline const node* element_at(const node* array, std::size_t idx) noexcept
|
||||
{
|
||||
const node* e = document_data::first_child(array);
|
||||
for (std::size_t i = 0; i < idx; ++i)
|
||||
{
|
||||
e = document_data::after(e);
|
||||
}
|
||||
return e;
|
||||
}
|
||||
|
||||
/// the last element of a non-empty array, or the key of the last member of a
|
||||
/// non-empty object
|
||||
inline const node* last_child(const node* container) noexcept
|
||||
{
|
||||
const std::size_t value_offset = container->kind == static_cast<std::uint8_t>(value_t::object) ? 1 : 0;
|
||||
const node* const end = document_data::child_end(container);
|
||||
const node* last = document_data::first_child(container);
|
||||
for (const node* c = document_data::after(last + value_offset); c != end; c = document_data::after(c + value_offset))
|
||||
{
|
||||
last = c;
|
||||
}
|
||||
return last;
|
||||
}
|
||||
|
||||
} // namespace view
|
||||
} // namespace detail
|
||||
NLOHMANN_JSON_NAMESPACE_END
|
||||
@@ -5067,29 +5067,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
JSON_HEDLEY_RETURNS_NON_NULL
|
||||
const char* type_name() const noexcept
|
||||
{
|
||||
switch (m_data.m_type)
|
||||
{
|
||||
case value_t::null:
|
||||
return "null";
|
||||
case value_t::object:
|
||||
return "object";
|
||||
case value_t::array:
|
||||
return "array";
|
||||
case value_t::string:
|
||||
return "string";
|
||||
case value_t::boolean:
|
||||
return "boolean";
|
||||
case value_t::binary:
|
||||
return "binary";
|
||||
case value_t::discarded:
|
||||
return "discarded";
|
||||
case value_t::number_integer:
|
||||
case value_t::number_unsigned:
|
||||
case value_t::number_float:
|
||||
return "number";
|
||||
default:
|
||||
return "invalid";
|
||||
}
|
||||
return detail::value_type_name(m_data.m_type);
|
||||
}
|
||||
|
||||
JSON_PRIVATE_UNLESS_TESTED:
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
#include <iterator> // distance, input_iterator_tag, iterator_traits
|
||||
#include <memory> // unique_ptr
|
||||
#include <string> // string
|
||||
#include <tuple> // tuple_element, tuple_size
|
||||
#include <type_traits> // enable_if, integral_constant, is_base_of, is_integral, is_same, remove_cv, remove_extent
|
||||
#include <utility> // forward, move
|
||||
|
||||
@@ -43,6 +44,8 @@
|
||||
#include <nlohmann/detail/view/document_data.hpp>
|
||||
#include <nlohmann/detail/view/errors.hpp>
|
||||
#include <nlohmann/detail/view/input.hpp>
|
||||
#include <nlohmann/detail/view/iterator.hpp>
|
||||
#include <nlohmann/detail/view/lookup.hpp>
|
||||
#include <nlohmann/detail/view/macro_scope.hpp>
|
||||
#include <nlohmann/detail/view/materialize.hpp>
|
||||
#include <nlohmann/detail/view/node.hpp>
|
||||
@@ -75,6 +78,11 @@ class basic_json_view
|
||||
using size_type = std::size_t;
|
||||
/// std::string_view from C++17 on
|
||||
using string_view_t = detail::view::string_ref;
|
||||
/// forward iterator over elements (arrays) or member values (objects)
|
||||
using iterator = detail::view::view_iterator<basic_json_view>;
|
||||
using const_iterator = iterator;
|
||||
/// a (key, value) item of items()
|
||||
using item = detail::view::view_item<basic_json_view>;
|
||||
|
||||
/// an invalid view (type() == value_t::discarded)
|
||||
basic_json_view() noexcept = default;
|
||||
@@ -162,6 +170,12 @@ class basic_json_view
|
||||
return m_node != nullptr;
|
||||
}
|
||||
|
||||
/// the name of the type, as basic_json::type_name()
|
||||
const char* type_name() const noexcept
|
||||
{
|
||||
return detail::value_type_name(type());
|
||||
}
|
||||
|
||||
//////////////
|
||||
// capacity //
|
||||
//////////////
|
||||
@@ -211,6 +225,219 @@ class basic_json_view
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////
|
||||
// element access //
|
||||
////////////////////
|
||||
|
||||
/// the value of the member with this key (the first one, should the key
|
||||
/// occur more than once); a discarded view if there is none. Throws
|
||||
/// type_error.305 if this is not an object.
|
||||
NLOHMANN_VIEW_ALWAYS_INLINE basic_json_view operator[](string_view_t key) const
|
||||
{
|
||||
if (NLOHMANN_VIEW_UNLIKELY(!is_object()))
|
||||
{
|
||||
detail::view::throw_type_error(305, "cannot use operator[] with a string argument with ", type_name());
|
||||
}
|
||||
return lookup(key);
|
||||
}
|
||||
|
||||
basic_json_view operator[](const char* key) const
|
||||
{
|
||||
return operator[](string_view_t(key));
|
||||
}
|
||||
|
||||
basic_json_view operator[](const string_t& key) const
|
||||
{
|
||||
return operator[](string_view_t(key.data(), key.size()));
|
||||
}
|
||||
|
||||
/// the element at this index; a discarded view if the index is out of
|
||||
/// range. Throws type_error.305 if this is not an array.
|
||||
basic_json_view operator[](size_type idx) const
|
||||
{
|
||||
if (NLOHMANN_VIEW_UNLIKELY(!is_array()))
|
||||
{
|
||||
detail::view::throw_type_error(305, "cannot use operator[] with a numeric argument with ", type_name());
|
||||
}
|
||||
return idx < m_node->len ? basic_json_view(m_doc, detail::view::element_at(m_node, idx)) : basic_json_view();
|
||||
}
|
||||
|
||||
/// (an int argument would be ambiguous between size_type and const char*)
|
||||
basic_json_view operator[](int idx) const
|
||||
{
|
||||
return operator[](static_cast<size_type>(idx));
|
||||
}
|
||||
|
||||
/// the value of the member with this key (the first one, should the key
|
||||
/// occur more than once). Throws type_error.304 if this is not an object,
|
||||
/// and out_of_range.403 if there is no such member.
|
||||
basic_json_view at(string_view_t key) const
|
||||
{
|
||||
if (NLOHMANN_VIEW_UNLIKELY(!is_object()))
|
||||
{
|
||||
detail::view::throw_type_error(304, "cannot use at() with ", type_name());
|
||||
}
|
||||
const basic_json_view r = lookup(key);
|
||||
if (NLOHMANN_VIEW_UNLIKELY(!r))
|
||||
{
|
||||
detail::view::throw_out_of_range(403, detail::concat("key '", std::string(key.data(), key.size()), "' not found"));
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
basic_json_view at(const char* key) const
|
||||
{
|
||||
return at(string_view_t(key));
|
||||
}
|
||||
|
||||
basic_json_view at(const string_t& key) const
|
||||
{
|
||||
return at(string_view_t(key.data(), key.size()));
|
||||
}
|
||||
|
||||
/// the element at this index. Throws type_error.304 if this is not an
|
||||
/// array, and out_of_range.401 if the index is out of range.
|
||||
basic_json_view at(size_type idx) const
|
||||
{
|
||||
if (NLOHMANN_VIEW_UNLIKELY(!is_array()))
|
||||
{
|
||||
detail::view::throw_type_error(304, "cannot use at() with ", type_name());
|
||||
}
|
||||
if (NLOHMANN_VIEW_UNLIKELY(idx >= m_node->len))
|
||||
{
|
||||
detail::view::throw_out_of_range(401, detail::concat("array index ", std::to_string(idx), " is out of range"));
|
||||
}
|
||||
return basic_json_view(m_doc, detail::view::element_at(m_node, idx));
|
||||
}
|
||||
|
||||
basic_json_view at(int idx) const
|
||||
{
|
||||
return at(static_cast<size_type>(idx));
|
||||
}
|
||||
|
||||
/// the first element or member value; a primitive value itself. Throws
|
||||
/// invalid_iterator.214 for null, discarded views, and empty containers.
|
||||
basic_json_view front() const
|
||||
{
|
||||
const iterator it = begin();
|
||||
if (NLOHMANN_VIEW_UNLIKELY(it == end()))
|
||||
{
|
||||
detail::view::throw_invalid_iterator(214, "cannot get value");
|
||||
}
|
||||
return *it;
|
||||
}
|
||||
|
||||
/// the last element or member value (linear in the size); a primitive
|
||||
/// value itself. Throws invalid_iterator.214 for null, discarded views,
|
||||
/// and empty containers.
|
||||
basic_json_view back() const
|
||||
{
|
||||
if (is_structured() && m_node->len != 0)
|
||||
{
|
||||
return basic_json_view(m_doc, detail::view::last_child(m_node) + (is_object() ? 1 : 0));
|
||||
}
|
||||
return front();
|
||||
}
|
||||
|
||||
////////////
|
||||
// lookup //
|
||||
////////////
|
||||
|
||||
/// an iterator to the member with this key (the first one, should the
|
||||
/// key occur more than once), or end(); end() also for non-objects
|
||||
iterator find(string_view_t key) const
|
||||
{
|
||||
if (!is_object())
|
||||
{
|
||||
return end();
|
||||
}
|
||||
const node* const k = detail::view::find_member(*m_doc, m_node, key.data(), key.size());
|
||||
return k != nullptr ? iterator(m_doc, k, true) : end();
|
||||
}
|
||||
|
||||
iterator find(const char* key) const
|
||||
{
|
||||
return find(string_view_t(key));
|
||||
}
|
||||
|
||||
iterator find(const string_t& key) const
|
||||
{
|
||||
return find(string_view_t(key.data(), key.size()));
|
||||
}
|
||||
|
||||
/// whether this is an object with a member with this key
|
||||
bool contains(string_view_t key) const
|
||||
{
|
||||
return is_object() && detail::view::find_member(*m_doc, m_node, key.data(), key.size()) != nullptr;
|
||||
}
|
||||
|
||||
bool contains(const char* key) const
|
||||
{
|
||||
return contains(string_view_t(key));
|
||||
}
|
||||
|
||||
bool contains(const string_t& key) const
|
||||
{
|
||||
return contains(string_view_t(key.data(), key.size()));
|
||||
}
|
||||
|
||||
/// 1 if this is an object with a member with this key, else 0 (duplicate
|
||||
/// keys count once)
|
||||
size_type count(string_view_t key) const
|
||||
{
|
||||
return contains(key) ? 1 : 0;
|
||||
}
|
||||
|
||||
size_type count(const char* key) const
|
||||
{
|
||||
return count(string_view_t(key));
|
||||
}
|
||||
|
||||
size_type count(const string_t& key) const
|
||||
{
|
||||
return count(string_view_t(key.data(), key.size()));
|
||||
}
|
||||
|
||||
///////////////
|
||||
// iteration //
|
||||
///////////////
|
||||
|
||||
/// the first element or member value, in document order; a primitive
|
||||
/// value is a range of one element (itself), null an empty range
|
||||
NLOHMANN_VIEW_ALWAYS_INLINE iterator begin() const noexcept
|
||||
{
|
||||
if (NLOHMANN_VIEW_LIKELY(is_structured()))
|
||||
{
|
||||
return iterator(m_doc, document_data::first_child(m_node), is_object());
|
||||
}
|
||||
return iterator(m_doc, m_node, false);
|
||||
}
|
||||
|
||||
NLOHMANN_VIEW_ALWAYS_INLINE iterator end() const noexcept
|
||||
{
|
||||
if (NLOHMANN_VIEW_LIKELY(is_structured()))
|
||||
{
|
||||
return iterator(m_doc, document_data::child_end(m_node), is_object());
|
||||
}
|
||||
return iterator(m_doc, (is_null() || is_discarded()) ? m_node : m_node + 1, false);
|
||||
}
|
||||
|
||||
iterator cbegin() const noexcept
|
||||
{
|
||||
return begin();
|
||||
}
|
||||
|
||||
iterator cend() const noexcept
|
||||
{
|
||||
return end();
|
||||
}
|
||||
|
||||
/// (key, value) items; the key of an array element is its index
|
||||
detail::view::view_items<basic_json_view> items() const noexcept
|
||||
{
|
||||
return detail::view::view_items<basic_json_view>(*this);
|
||||
}
|
||||
|
||||
/////////////////
|
||||
// materialize //
|
||||
/////////////////
|
||||
@@ -237,11 +464,20 @@ class basic_json_view
|
||||
|
||||
private:
|
||||
template<typename> friend class basic_json_document;
|
||||
friend iterator;
|
||||
|
||||
basic_json_view(const document_data* d, const node* n) noexcept
|
||||
: m_doc(d), m_node(n)
|
||||
{}
|
||||
|
||||
/// the value of the first member with this key, or a discarded view
|
||||
/// (object required)
|
||||
NLOHMANN_VIEW_ALWAYS_INLINE basic_json_view lookup(string_view_t key) const noexcept
|
||||
{
|
||||
const node* const k = detail::view::find_member(*m_doc, m_node, key.data(), key.size());
|
||||
return k != nullptr ? basic_json_view(m_doc, k + 1) : basic_json_view();
|
||||
}
|
||||
|
||||
const document_data* m_doc = nullptr;
|
||||
const node* m_node = nullptr;
|
||||
};
|
||||
@@ -587,6 +823,31 @@ using ordered_json_view = basic_json_view<ordered_json>;
|
||||
|
||||
NLOHMANN_JSON_NAMESPACE_END
|
||||
|
||||
// tuple protocol for the items of basic_json_view::items() (structured bindings)
|
||||
namespace std // NOLINT(cert-dcl58-cpp)
|
||||
{
|
||||
|
||||
#if defined(__clang__)
|
||||
// Fix: https://github.com/nlohmann/json/issues/1401
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wmismatched-tags"
|
||||
#endif
|
||||
template<typename View>
|
||||
class tuple_size<::nlohmann::detail::view::view_item<View>> // NOLINT(cert-dcl58-cpp)
|
||||
: public std::integral_constant<std::size_t, 2> {};
|
||||
|
||||
template<std::size_t N, typename View>
|
||||
class tuple_element<N, ::nlohmann::detail::view::view_item<View>> // NOLINT(cert-dcl58-cpp)
|
||||
{
|
||||
public:
|
||||
using type = decltype(std::declval<::nlohmann::detail::view::view_item<View>>().template get<N>());
|
||||
};
|
||||
#if defined(__clang__)
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
|
||||
} // namespace std
|
||||
|
||||
#include <nlohmann/detail/view/macro_unscope.hpp>
|
||||
|
||||
#endif // INCLUDE_NLOHMANN_JSON_VIEW_HPP_
|
||||
|
||||
@@ -3381,6 +3381,39 @@ enum class value_t : std::uint8_t
|
||||
discarded ///< discarded by the parser callback function
|
||||
};
|
||||
|
||||
/*!
|
||||
@brief the name of a JSON type, as returned by basic_json::type_name()
|
||||
|
||||
Used in exception messages; also by code that reports types without a
|
||||
basic_json value at hand (such as the zero-copy view).
|
||||
*/
|
||||
inline const char* value_type_name(const value_t t) noexcept
|
||||
{
|
||||
switch (t)
|
||||
{
|
||||
case value_t::null:
|
||||
return "null";
|
||||
case value_t::object:
|
||||
return "object";
|
||||
case value_t::array:
|
||||
return "array";
|
||||
case value_t::string:
|
||||
return "string";
|
||||
case value_t::boolean:
|
||||
return "boolean";
|
||||
case value_t::binary:
|
||||
return "binary";
|
||||
case value_t::discarded:
|
||||
return "discarded";
|
||||
case value_t::number_integer:
|
||||
case value_t::number_unsigned:
|
||||
case value_t::number_float:
|
||||
return "number";
|
||||
default:
|
||||
return "invalid";
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief comparison operator for JSON types
|
||||
|
||||
@@ -32023,29 +32056,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
JSON_HEDLEY_RETURNS_NON_NULL
|
||||
const char* type_name() const noexcept
|
||||
{
|
||||
switch (m_data.m_type)
|
||||
{
|
||||
case value_t::null:
|
||||
return "null";
|
||||
case value_t::object:
|
||||
return "object";
|
||||
case value_t::array:
|
||||
return "array";
|
||||
case value_t::string:
|
||||
return "string";
|
||||
case value_t::boolean:
|
||||
return "boolean";
|
||||
case value_t::binary:
|
||||
return "binary";
|
||||
case value_t::discarded:
|
||||
return "discarded";
|
||||
case value_t::number_integer:
|
||||
case value_t::number_unsigned:
|
||||
case value_t::number_float:
|
||||
return "number";
|
||||
default:
|
||||
return "invalid";
|
||||
}
|
||||
return detail::value_type_name(m_data.m_type);
|
||||
}
|
||||
|
||||
JSON_PRIVATE_UNLESS_TESTED:
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
#include <iterator> // distance, input_iterator_tag, iterator_traits
|
||||
#include <memory> // unique_ptr
|
||||
#include <string> // string
|
||||
#include <tuple> // tuple_element, tuple_size
|
||||
#include <type_traits> // enable_if, integral_constant, is_base_of, is_integral, is_same, remove_cv, remove_extent
|
||||
#include <utility> // forward, move
|
||||
|
||||
@@ -1742,6 +1743,419 @@ std::string collect_adapter(Adapter ia)
|
||||
} // namespace detail
|
||||
NLOHMANN_JSON_NAMESPACE_END
|
||||
|
||||
// #include <nlohmann/detail/view/iterator.hpp>
|
||||
// __ _____ _____ _____
|
||||
// __| | __| | | | JSON for Modern C++
|
||||
// | | |__ | | | | | | version 3.12.0
|
||||
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2013-2026 Niels Lohmann <https://nlohmann.me>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
|
||||
|
||||
#include <cstddef> // ptrdiff_t, size_t
|
||||
#include <iterator> // forward_iterator_tag
|
||||
#include <string> // string, to_string
|
||||
#include <type_traits> // enable_if
|
||||
|
||||
// #include <nlohmann/json.hpp>
|
||||
// #include <nlohmann/detail/view/document_data.hpp>
|
||||
|
||||
// #include <nlohmann/detail/view/errors.hpp>
|
||||
|
||||
// #include <nlohmann/detail/view/macro_scope.hpp>
|
||||
|
||||
// #include <nlohmann/detail/view/node.hpp>
|
||||
|
||||
|
||||
NLOHMANN_JSON_NAMESPACE_BEGIN
|
||||
namespace detail
|
||||
{
|
||||
namespace view
|
||||
{
|
||||
|
||||
/// the result of view_iterator::operator->: keeps the view alive for the
|
||||
/// duration of the member access
|
||||
template<typename View>
|
||||
class arrow_proxy
|
||||
{
|
||||
public:
|
||||
explicit arrow_proxy(const View& v) noexcept
|
||||
: m_view(v)
|
||||
{}
|
||||
|
||||
const View* operator->() const noexcept
|
||||
{
|
||||
return &m_view;
|
||||
}
|
||||
|
||||
private:
|
||||
View m_view;
|
||||
};
|
||||
|
||||
/*!
|
||||
@brief forward iterator over the elements of a basic_json_view
|
||||
|
||||
Iterates over the elements of an array or the member values of an object, in
|
||||
document order; key() gives the key of an object member. As for basic_json, a
|
||||
primitive value iterates as a range of one element (itself), and null as an
|
||||
empty range.
|
||||
*/
|
||||
template<typename View>
|
||||
class view_iterator
|
||||
{
|
||||
public:
|
||||
using iterator_category = std::forward_iterator_tag;
|
||||
using value_type = View;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using pointer = arrow_proxy<View>;
|
||||
using reference = View;
|
||||
using string_view_t = typename View::string_view_t;
|
||||
|
||||
view_iterator() noexcept = default;
|
||||
|
||||
/// @param[in] pos the element, or the key of the member
|
||||
/// @param[in] object whether pos is a key (its value is the next node)
|
||||
view_iterator(const document_data* d, const node* pos, bool object) noexcept
|
||||
: m_doc(d), m_pos(pos), m_value_offset(object ? 1 : 0)
|
||||
{}
|
||||
|
||||
NLOHMANN_VIEW_ALWAYS_INLINE View operator*() const noexcept
|
||||
{
|
||||
return View(m_doc, m_pos + m_value_offset);
|
||||
}
|
||||
|
||||
pointer operator->() const noexcept
|
||||
{
|
||||
return pointer(**this);
|
||||
}
|
||||
|
||||
NLOHMANN_VIEW_ALWAYS_INLINE view_iterator& operator++() noexcept
|
||||
{
|
||||
m_pos = document_data::after(m_pos + m_value_offset);
|
||||
return *this;
|
||||
}
|
||||
|
||||
view_iterator operator++(int) noexcept
|
||||
{
|
||||
const view_iterator r = *this;
|
||||
++*this;
|
||||
return r;
|
||||
}
|
||||
|
||||
friend bool operator==(const view_iterator& a, const view_iterator& b) noexcept
|
||||
{
|
||||
return a.m_pos == b.m_pos;
|
||||
}
|
||||
|
||||
friend bool operator!=(const view_iterator& a, const view_iterator& b) noexcept
|
||||
{
|
||||
return a.m_pos != b.m_pos;
|
||||
}
|
||||
|
||||
/// the key of the current object member; throws invalid_iterator.207 for
|
||||
/// other iterators, like basic_json's iterators
|
||||
string_view_t key() const
|
||||
{
|
||||
if (NLOHMANN_VIEW_UNLIKELY(m_value_offset == 0))
|
||||
{
|
||||
throw_invalid_iterator(207, "cannot use key() for non-object iterators");
|
||||
}
|
||||
return string_view_t(m_doc->str(*m_pos), m_pos->len);
|
||||
}
|
||||
|
||||
View value() const noexcept
|
||||
{
|
||||
return **this;
|
||||
}
|
||||
|
||||
/// whether the iterator runs over the members of an object
|
||||
bool is_object_iterator() const noexcept
|
||||
{
|
||||
return m_value_offset != 0;
|
||||
}
|
||||
|
||||
private:
|
||||
const document_data* m_doc = nullptr;
|
||||
const node* m_pos = nullptr;
|
||||
std::size_t m_value_offset = 0; ///< 1 for objects: the value follows its key
|
||||
};
|
||||
|
||||
/*!
|
||||
@brief a (key, value) item of basic_json_view::items()
|
||||
|
||||
The key of an array element is its index, as for basic_json::items().
|
||||
Supports structured bindings: for (const auto [key, value] : view.items())
|
||||
*/
|
||||
template<typename View>
|
||||
class view_item
|
||||
{
|
||||
public:
|
||||
using string_view_t = typename View::string_view_t;
|
||||
using iterator = view_iterator<View>;
|
||||
|
||||
view_item(const iterator& it, std::size_t index)
|
||||
: m_it(it)
|
||||
{
|
||||
if (!it.is_object_iterator())
|
||||
{
|
||||
m_index = std::to_string(index);
|
||||
}
|
||||
}
|
||||
|
||||
/// the member key, or the element index for arrays
|
||||
string_view_t key() const
|
||||
{
|
||||
if (m_it.is_object_iterator())
|
||||
{
|
||||
return m_it.key();
|
||||
}
|
||||
return string_view_t(m_index.data(), m_index.size());
|
||||
}
|
||||
|
||||
View value() const noexcept
|
||||
{
|
||||
return *m_it;
|
||||
}
|
||||
|
||||
template<std::size_t N, typename std::enable_if<N == 0, int>::type = 0>
|
||||
string_view_t get() const
|
||||
{
|
||||
return key();
|
||||
}
|
||||
|
||||
template<std::size_t N, typename std::enable_if<N == 1, int>::type = 0>
|
||||
View get() const noexcept
|
||||
{
|
||||
return value();
|
||||
}
|
||||
|
||||
private:
|
||||
iterator m_it;
|
||||
std::string m_index{}; // NOLINT(readability-redundant-member-init)
|
||||
};
|
||||
|
||||
/// the range returned by basic_json_view::items()
|
||||
template<typename View>
|
||||
class view_items
|
||||
{
|
||||
public:
|
||||
using item = view_item<View>;
|
||||
|
||||
class iterator
|
||||
{
|
||||
public:
|
||||
using iterator_category = std::forward_iterator_tag;
|
||||
using value_type = item;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using pointer = void;
|
||||
using reference = item;
|
||||
|
||||
explicit iterator(const view_iterator<View>& it) noexcept
|
||||
: m_it(it)
|
||||
{}
|
||||
|
||||
item operator*() const
|
||||
{
|
||||
return item(m_it, m_index);
|
||||
}
|
||||
|
||||
iterator& operator++() noexcept
|
||||
{
|
||||
++m_it;
|
||||
++m_index;
|
||||
return *this;
|
||||
}
|
||||
|
||||
iterator operator++(int) noexcept
|
||||
{
|
||||
const iterator r = *this;
|
||||
++*this;
|
||||
return r;
|
||||
}
|
||||
|
||||
friend bool operator==(const iterator& a, const iterator& b) noexcept
|
||||
{
|
||||
return a.m_it == b.m_it;
|
||||
}
|
||||
|
||||
friend bool operator!=(const iterator& a, const iterator& b) noexcept
|
||||
{
|
||||
return a.m_it != b.m_it;
|
||||
}
|
||||
|
||||
private:
|
||||
view_iterator<View> m_it;
|
||||
std::size_t m_index = 0;
|
||||
};
|
||||
|
||||
explicit view_items(const View& v) noexcept
|
||||
: m_view(v)
|
||||
{}
|
||||
|
||||
iterator begin() const noexcept
|
||||
{
|
||||
return iterator(m_view.begin());
|
||||
}
|
||||
|
||||
iterator end() const noexcept
|
||||
{
|
||||
return iterator(m_view.end());
|
||||
}
|
||||
|
||||
private:
|
||||
View m_view;
|
||||
};
|
||||
|
||||
} // namespace view
|
||||
} // namespace detail
|
||||
NLOHMANN_JSON_NAMESPACE_END
|
||||
|
||||
// #include <nlohmann/detail/view/lookup.hpp>
|
||||
// __ _____ _____ _____
|
||||
// __| | __| | | | JSON for Modern C++
|
||||
// | | |__ | | | | | | version 3.12.0
|
||||
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2013-2026 Niels Lohmann <https://nlohmann.me>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
|
||||
|
||||
#include <cstddef> // size_t
|
||||
#include <cstdint> // uint16_t, uint32_t, uint64_t
|
||||
#include <cstring> // memcmp, memcpy
|
||||
|
||||
// #include <nlohmann/json.hpp>
|
||||
// #include <nlohmann/detail/view/document_data.hpp>
|
||||
|
||||
// #include <nlohmann/detail/view/macro_scope.hpp>
|
||||
|
||||
// #include <nlohmann/detail/view/node.hpp>
|
||||
|
||||
|
||||
NLOHMANN_JSON_NAMESPACE_BEGIN
|
||||
namespace detail
|
||||
{
|
||||
namespace view
|
||||
{
|
||||
|
||||
/// equality test for strings of one length n <= 16: two overlapping loads per
|
||||
/// string (the first and the last 8, 4, or 2 bytes) replace a memcmp, and no
|
||||
/// byte outside [s, s + n) is read
|
||||
class short_key
|
||||
{
|
||||
public:
|
||||
short_key(const unsigned char* k, std::size_t n) noexcept
|
||||
: m_n(n)
|
||||
{
|
||||
load(k, m_a, m_b);
|
||||
}
|
||||
|
||||
NLOHMANN_VIEW_ALWAYS_INLINE bool matches(const unsigned char* s) const noexcept
|
||||
{
|
||||
std::uint64_t a = 0;
|
||||
std::uint64_t b = 0;
|
||||
load(s, a, b);
|
||||
return a == m_a && b == m_b;
|
||||
}
|
||||
|
||||
private:
|
||||
template<typename T>
|
||||
static NLOHMANN_VIEW_ALWAYS_INLINE std::uint64_t load_word(const unsigned char* s) noexcept
|
||||
{
|
||||
T w = 0;
|
||||
std::memcpy(&w, s, sizeof(T));
|
||||
return w;
|
||||
}
|
||||
|
||||
NLOHMANN_VIEW_ALWAYS_INLINE void load(const unsigned char* s, std::uint64_t& a, std::uint64_t& b) const noexcept
|
||||
{
|
||||
if (m_n >= 8)
|
||||
{
|
||||
a = load_word<std::uint64_t>(s);
|
||||
b = load_word<std::uint64_t>(s + m_n - 8);
|
||||
}
|
||||
else if (m_n >= 4)
|
||||
{
|
||||
a = load_word<std::uint32_t>(s);
|
||||
b = load_word<std::uint32_t>(s + m_n - 4);
|
||||
}
|
||||
else if (m_n >= 2)
|
||||
{
|
||||
a = load_word<std::uint16_t>(s);
|
||||
b = load_word<std::uint16_t>(s + m_n - 2);
|
||||
}
|
||||
else
|
||||
{
|
||||
a = m_n == 1 ? s[0] : 0;
|
||||
b = 0;
|
||||
}
|
||||
}
|
||||
|
||||
std::size_t m_n;
|
||||
std::uint64_t m_a = 0;
|
||||
std::uint64_t m_b = 0;
|
||||
};
|
||||
|
||||
/// the key node of the first member of an object with the given key, or
|
||||
/// nullptr; most keys are rejected by their length, from the index alone
|
||||
inline const node* find_member(const document_data& d, const node* object, const char* key, std::size_t n) noexcept
|
||||
{
|
||||
const node* const end = document_data::child_end(object);
|
||||
const auto* const k = reinterpret_cast<const unsigned char*>(key); // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast)
|
||||
if (NLOHMANN_VIEW_LIKELY(n <= 16))
|
||||
{
|
||||
const short_key probe(k, n);
|
||||
for (const node* m = document_data::first_child(object); m != end; m = document_data::after(m + 1))
|
||||
{
|
||||
if (m->len == n && probe.matches(reinterpret_cast<const unsigned char*>(d.str(*m)))) // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast)
|
||||
{
|
||||
return m;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
for (const node* m = document_data::first_child(object); m != end; m = document_data::after(m + 1))
|
||||
{
|
||||
if (m->len == n && std::memcmp(d.str(*m), key, n) == 0)
|
||||
{
|
||||
return m;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/// the element of an array at an index below its size
|
||||
inline const node* element_at(const node* array, std::size_t idx) noexcept
|
||||
{
|
||||
const node* e = document_data::first_child(array);
|
||||
for (std::size_t i = 0; i < idx; ++i)
|
||||
{
|
||||
e = document_data::after(e);
|
||||
}
|
||||
return e;
|
||||
}
|
||||
|
||||
/// the last element of a non-empty array, or the key of the last member of a
|
||||
/// non-empty object
|
||||
inline const node* last_child(const node* container) noexcept
|
||||
{
|
||||
const std::size_t value_offset = container->kind == static_cast<std::uint8_t>(value_t::object) ? 1 : 0;
|
||||
const node* const end = document_data::child_end(container);
|
||||
const node* last = document_data::first_child(container);
|
||||
for (const node* c = document_data::after(last + value_offset); c != end; c = document_data::after(c + value_offset))
|
||||
{
|
||||
last = c;
|
||||
}
|
||||
return last;
|
||||
}
|
||||
|
||||
} // namespace view
|
||||
} // namespace detail
|
||||
NLOHMANN_JSON_NAMESPACE_END
|
||||
|
||||
// #include <nlohmann/detail/view/macro_scope.hpp>
|
||||
|
||||
// #include <nlohmann/detail/view/materialize.hpp>
|
||||
@@ -2100,6 +2514,11 @@ class basic_json_view
|
||||
using size_type = std::size_t;
|
||||
/// std::string_view from C++17 on
|
||||
using string_view_t = detail::view::string_ref;
|
||||
/// forward iterator over elements (arrays) or member values (objects)
|
||||
using iterator = detail::view::view_iterator<basic_json_view>;
|
||||
using const_iterator = iterator;
|
||||
/// a (key, value) item of items()
|
||||
using item = detail::view::view_item<basic_json_view>;
|
||||
|
||||
/// an invalid view (type() == value_t::discarded)
|
||||
basic_json_view() noexcept = default;
|
||||
@@ -2187,6 +2606,12 @@ class basic_json_view
|
||||
return m_node != nullptr;
|
||||
}
|
||||
|
||||
/// the name of the type, as basic_json::type_name()
|
||||
const char* type_name() const noexcept
|
||||
{
|
||||
return detail::value_type_name(type());
|
||||
}
|
||||
|
||||
//////////////
|
||||
// capacity //
|
||||
//////////////
|
||||
@@ -2236,6 +2661,219 @@ class basic_json_view
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////
|
||||
// element access //
|
||||
////////////////////
|
||||
|
||||
/// the value of the member with this key (the first one, should the key
|
||||
/// occur more than once); a discarded view if there is none. Throws
|
||||
/// type_error.305 if this is not an object.
|
||||
NLOHMANN_VIEW_ALWAYS_INLINE basic_json_view operator[](string_view_t key) const
|
||||
{
|
||||
if (NLOHMANN_VIEW_UNLIKELY(!is_object()))
|
||||
{
|
||||
detail::view::throw_type_error(305, "cannot use operator[] with a string argument with ", type_name());
|
||||
}
|
||||
return lookup(key);
|
||||
}
|
||||
|
||||
basic_json_view operator[](const char* key) const
|
||||
{
|
||||
return operator[](string_view_t(key));
|
||||
}
|
||||
|
||||
basic_json_view operator[](const string_t& key) const
|
||||
{
|
||||
return operator[](string_view_t(key.data(), key.size()));
|
||||
}
|
||||
|
||||
/// the element at this index; a discarded view if the index is out of
|
||||
/// range. Throws type_error.305 if this is not an array.
|
||||
basic_json_view operator[](size_type idx) const
|
||||
{
|
||||
if (NLOHMANN_VIEW_UNLIKELY(!is_array()))
|
||||
{
|
||||
detail::view::throw_type_error(305, "cannot use operator[] with a numeric argument with ", type_name());
|
||||
}
|
||||
return idx < m_node->len ? basic_json_view(m_doc, detail::view::element_at(m_node, idx)) : basic_json_view();
|
||||
}
|
||||
|
||||
/// (an int argument would be ambiguous between size_type and const char*)
|
||||
basic_json_view operator[](int idx) const
|
||||
{
|
||||
return operator[](static_cast<size_type>(idx));
|
||||
}
|
||||
|
||||
/// the value of the member with this key (the first one, should the key
|
||||
/// occur more than once). Throws type_error.304 if this is not an object,
|
||||
/// and out_of_range.403 if there is no such member.
|
||||
basic_json_view at(string_view_t key) const
|
||||
{
|
||||
if (NLOHMANN_VIEW_UNLIKELY(!is_object()))
|
||||
{
|
||||
detail::view::throw_type_error(304, "cannot use at() with ", type_name());
|
||||
}
|
||||
const basic_json_view r = lookup(key);
|
||||
if (NLOHMANN_VIEW_UNLIKELY(!r))
|
||||
{
|
||||
detail::view::throw_out_of_range(403, detail::concat("key '", std::string(key.data(), key.size()), "' not found"));
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
basic_json_view at(const char* key) const
|
||||
{
|
||||
return at(string_view_t(key));
|
||||
}
|
||||
|
||||
basic_json_view at(const string_t& key) const
|
||||
{
|
||||
return at(string_view_t(key.data(), key.size()));
|
||||
}
|
||||
|
||||
/// the element at this index. Throws type_error.304 if this is not an
|
||||
/// array, and out_of_range.401 if the index is out of range.
|
||||
basic_json_view at(size_type idx) const
|
||||
{
|
||||
if (NLOHMANN_VIEW_UNLIKELY(!is_array()))
|
||||
{
|
||||
detail::view::throw_type_error(304, "cannot use at() with ", type_name());
|
||||
}
|
||||
if (NLOHMANN_VIEW_UNLIKELY(idx >= m_node->len))
|
||||
{
|
||||
detail::view::throw_out_of_range(401, detail::concat("array index ", std::to_string(idx), " is out of range"));
|
||||
}
|
||||
return basic_json_view(m_doc, detail::view::element_at(m_node, idx));
|
||||
}
|
||||
|
||||
basic_json_view at(int idx) const
|
||||
{
|
||||
return at(static_cast<size_type>(idx));
|
||||
}
|
||||
|
||||
/// the first element or member value; a primitive value itself. Throws
|
||||
/// invalid_iterator.214 for null, discarded views, and empty containers.
|
||||
basic_json_view front() const
|
||||
{
|
||||
const iterator it = begin();
|
||||
if (NLOHMANN_VIEW_UNLIKELY(it == end()))
|
||||
{
|
||||
detail::view::throw_invalid_iterator(214, "cannot get value");
|
||||
}
|
||||
return *it;
|
||||
}
|
||||
|
||||
/// the last element or member value (linear in the size); a primitive
|
||||
/// value itself. Throws invalid_iterator.214 for null, discarded views,
|
||||
/// and empty containers.
|
||||
basic_json_view back() const
|
||||
{
|
||||
if (is_structured() && m_node->len != 0)
|
||||
{
|
||||
return basic_json_view(m_doc, detail::view::last_child(m_node) + (is_object() ? 1 : 0));
|
||||
}
|
||||
return front();
|
||||
}
|
||||
|
||||
////////////
|
||||
// lookup //
|
||||
////////////
|
||||
|
||||
/// an iterator to the member with this key (the first one, should the
|
||||
/// key occur more than once), or end(); end() also for non-objects
|
||||
iterator find(string_view_t key) const
|
||||
{
|
||||
if (!is_object())
|
||||
{
|
||||
return end();
|
||||
}
|
||||
const node* const k = detail::view::find_member(*m_doc, m_node, key.data(), key.size());
|
||||
return k != nullptr ? iterator(m_doc, k, true) : end();
|
||||
}
|
||||
|
||||
iterator find(const char* key) const
|
||||
{
|
||||
return find(string_view_t(key));
|
||||
}
|
||||
|
||||
iterator find(const string_t& key) const
|
||||
{
|
||||
return find(string_view_t(key.data(), key.size()));
|
||||
}
|
||||
|
||||
/// whether this is an object with a member with this key
|
||||
bool contains(string_view_t key) const
|
||||
{
|
||||
return is_object() && detail::view::find_member(*m_doc, m_node, key.data(), key.size()) != nullptr;
|
||||
}
|
||||
|
||||
bool contains(const char* key) const
|
||||
{
|
||||
return contains(string_view_t(key));
|
||||
}
|
||||
|
||||
bool contains(const string_t& key) const
|
||||
{
|
||||
return contains(string_view_t(key.data(), key.size()));
|
||||
}
|
||||
|
||||
/// 1 if this is an object with a member with this key, else 0 (duplicate
|
||||
/// keys count once)
|
||||
size_type count(string_view_t key) const
|
||||
{
|
||||
return contains(key) ? 1 : 0;
|
||||
}
|
||||
|
||||
size_type count(const char* key) const
|
||||
{
|
||||
return count(string_view_t(key));
|
||||
}
|
||||
|
||||
size_type count(const string_t& key) const
|
||||
{
|
||||
return count(string_view_t(key.data(), key.size()));
|
||||
}
|
||||
|
||||
///////////////
|
||||
// iteration //
|
||||
///////////////
|
||||
|
||||
/// the first element or member value, in document order; a primitive
|
||||
/// value is a range of one element (itself), null an empty range
|
||||
NLOHMANN_VIEW_ALWAYS_INLINE iterator begin() const noexcept
|
||||
{
|
||||
if (NLOHMANN_VIEW_LIKELY(is_structured()))
|
||||
{
|
||||
return iterator(m_doc, document_data::first_child(m_node), is_object());
|
||||
}
|
||||
return iterator(m_doc, m_node, false);
|
||||
}
|
||||
|
||||
NLOHMANN_VIEW_ALWAYS_INLINE iterator end() const noexcept
|
||||
{
|
||||
if (NLOHMANN_VIEW_LIKELY(is_structured()))
|
||||
{
|
||||
return iterator(m_doc, document_data::child_end(m_node), is_object());
|
||||
}
|
||||
return iterator(m_doc, (is_null() || is_discarded()) ? m_node : m_node + 1, false);
|
||||
}
|
||||
|
||||
iterator cbegin() const noexcept
|
||||
{
|
||||
return begin();
|
||||
}
|
||||
|
||||
iterator cend() const noexcept
|
||||
{
|
||||
return end();
|
||||
}
|
||||
|
||||
/// (key, value) items; the key of an array element is its index
|
||||
detail::view::view_items<basic_json_view> items() const noexcept
|
||||
{
|
||||
return detail::view::view_items<basic_json_view>(*this);
|
||||
}
|
||||
|
||||
/////////////////
|
||||
// materialize //
|
||||
/////////////////
|
||||
@@ -2262,11 +2900,20 @@ class basic_json_view
|
||||
|
||||
private:
|
||||
template<typename> friend class basic_json_document;
|
||||
friend iterator;
|
||||
|
||||
basic_json_view(const document_data* d, const node* n) noexcept
|
||||
: m_doc(d), m_node(n)
|
||||
{}
|
||||
|
||||
/// the value of the first member with this key, or a discarded view
|
||||
/// (object required)
|
||||
NLOHMANN_VIEW_ALWAYS_INLINE basic_json_view lookup(string_view_t key) const noexcept
|
||||
{
|
||||
const node* const k = detail::view::find_member(*m_doc, m_node, key.data(), key.size());
|
||||
return k != nullptr ? basic_json_view(m_doc, k + 1) : basic_json_view();
|
||||
}
|
||||
|
||||
const document_data* m_doc = nullptr;
|
||||
const node* m_node = nullptr;
|
||||
};
|
||||
@@ -2612,6 +3259,31 @@ using ordered_json_view = basic_json_view<ordered_json>;
|
||||
|
||||
NLOHMANN_JSON_NAMESPACE_END
|
||||
|
||||
// tuple protocol for the items of basic_json_view::items() (structured bindings)
|
||||
namespace std // NOLINT(cert-dcl58-cpp)
|
||||
{
|
||||
|
||||
#if defined(__clang__)
|
||||
// Fix: https://github.com/nlohmann/json/issues/1401
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wmismatched-tags"
|
||||
#endif
|
||||
template<typename View>
|
||||
class tuple_size<::nlohmann::detail::view::view_item<View>> // NOLINT(cert-dcl58-cpp)
|
||||
: public std::integral_constant<std::size_t, 2> {};
|
||||
|
||||
template<std::size_t N, typename View>
|
||||
class tuple_element<N, ::nlohmann::detail::view::view_item<View>> // NOLINT(cert-dcl58-cpp)
|
||||
{
|
||||
public:
|
||||
using type = decltype(std::declval<::nlohmann::detail::view::view_item<View>>().template get<N>());
|
||||
};
|
||||
#if defined(__clang__)
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
|
||||
} // namespace std
|
||||
|
||||
// #include <nlohmann/detail/view/macro_unscope.hpp>
|
||||
// __ _____ _____ _____
|
||||
// __| | __| | | | JSON for Modern C++
|
||||
|
||||
@@ -14,8 +14,11 @@ using nlohmann::ordered_json;
|
||||
using nlohmann::json_document;
|
||||
using nlohmann::json_view;
|
||||
using nlohmann::ordered_json_document;
|
||||
using nlohmann::ordered_json_view;
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdint>
|
||||
#include <iterator>
|
||||
#include <list>
|
||||
#include <random>
|
||||
#include <sstream>
|
||||
@@ -367,7 +370,282 @@ TEST_CASE("json_view")
|
||||
const std::string text = R"( {"key": "value", "escaped": "a\nb", "n": 42})";
|
||||
const json_document d = json_document::parse(text);
|
||||
CHECK(d.root().source_offset() == 2);
|
||||
// (element access comes with a later change; the offsets of the
|
||||
// string nodes are checked through materialize() above)
|
||||
CHECK(d.root()["key"].source_offset() == text.find("value"));
|
||||
CHECK(d.root()["escaped"].source_offset() == static_cast<std::size_t>(-1));
|
||||
CHECK(d.root()["n"].source_offset() == text.find("42"));
|
||||
}
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
// the exception a call throws, or "" if it throws none
|
||||
template<typename F>
|
||||
std::string exception_of(F f)
|
||||
{
|
||||
try
|
||||
{
|
||||
f();
|
||||
}
|
||||
catch (const json::exception& e)
|
||||
{
|
||||
return e.what();
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
// compares a view with the ordered_json value materialize() gives for it:
|
||||
// types, sizes, elements and members (by index, key, and iteration), in
|
||||
// document order; duplicate keys are found as their first occurrence
|
||||
void check_access(const ordered_json_view& v, const ordered_json& j)
|
||||
{
|
||||
REQUIRE(v.type() == j.type());
|
||||
CHECK(std::string(v.type_name()) == j.type_name());
|
||||
if (v.is_array())
|
||||
{
|
||||
REQUIRE(v.size() == j.size());
|
||||
std::size_t i = 0;
|
||||
for (const ordered_json_view e : v)
|
||||
{
|
||||
CHECK(v[i].materialize() == e.materialize());
|
||||
CHECK(v.at(i).materialize() == e.materialize());
|
||||
check_access(e, j[i]);
|
||||
++i;
|
||||
}
|
||||
CHECK(i == v.size());
|
||||
CHECK(!v[v.size()]);
|
||||
std::size_t index = 0;
|
||||
for (const auto& item : v.items())
|
||||
{
|
||||
CHECK(item.key() == std::to_string(index));
|
||||
CHECK(item.value().materialize() == j[index]);
|
||||
++index;
|
||||
}
|
||||
if (!v.empty())
|
||||
{
|
||||
CHECK(v.front().materialize() == j.front());
|
||||
CHECK(v.back().materialize() == j.back());
|
||||
}
|
||||
}
|
||||
else if (v.is_object())
|
||||
{
|
||||
std::vector<std::string> keys; // first occurrences, in order
|
||||
std::size_t members = 0;
|
||||
for (auto it = v.begin(); it != v.end(); ++it)
|
||||
{
|
||||
++members;
|
||||
const std::string key(it.key().data(), it.key().size());
|
||||
CHECK(v.contains(key));
|
||||
CHECK(v.count(key) == 1);
|
||||
if (std::find(keys.begin(), keys.end(), key) != keys.end())
|
||||
{
|
||||
continue; // a duplicate: lookups find the first one
|
||||
}
|
||||
keys.push_back(key);
|
||||
CHECK(v.find(key) == it);
|
||||
CHECK(v[key].materialize() == it->materialize());
|
||||
CHECK(v.at(key).materialize() == it.value().materialize());
|
||||
CHECK(v[key.c_str()].materialize() == (*it).materialize());
|
||||
}
|
||||
CHECK(members == v.size());
|
||||
REQUIRE(keys.size() == j.size());
|
||||
std::size_t k = 0;
|
||||
for (const auto& member : j.items())
|
||||
{
|
||||
CHECK(keys[k++] == member.key());
|
||||
}
|
||||
if (keys.size() == members)
|
||||
{
|
||||
// no duplicates: the values are those of the object
|
||||
for (const auto& key : keys)
|
||||
{
|
||||
check_access(v[key], j[key]);
|
||||
}
|
||||
if (!v.empty())
|
||||
{
|
||||
CHECK(v.front().materialize() == j.front());
|
||||
CHECK(v.back().materialize() == j.back());
|
||||
}
|
||||
}
|
||||
CHECK(!v["not a key in the generated documents"]);
|
||||
CHECK(v.find("not a key in the generated documents") == v.end());
|
||||
}
|
||||
else
|
||||
{
|
||||
// a primitive is a range of one element; null is empty
|
||||
CHECK(static_cast<std::size_t>(std::distance(v.begin(), v.end())) == (v.is_null() ? 0u : 1u));
|
||||
if (!v.is_null())
|
||||
{
|
||||
CHECK((*v.begin()).materialize() == j);
|
||||
CHECK(v.front().materialize() == j);
|
||||
CHECK(v.back().materialize() == j);
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
TEST_CASE("json_view element access and iteration")
|
||||
{
|
||||
SECTION("generated documents")
|
||||
{
|
||||
generator g;
|
||||
for (int i = 0; i < 2000; ++i)
|
||||
{
|
||||
std::string text;
|
||||
g.value(text, 0);
|
||||
CAPTURE(text);
|
||||
const ordered_json_document d = ordered_json_document::parse(text);
|
||||
check_access(d.root(), ordered_json::parse(text));
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("keys")
|
||||
{
|
||||
// keys of every length around the 2/4/8/16-byte loads, with escapes
|
||||
std::string text = "{";
|
||||
std::vector<std::string> keys = {"", "x"};
|
||||
for (std::size_t n = 1; n <= 40; ++n)
|
||||
{
|
||||
keys.emplace_back(n, 'k');
|
||||
keys.push_back(std::string(n, 'k') + "x");
|
||||
keys.push_back("x" + std::string(n, 'k'));
|
||||
}
|
||||
for (std::size_t i = 0; i < keys.size(); ++i)
|
||||
{
|
||||
text += (i != 0 ? ",\"" : "\"") + keys[i] + "\":" + std::to_string(i);
|
||||
}
|
||||
text += ",\"esc\\u0061ped\":\"escaped key\"}"; // NOLINT(modernize-raw-string-literal)
|
||||
const json_document d = json_document::parse(text);
|
||||
const json_view root = d.root();
|
||||
for (std::size_t i = 0; i < keys.size(); ++i)
|
||||
{
|
||||
CAPTURE(keys[i]);
|
||||
CHECK(root[keys[i]].materialize() == i);
|
||||
CHECK(root.at(keys[i]).materialize() == i);
|
||||
CHECK(root.find(keys[i]).key() == keys[i]);
|
||||
CHECK(!root.contains(keys[i] + "y"));
|
||||
}
|
||||
CHECK(root["escaped"].materialize() == "escaped key");
|
||||
CHECK(!root.contains("esc\\u0061ped"));
|
||||
#ifdef JSON_HAS_CPP_17
|
||||
CHECK(root[std::string_view("kkk")].materialize() == root["kkk"].materialize());
|
||||
#endif
|
||||
}
|
||||
|
||||
SECTION("duplicate keys: lookups find the first member, iteration all")
|
||||
{
|
||||
const json_document d = json_document::parse(R"({"a":1,"b":2,"a":3})");
|
||||
const json_view v = d.root();
|
||||
CHECK(v.size() == 3);
|
||||
CHECK(v["a"].materialize() == 1);
|
||||
CHECK(v.at("a").materialize() == 1);
|
||||
CHECK(v.find("a") == v.begin());
|
||||
CHECK(v.count("a") == 1);
|
||||
std::string order;
|
||||
for (auto it = v.begin(); it != v.end(); ++it)
|
||||
{
|
||||
order += std::string(it.key().data(), it.key().size()) + it->materialize().dump();
|
||||
}
|
||||
CHECK(order == "a1b2a3");
|
||||
CHECK(v.back().materialize() == 3);
|
||||
CHECK(v.materialize() == json::parse(R"({"a":1,"b":2,"a":3})")); // the last value, as parse()
|
||||
}
|
||||
|
||||
SECTION("errors are those of const basic_json")
|
||||
{
|
||||
for (const char* text :
|
||||
{"null", "true", "42", "-1", "1.5", "\"s\"", "[]", "[1,2]", "{}", "{\"a\":1}"
|
||||
})
|
||||
{
|
||||
CAPTURE(text);
|
||||
const json_document d = json_document::parse(text);
|
||||
const json_view v = d.root();
|
||||
const json j = v.materialize();
|
||||
if (!j.is_object())
|
||||
{
|
||||
CHECK(exception_of([&] { static_cast<void>(v["a"]); }) == exception_of([&] { static_cast<void>(j["a"]); }));
|
||||
}
|
||||
if (!j.is_array())
|
||||
{
|
||||
CHECK(exception_of([&] { static_cast<void>(v[0]); }) == exception_of([&] { static_cast<void>(j[0]); }));
|
||||
}
|
||||
CHECK(exception_of([&] { static_cast<void>(v.at("a")); }) == exception_of([&] { static_cast<void>(j.at("a")); }));
|
||||
CHECK(exception_of([&] { static_cast<void>(v.at("missing")); }) == exception_of([&] { static_cast<void>(j.at("missing")); }));
|
||||
CHECK(exception_of([&] { static_cast<void>(v.at(0)); }) == exception_of([&] { static_cast<void>(j.at(0)); }));
|
||||
CHECK(exception_of([&] { static_cast<void>(v.at(5)); }) == exception_of([&] { static_cast<void>(j.at(5)); }));
|
||||
if (!(j.is_object() && j.empty())) // (key() of an end iterator)
|
||||
{
|
||||
CHECK(exception_of([&] { static_cast<void>(v.begin().key()); }) == exception_of([&] { static_cast<void>(j.begin().key()); }));
|
||||
}
|
||||
if (!j.empty() || j.is_null())
|
||||
{
|
||||
CHECK(exception_of([&] { static_cast<void>(v.front()); }) == exception_of([&] { static_cast<void>(j.front()); }));
|
||||
CHECK(exception_of([&] { static_cast<void>(v.back()); }) == exception_of([&] { static_cast<void>(j.back()); }));
|
||||
}
|
||||
CHECK(v.contains("a") == j.contains("a"));
|
||||
CHECK(v.count("a") == j.count("a"));
|
||||
CHECK((v.find("a") == v.end()) == (j.find("a") == j.end())); // NOLINT(readability-container-contains): find() is what is tested
|
||||
}
|
||||
|
||||
// where basic_json has undefined behavior, the view answers safely
|
||||
const json_document d = json_document::parse(R"({"a":[]})");
|
||||
CHECK(!d.root()["b"]);
|
||||
CHECK(!d.root()["a"][0]);
|
||||
CHECK_THROWS_WITH_AS(d.root()["a"].front(), "[json.exception.invalid_iterator.214] cannot get value", json::invalid_iterator&);
|
||||
CHECK_THROWS_WITH_AS(d.root()["a"].back(), "[json.exception.invalid_iterator.214] cannot get value", json::invalid_iterator&);
|
||||
const json_view invalid;
|
||||
CHECK(invalid.begin() == invalid.end());
|
||||
CHECK(std::string(invalid.type_name()) == "discarded");
|
||||
CHECK_THROWS_WITH_AS(invalid["a"], "[json.exception.type_error.305] cannot use operator[] with a string argument with discarded", json::type_error&);
|
||||
}
|
||||
|
||||
SECTION("iterators")
|
||||
{
|
||||
const json_document d = json_document::parse(R"({"x":[1,{"y":2}],"z":null})");
|
||||
const json_view v = d.root();
|
||||
json_view::iterator it = v.begin();
|
||||
CHECK(it.is_object_iterator());
|
||||
CHECK(it->is_array());
|
||||
CHECK(it->size() == 2);
|
||||
const json_view::iterator previous = it++;
|
||||
CHECK(previous.key() == "x");
|
||||
CHECK(it.key() == "z");
|
||||
CHECK(it.value().is_null());
|
||||
CHECK(++it == v.end());
|
||||
CHECK(v.cbegin() == v.begin());
|
||||
CHECK(v.cend() == v.end());
|
||||
CHECK(!v["x"].begin().is_object_iterator());
|
||||
CHECK(json_view::iterator() == json_view::iterator());
|
||||
// standard algorithms
|
||||
CHECK(std::count_if(v["x"].begin(), v["x"].end(), [](const json_view & e)
|
||||
{
|
||||
return e.is_object();
|
||||
}) == 1);
|
||||
}
|
||||
|
||||
SECTION("items")
|
||||
{
|
||||
const json_document d = json_document::parse(R"({"a":1,"b":[true,false]})");
|
||||
std::string keys;
|
||||
for (const auto& item : d.root().items())
|
||||
{
|
||||
keys += std::string(item.key().data(), item.key().size());
|
||||
CHECK(item.value().materialize() == d.root()[item.key()].materialize());
|
||||
}
|
||||
CHECK(keys == "ab");
|
||||
auto items = d.root()["b"].items();
|
||||
auto first = items.begin();
|
||||
CHECK((*first++).key() == "0");
|
||||
CHECK((*first).key() == "1");
|
||||
CHECK(++first == items.end());
|
||||
#ifdef JSON_HAS_CPP_17
|
||||
std::string pairs;
|
||||
for (const auto [key, value] : d.root().items())
|
||||
{
|
||||
pairs += std::string(key) + "=" + value.materialize().dump() + ";";
|
||||
}
|
||||
CHECK(pairs == "a=1;b=[true,false];");
|
||||
static_assert(std::tuple_size<json_view::item>::value == 2, "");
|
||||
static_assert(std::is_same<std::tuple_element<1, json_view::item>::type, json_view>::value, "");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user