diff --git a/docs/docset/docSet.sql b/docs/docset/docSet.sql
index 7a8184eae..6e5f7001b 100644
--- a/docs/docset/docSet.sql
+++ b/docs/docset/docSet.sql
@@ -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');
diff --git a/docs/mkdocs/docs/api/basic_json/at.md b/docs/mkdocs/docs/api/basic_json/at.md
index 2d1042cc8..798113898 100644
--- a/docs/mkdocs/docs/api/basic_json/at.md
+++ b/docs/mkdocs/docs/api/basic_json/at.md
@@ -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
diff --git a/docs/mkdocs/docs/api/basic_json/back.md b/docs/mkdocs/docs/api/basic_json/back.md
index b717e16e0..685c1c84b 100644
--- a/docs/mkdocs/docs/api/basic_json/back.md
+++ b/docs/mkdocs/docs/api/basic_json/back.md
@@ -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
diff --git a/docs/mkdocs/docs/api/basic_json/begin.md b/docs/mkdocs/docs/api/basic_json/begin.md
index ef623a5ff..288fc7c12 100644
--- a/docs/mkdocs/docs/api/basic_json/begin.md
+++ b/docs/mkdocs/docs/api/basic_json/begin.md
@@ -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.
diff --git a/docs/mkdocs/docs/api/basic_json/cbegin.md b/docs/mkdocs/docs/api/basic_json/cbegin.md
index 06504fee6..876c8a360 100644
--- a/docs/mkdocs/docs/api/basic_json/cbegin.md
+++ b/docs/mkdocs/docs/api/basic_json/cbegin.md
@@ -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.
diff --git a/docs/mkdocs/docs/api/basic_json/cend.md b/docs/mkdocs/docs/api/basic_json/cend.md
index 3f3aa949d..f808173a6 100644
--- a/docs/mkdocs/docs/api/basic_json/cend.md
+++ b/docs/mkdocs/docs/api/basic_json/cend.md
@@ -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.
diff --git a/docs/mkdocs/docs/api/basic_json/contains.md b/docs/mkdocs/docs/api/basic_json/contains.md
index 7f865f83c..3bde577d6 100644
--- a/docs/mkdocs/docs/api/basic_json/contains.md
+++ b/docs/mkdocs/docs/api/basic_json/contains.md
@@ -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
diff --git a/docs/mkdocs/docs/api/basic_json/count.md b/docs/mkdocs/docs/api/basic_json/count.md
index ce51addbd..6c7f4a897 100644
--- a/docs/mkdocs/docs/api/basic_json/count.md
+++ b/docs/mkdocs/docs/api/basic_json/count.md
@@ -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
diff --git a/docs/mkdocs/docs/api/basic_json/end.md b/docs/mkdocs/docs/api/basic_json/end.md
index 179ce9e67..2c2a59ed1 100644
--- a/docs/mkdocs/docs/api/basic_json/end.md
+++ b/docs/mkdocs/docs/api/basic_json/end.md
@@ -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.
diff --git a/docs/mkdocs/docs/api/basic_json/find.md b/docs/mkdocs/docs/api/basic_json/find.md
index 35ff9dcb2..98c3c51ae 100644
--- a/docs/mkdocs/docs/api/basic_json/find.md
+++ b/docs/mkdocs/docs/api/basic_json/find.md
@@ -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
diff --git a/docs/mkdocs/docs/api/basic_json/front.md b/docs/mkdocs/docs/api/basic_json/front.md
index b5fea1135..ef4f0d262 100644
--- a/docs/mkdocs/docs/api/basic_json/front.md
+++ b/docs/mkdocs/docs/api/basic_json/front.md
@@ -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
diff --git a/docs/mkdocs/docs/api/basic_json/items.md b/docs/mkdocs/docs/api/basic_json/items.md
index 3f3d1f2ca..4a772a22a 100644
--- a/docs/mkdocs/docs/api/basic_json/items.md
+++ b/docs/mkdocs/docs/api/basic_json/items.md
@@ -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
diff --git a/docs/mkdocs/docs/api/basic_json/operator[].md b/docs/mkdocs/docs/api/basic_json/operator[].md
index 3195870e4..8b289a276 100644
--- a/docs/mkdocs/docs/api/basic_json/operator[].md
+++ b/docs/mkdocs/docs/api/basic_json/operator[].md
@@ -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
diff --git a/docs/mkdocs/docs/api/basic_json/type_name.md b/docs/mkdocs/docs/api/basic_json/type_name.md
index 2022b8897..385e5b08a 100644
--- a/docs/mkdocs/docs/api/basic_json/type_name.md
+++ b/docs/mkdocs/docs/api/basic_json/type_name.md
@@ -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.
diff --git a/docs/mkdocs/docs/api/basic_json_view/at.md b/docs/mkdocs/docs/api/basic_json_view/at.md
new file mode 100644
index 000000000..2c563232f
--- /dev/null
+++ b/docs/mkdocs/docs/api/basic_json_view/at.md
@@ -0,0 +1,90 @@
+# nlohmann::basic_json_view::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.
diff --git a/docs/mkdocs/docs/api/basic_json_view/back.md b/docs/mkdocs/docs/api/basic_json_view/back.md
new file mode 100644
index 000000000..5ddb1fb35
--- /dev/null
+++ b/docs/mkdocs/docs/api/basic_json_view/back.md
@@ -0,0 +1,64 @@
+# nlohmann::basic_json_view::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.
diff --git a/docs/mkdocs/docs/api/basic_json_view/basic_json_view.md b/docs/mkdocs/docs/api/basic_json_view/basic_json_view.md
index 143ea2bea..031c3b29d 100644
--- a/docs/mkdocs/docs/api/basic_json_view/basic_json_view.md
+++ b/docs/mkdocs/docs/api/basic_json_view/basic_json_view.md
@@ -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
diff --git a/docs/mkdocs/docs/api/basic_json_view/begin.md b/docs/mkdocs/docs/api/basic_json_view/begin.md
new file mode 100644
index 000000000..ae2665ee9
--- /dev/null
+++ b/docs/mkdocs/docs/api/basic_json_view/begin.md
@@ -0,0 +1,61 @@
+# nlohmann::basic_json_view::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.
diff --git a/docs/mkdocs/docs/api/basic_json_view/cbegin.md b/docs/mkdocs/docs/api/basic_json_view/cbegin.md
new file mode 100644
index 000000000..25d17bdad
--- /dev/null
+++ b/docs/mkdocs/docs/api/basic_json_view/cbegin.md
@@ -0,0 +1,49 @@
+# nlohmann::basic_json_view::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.
diff --git a/docs/mkdocs/docs/api/basic_json_view/cend.md b/docs/mkdocs/docs/api/basic_json_view/cend.md
new file mode 100644
index 000000000..6d19530ce
--- /dev/null
+++ b/docs/mkdocs/docs/api/basic_json_view/cend.md
@@ -0,0 +1,49 @@
+# nlohmann::basic_json_view::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.
diff --git a/docs/mkdocs/docs/api/basic_json_view/contains.md b/docs/mkdocs/docs/api/basic_json_view/contains.md
new file mode 100644
index 000000000..e5abc4ffa
--- /dev/null
+++ b/docs/mkdocs/docs/api/basic_json_view/contains.md
@@ -0,0 +1,64 @@
+# nlohmann::basic_json_view::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.
diff --git a/docs/mkdocs/docs/api/basic_json_view/count.md b/docs/mkdocs/docs/api/basic_json_view/count.md
new file mode 100644
index 000000000..6a599477e
--- /dev/null
+++ b/docs/mkdocs/docs/api/basic_json_view/count.md
@@ -0,0 +1,66 @@
+# nlohmann::basic_json_view::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.
diff --git a/docs/mkdocs/docs/api/basic_json_view/end.md b/docs/mkdocs/docs/api/basic_json_view/end.md
new file mode 100644
index 000000000..d0346c049
--- /dev/null
+++ b/docs/mkdocs/docs/api/basic_json_view/end.md
@@ -0,0 +1,54 @@
+# nlohmann::basic_json_view::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.
diff --git a/docs/mkdocs/docs/api/basic_json_view/find.md b/docs/mkdocs/docs/api/basic_json_view/find.md
new file mode 100644
index 000000000..f7ad92e9f
--- /dev/null
+++ b/docs/mkdocs/docs/api/basic_json_view/find.md
@@ -0,0 +1,63 @@
+# nlohmann::basic_json_view::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.
diff --git a/docs/mkdocs/docs/api/basic_json_view/front.md b/docs/mkdocs/docs/api/basic_json_view/front.md
new file mode 100644
index 000000000..c96a35eaf
--- /dev/null
+++ b/docs/mkdocs/docs/api/basic_json_view/front.md
@@ -0,0 +1,61 @@
+# nlohmann::basic_json_view::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.
diff --git a/docs/mkdocs/docs/api/basic_json_view/index.md b/docs/mkdocs/docs/api/basic_json_view/index.md
index 564406667..54e76bd1e 100644
--- a/docs/mkdocs/docs/api/basic_json_view/index.md
+++ b/docs/mkdocs/docs/api/basic_json_view/index.md
@@ -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()`, 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()`, JSON Pointer support, `dump()`, or comparison.
## Template parameters
@@ -41,6 +41,9 @@ element access, iteration, `get()`, 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()`, 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()`, 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
diff --git a/docs/mkdocs/docs/api/basic_json_view/items.md b/docs/mkdocs/docs/api/basic_json_view/items.md
new file mode 100644
index 000000000..d54f8d723
--- /dev/null
+++ b/docs/mkdocs/docs/api/basic_json_view/items.md
@@ -0,0 +1,86 @@
+# nlohmann::basic_json_view::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.
diff --git a/docs/mkdocs/docs/api/basic_json_view/operator[].md b/docs/mkdocs/docs/api/basic_json_view/operator[].md
new file mode 100644
index 000000000..0959b9972
--- /dev/null
+++ b/docs/mkdocs/docs/api/basic_json_view/operator[].md
@@ -0,0 +1,105 @@
+# nlohmann::basic_json_view::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.
diff --git a/docs/mkdocs/docs/api/basic_json_view/size.md b/docs/mkdocs/docs/api/basic_json_view/size.md
index cd354d2f3..1bb0a5822 100644
--- a/docs/mkdocs/docs/api/basic_json_view/size.md
+++ b/docs/mkdocs/docs/api/basic_json_view/size.md
@@ -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
diff --git a/docs/mkdocs/docs/api/basic_json_view/type_name.md b/docs/mkdocs/docs/api/basic_json_view/type_name.md
new file mode 100644
index 000000000..b5bde001d
--- /dev/null
+++ b/docs/mkdocs/docs/api/basic_json_view/type_name.md
@@ -0,0 +1,63 @@
+# nlohmann::basic_json_view::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.
diff --git a/docs/mkdocs/docs/examples/basic_json_view__at.cpp b/docs/mkdocs/docs/examples/basic_json_view__at.cpp
new file mode 100644
index 000000000..1e984c55f
--- /dev/null
+++ b/docs/mkdocs/docs/examples/basic_json_view__at.cpp
@@ -0,0 +1,36 @@
+#include
+#include
+
+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(service.at("port").at(0));
+ }
+ catch (const nlohmann::json::type_error& e)
+ {
+ std::cout << e.what() << '\n';
+ }
+
+ try
+ {
+ static_cast(service.at("timeout"));
+ }
+ catch (const nlohmann::json::out_of_range& e)
+ {
+ std::cout << e.what() << '\n';
+ }
+}
diff --git a/docs/mkdocs/docs/examples/basic_json_view__at.output b/docs/mkdocs/docs/examples/basic_json_view__at.output
new file mode 100644
index 000000000..fe716b135
--- /dev/null
+++ b/docs/mkdocs/docs/examples/basic_json_view__at.output
@@ -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
diff --git a/docs/mkdocs/docs/examples/basic_json_view__back.cpp b/docs/mkdocs/docs/examples/basic_json_view__back.cpp
new file mode 100644
index 000000000..606cb8966
--- /dev/null
+++ b/docs/mkdocs/docs/examples/basic_json_view__back.cpp
@@ -0,0 +1,25 @@
+#include
+#include
+
+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(empty_log.root().back());
+ }
+ catch (const nlohmann::json::invalid_iterator& e)
+ {
+ std::cout << e.what() << '\n';
+ }
+}
diff --git a/docs/mkdocs/docs/examples/basic_json_view__back.output b/docs/mkdocs/docs/examples/basic_json_view__back.output
new file mode 100644
index 000000000..8362099a1
--- /dev/null
+++ b/docs/mkdocs/docs/examples/basic_json_view__back.output
@@ -0,0 +1,2 @@
+"done"
+[json.exception.invalid_iterator.214] cannot get value
diff --git a/docs/mkdocs/docs/examples/basic_json_view__begin.cpp b/docs/mkdocs/docs/examples/basic_json_view__begin.cpp
new file mode 100644
index 000000000..5989ae404
--- /dev/null
+++ b/docs/mkdocs/docs/examples/basic_json_view__begin.cpp
@@ -0,0 +1,18 @@
+#include
+#include
+
+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';
+ }
+}
diff --git a/docs/mkdocs/docs/examples/basic_json_view__begin.output b/docs/mkdocs/docs/examples/basic_json_view__begin.output
new file mode 100644
index 000000000..1c92e0f83
--- /dev/null
+++ b/docs/mkdocs/docs/examples/basic_json_view__begin.output
@@ -0,0 +1,3 @@
+time="10:00:01"
+level="info"
+message="started"
diff --git a/docs/mkdocs/docs/examples/basic_json_view__cbegin.cpp b/docs/mkdocs/docs/examples/basic_json_view__cbegin.cpp
new file mode 100644
index 000000000..811db6267
--- /dev/null
+++ b/docs/mkdocs/docs/examples/basic_json_view__cbegin.cpp
@@ -0,0 +1,24 @@
+#include
+#include
+#include
+
+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();
+ });
+
+ std::cout << sum << '\n';
+}
diff --git a/docs/mkdocs/docs/examples/basic_json_view__cbegin.output b/docs/mkdocs/docs/examples/basic_json_view__cbegin.output
new file mode 100644
index 000000000..e85087aff
--- /dev/null
+++ b/docs/mkdocs/docs/examples/basic_json_view__cbegin.output
@@ -0,0 +1 @@
+31
diff --git a/docs/mkdocs/docs/examples/basic_json_view__cend.cpp b/docs/mkdocs/docs/examples/basic_json_view__cend.cpp
new file mode 100644
index 000000000..2999bd684
--- /dev/null
+++ b/docs/mkdocs/docs/examples/basic_json_view__cend.cpp
@@ -0,0 +1,24 @@
+#include
+#include
+#include
+
+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';
+}
diff --git a/docs/mkdocs/docs/examples/basic_json_view__cend.output b/docs/mkdocs/docs/examples/basic_json_view__cend.output
new file mode 100644
index 000000000..27ba77dda
--- /dev/null
+++ b/docs/mkdocs/docs/examples/basic_json_view__cend.output
@@ -0,0 +1 @@
+true
diff --git a/docs/mkdocs/docs/examples/basic_json_view__contains.cpp b/docs/mkdocs/docs/examples/basic_json_view__contains.cpp
new file mode 100644
index 000000000..e339ee79a
--- /dev/null
+++ b/docs/mkdocs/docs/examples/basic_json_view__contains.cpp
@@ -0,0 +1,30 @@
+#include
+#include
+
+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";
+}
diff --git a/docs/mkdocs/docs/examples/basic_json_view__contains.output b/docs/mkdocs/docs/examples/basic_json_view__contains.output
new file mode 100644
index 000000000..f06576214
--- /dev/null
+++ b/docs/mkdocs/docs/examples/basic_json_view__contains.output
@@ -0,0 +1 @@
+2 of 4 records are retries
diff --git a/docs/mkdocs/docs/examples/basic_json_view__count.cpp b/docs/mkdocs/docs/examples/basic_json_view__count.cpp
new file mode 100644
index 000000000..648142e21
--- /dev/null
+++ b/docs/mkdocs/docs/examples/basic_json_view__count.cpp
@@ -0,0 +1,29 @@
+#include
+#include
+
+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';
+ }
+}
diff --git a/docs/mkdocs/docs/examples/basic_json_view__count.output b/docs/mkdocs/docs/examples/basic_json_view__count.output
new file mode 100644
index 000000000..a6344a13b
--- /dev/null
+++ b/docs/mkdocs/docs/examples/basic_json_view__count.output
@@ -0,0 +1,2 @@
+transaction 0: 9.99
+transaction 1 is missing "amount"
diff --git a/docs/mkdocs/docs/examples/basic_json_view__end.cpp b/docs/mkdocs/docs/examples/basic_json_view__end.cpp
new file mode 100644
index 000000000..6808a6c95
--- /dev/null
+++ b/docs/mkdocs/docs/examples/basic_json_view__end.cpp
@@ -0,0 +1,27 @@
+#include
+#include
+
+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() > 20)
+ {
+ break;
+ }
+ }
+
+ if (it != values.end())
+ {
+ std::cout << "first reading over 20: " << it->materialize().dump() << '\n';
+ }
+}
diff --git a/docs/mkdocs/docs/examples/basic_json_view__end.output b/docs/mkdocs/docs/examples/basic_json_view__end.output
new file mode 100644
index 000000000..b36dc9c70
--- /dev/null
+++ b/docs/mkdocs/docs/examples/basic_json_view__end.output
@@ -0,0 +1 @@
+first reading over 20: 25
diff --git a/docs/mkdocs/docs/examples/basic_json_view__find.cpp b/docs/mkdocs/docs/examples/basic_json_view__find.cpp
new file mode 100644
index 000000000..06141b65a
--- /dev/null
+++ b/docs/mkdocs/docs/examples/basic_json_view__find.cpp
@@ -0,0 +1,29 @@
+#include
+#include
+
+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';
+ }
+ }
+}
diff --git a/docs/mkdocs/docs/examples/basic_json_view__find.output b/docs/mkdocs/docs/examples/basic_json_view__find.output
new file mode 100644
index 000000000..30637e7e3
--- /dev/null
+++ b/docs/mkdocs/docs/examples/basic_json_view__find.output
@@ -0,0 +1,2 @@
+user 42
+user 7
diff --git a/docs/mkdocs/docs/examples/basic_json_view__front.cpp b/docs/mkdocs/docs/examples/basic_json_view__front.cpp
new file mode 100644
index 000000000..ed743f77e
--- /dev/null
+++ b/docs/mkdocs/docs/examples/basic_json_view__front.cpp
@@ -0,0 +1,24 @@
+#include
+#include
+
+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(empty_log.root().front());
+ }
+ catch (const nlohmann::json::invalid_iterator& e)
+ {
+ std::cout << e.what() << '\n';
+ }
+}
diff --git a/docs/mkdocs/docs/examples/basic_json_view__front.output b/docs/mkdocs/docs/examples/basic_json_view__front.output
new file mode 100644
index 000000000..a0de5266a
--- /dev/null
+++ b/docs/mkdocs/docs/examples/basic_json_view__front.output
@@ -0,0 +1,2 @@
+"queued"
+[json.exception.invalid_iterator.214] cannot get value
diff --git a/docs/mkdocs/docs/examples/basic_json_view__items.cpp b/docs/mkdocs/docs/examples/basic_json_view__items.cpp
new file mode 100644
index 000000000..3f7779c19
--- /dev/null
+++ b/docs/mkdocs/docs/examples/basic_json_view__items.cpp
@@ -0,0 +1,22 @@
+#include
+#include
+
+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';
+}
diff --git a/docs/mkdocs/docs/examples/basic_json_view__items.output b/docs/mkdocs/docs/examples/basic_json_view__items.output
new file mode 100644
index 000000000..78609c8ee
--- /dev/null
+++ b/docs/mkdocs/docs/examples/basic_json_view__items.output
@@ -0,0 +1,5 @@
+retries=1
+timeout=30
+retries=5
+first "retries" seen by operator[]: 1
+last "retries" kept by materialize(): 5
diff --git a/docs/mkdocs/docs/examples/basic_json_view__operator[].cpp b/docs/mkdocs/docs/examples/basic_json_view__operator[].cpp
new file mode 100644
index 000000000..e17919a9d
--- /dev/null
+++ b/docs/mkdocs/docs/examples/basic_json_view__operator[].cpp
@@ -0,0 +1,42 @@
+#include
+#include
+
+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';
+ }
+}
diff --git a/docs/mkdocs/docs/examples/basic_json_view__operator[].output b/docs/mkdocs/docs/examples/basic_json_view__operator[].output
new file mode 100644
index 000000000..630659e36
--- /dev/null
+++ b/docs/mkdocs/docs/examples/basic_json_view__operator[].output
@@ -0,0 +1,2 @@
+"Alice" <"alice@example.com"> #"admin"
+"Bob"
diff --git a/docs/mkdocs/docs/examples/basic_json_view__type_name.cpp b/docs/mkdocs/docs/examples/basic_json_view__type_name.cpp
new file mode 100644
index 000000000..9d59792ca
--- /dev/null
+++ b/docs/mkdocs/docs/examples/basic_json_view__type_name.cpp
@@ -0,0 +1,27 @@
+#include
+#include
+
+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';
+ }
+ }
+}
diff --git a/docs/mkdocs/docs/examples/basic_json_view__type_name.output b/docs/mkdocs/docs/examples/basic_json_view__type_name.output
new file mode 100644
index 000000000..e0ab0669e
--- /dev/null
+++ b/docs/mkdocs/docs/examples/basic_json_view__type_name.output
@@ -0,0 +1,3 @@
+ok
+expected an object, got array
+expected an object, got discarded
diff --git a/docs/mkdocs/docs/features/json_view.md b/docs/mkdocs/docs/features/json_view.md
index 6b66c42ca..cb8b8ed5d 100644
--- a/docs/mkdocs/docs/features/json_view.md
+++ b/docs/mkdocs/docs/features/json_view.md
@@ -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()`, 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()`, 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`
diff --git a/docs/mkdocs/mkdocs.yml b/docs/mkdocs/mkdocs.yml
index 0058b0e58..4c7bb7fd8 100644
--- a/docs/mkdocs/mkdocs.yml
+++ b/docs/mkdocs/mkdocs.yml
@@ -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