Document the comparisons of json_view

- API pages for operator== and operator!= of basic_json_view, linked
  both ways with the basic_json pages
- the feature page and the class overview list the comparisons
- the examples show when the view helps: detecting a changed document
  without building json values

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
This commit is contained in:
Niels Lohmann
2026-09-30 21:01:48 +02:00
parent e842f3a68f
commit 21d90fac1c
12 changed files with 279 additions and 4 deletions
@@ -20,11 +20,12 @@ Moving the document itself does not invalidate its views: the index is heap-allo
`basic_json_document` object.
`basic_json_view` provides the read-only part of the `BasicJsonType` interface: the type-inspection functions, element
access, lookup, iteration, and conversion -- [`get<T>()`](get.md), [`get_string()`](get_string.md),
access, lookup, iteration, conversion, and comparison -- [`get<T>()`](get.md), [`get_string()`](get_string.md),
[`number_token()`](number_token.md), and [`materialize()`](materialize.md) to build the `BasicJsonType` value of a
subtree on demand. [`operator[]`](operator%5B%5D.md), [`at`](at.md), [`contains`](contains.md), and
[`value`](value.md) also accept a [`json_pointer`](../json_pointer/index.md). It does not (yet) provide
comparison.
[`value`](value.md) also accept a [`json_pointer`](../json_pointer/index.md). [`operator==`](operator_eq.md) and
[`operator!=`](operator_ne.md) compare two views, or a view and a `BasicJsonType` value, without ever building a
`BasicJsonType` value for a view; no ordering comparison (`#!cpp operator<`) is provided.
## Template parameters
@@ -107,6 +108,11 @@ comparison.
- [**number_token**](number_token.md) - get a number's token text without a copy
- [**materialize**](materialize.md) - build the `BasicJsonType` value of this subtree
### Comparison
- [**operator==**](operator_eq.md) - comparison: equal
- [**operator!=**](operator_ne.md) - comparison: not equal
### Serialization
- [**dump**](dump.md) - serialize to a JSON-formatted string
@@ -0,0 +1,107 @@
# <small>nlohmann::basic_json_view::</small>operator==
```cpp
// (1)
bool operator==(const basic_json_view& lhs, const basic_json_view& rhs);
// (2)
bool operator==(const basic_json_view& lhs, const BasicJsonType& rhs);
bool operator==(const BasicJsonType& lhs, const basic_json_view& rhs);
```
1. Compares two views for equality: whether the values [`BasicJsonType::parse()`](../basic_json/parse.md) would
produce for `lhs` and `rhs` are equal, according to `BasicJsonType`'s [`operator==`](../basic_json/operator_eq.md).
2. Compares a view and a `BasicJsonType` value for equality, in either order: whether the value `parse()` would
produce for the view and the other operand are equal, according to `BasicJsonType`'s
[`operator==`](../basic_json/operator_eq.md).
Neither overload builds a `BasicJsonType` value for a view to do the comparison (see [Notes](#notes) below). Numbers
compare by value across their types (`#!cpp 1 == 1.0`), and an object compares by its members, with duplicate keys
resolved exactly as `parse()` resolves them -- the last value, at the position of the first occurrence of the key.
## Parameters
`lhs` (in)
: first value to consider
`rhs` (in)
: second value to consider
## Return value
whether the values `lhs` and `rhs` are equal
## Exception safety
Strong exception safety: if an exception is thrown, there are no changes to either operand, or to the document(s) a
view refers to.
## Exceptions
May throw `#!cpp std::bad_alloc`. Unlike the other comparison and most other `basic_json_view` functions,
`operator==` is not `#!cpp noexcept`: resolving an object's members needs a temporary array to sort them by key (see
[Complexity](#complexity) below), and that allocation can fail.
## Complexity
Linear in the size of the compared values: every number, string, array element, and object member is visited at most
once, and the walk is iterative, so the nesting depth it can compare is limited by available memory only, not by the
call stack (as for [`materialize()`](materialize.md)). Resolving an object's members takes an additional O(n log n)
in the number of members at that level, since they are sorted by key to detect and resolve duplicates before being
compared. Two arrays of different [`size()`](size.md) are rejected without visiting either one's elements.
## Notes
Only a single number, boolean, or `#!cpp null` value is ever materialized into a `BasicJsonType`, to reuse its
`operator==` -- for numbers, so that values written differently in the source text but equal in value (e.g. an
integer and a floating-point literal) still compare equal, following the same rules `BasicJsonType` does for special
values such as `#!cpp NaN`. Constructing one of these scalars never allocates. Strings are compared directly, without
allocating, either from the source text on both sides or, for overload 2, against `BasicJsonType`'s own string.
Arrays and objects are never materialized at all; only their elements or members are visited, one pair at a time.
!!! info "How objects are compared"
For a [`json_view`](../json_view.md) (`BasicJsonType::object_t` is `#!cpp std::map`), members are compared by
key, regardless of the order they appear in the source text. For an
[`ordered_json_view`](../ordered_json_view.md) (`object_t` is `ordered_map`), they are compared in the order
they occur, so the very same two objects with their members reordered can compare equal as `json_view`s but not
as `ordered_json_view`s. This is exactly how [`json`](../json.md) and [`ordered_json`](../ordered_json.md)
compare, see ["Comparing different `basic_json` specializations"](../basic_json/operator_eq.md#notes).
!!! info "Discarded views"
A [discarded](is_discarded.md) view compares the same way a discarded `BasicJsonType` value does, which is
governed by
[`JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON`](../macros/json_use_legacy_discarded_value_comparison.md): by
default, a discarded view is never equal to anything, not even another discarded view.
No ordering comparison (`#!cpp operator<`) is provided for `basic_json_view`; [`materialize()`](materialize.md) is
the way to get a `BasicJsonType` value that supports it.
## Examples
??? example
The example below checks whether a newly received configuration differs from the previous one, and whether a
received document matches what a test expects -- directly on views, without ever materializing a `BasicJsonType`
value for either side.
```cpp
--8<-- "examples/basic_json_view__operator_eq.cpp"
```
Output:
```json
--8<-- "examples/basic_json_view__operator_eq.output"
```
## See also
- [operator!=](operator_ne.md) - compare for inequality
- [materialize](materialize.md) - build a `BasicJsonType` value, e.g. to keep comparing after the document is gone
- [`BasicJsonType::operator==`](../basic_json/operator_eq.md) - the corresponding function of `basic_json`
## Version history
- Added in version 3.13.0.
@@ -0,0 +1,82 @@
# <small>nlohmann::basic_json_view::</small>operator!=
```cpp
// (1)
bool operator!=(const basic_json_view& lhs, const basic_json_view& rhs);
// (2)
bool operator!=(const basic_json_view& lhs, const BasicJsonType& rhs);
bool operator!=(const BasicJsonType& lhs, const basic_json_view& rhs);
```
1. Compares two views for inequality. Returns `#!cpp !(lhs == rhs)`, see [operator==](operator_eq.md).
2. Compares a view and a `BasicJsonType` value for inequality, in either order. Returns `#!cpp !(lhs == rhs)` (or,
for the reversed order, `#!cpp !(rhs == lhs)`), see [operator==](operator_eq.md).
Since `operator!=` is defined as the negation of [`operator==`](operator_eq.md), it follows the same rules for
special cases: for instance, since a [discarded](is_discarded.md) view is never equal to anything by default (see
[operator=='s Notes](operator_eq.md#notes)), it is never *unequal* to anything either -- `#!cpp discarded != discarded`
is also `#!cpp false`, exactly as for a discarded `BasicJsonType` value.
## Parameters
`lhs` (in)
: first value to consider
`rhs` (in)
: second value to consider
## Return value
whether the values `lhs` and `rhs` are not equal
## Exception safety
Strong exception safety: if an exception is thrown, there are no changes to either operand, or to the document(s) a
view refers to.
## Exceptions
May throw `#!cpp std::bad_alloc`, propagated from [`operator==`](operator_eq.md#exceptions). Unlike most other
`basic_json_view` functions, `operator!=` is not `#!cpp noexcept`.
## Complexity
Linear, as [`operator==`](operator_eq.md#complexity).
## Notes
See the [Notes](operator_eq.md#notes) of `operator==` -- in particular for how an object's members are compared
(order matters for [`ordered_json_view`](../ordered_json_view.md) but not for [`json_view`](../json_view.md)) and
for how discarded views compare.
No ordering comparison (`#!cpp operator<`) is provided for `basic_json_view`; [`materialize()`](materialize.md) is
the way to get a `BasicJsonType` value that supports it.
## Examples
??? example
The example below asserts, as a test would, that a received document differs from an unwanted value, and shows
that -- as for [`json`](../json.md)/[`ordered_json`](../ordered_json.md) -- reordering an object's members is
detected as a difference for an `ordered_json_view` but not for a `json_view`.
```cpp
--8<-- "examples/basic_json_view__operator_ne.cpp"
```
Output:
```json
--8<-- "examples/basic_json_view__operator_ne.output"
```
## See also
- [operator==](operator_eq.md) - compare for equality
- [materialize](materialize.md) - build a `BasicJsonType` value, e.g. to keep comparing after the document is gone
- [`BasicJsonType::operator!=`](../basic_json/operator_ne.md) - the corresponding function of `basic_json`
## Version history
- Added in version 3.13.0.