Rework basic_json element access to accept more key types

Rework basic_json element access member functions and operators to
accept any type that meets the requirements defined by type trait
detail::is_usable_as_key_type.

Member functions and operators:
* at()
* operator[]
* value()
* erase()
* find()
* count()
* contains()

Update documentation to reflect these changes.

Add unit tests to excercise the new functions using std::string_view.

Co-authored-by: Niels Lohmann <niels.lohmann@gmail.com>
This commit is contained in:
Florian Albrechtskirchinger 2022-03-03 14:23:13 +01:00
parent 0d790397a2
commit 078673fdd9
17 changed files with 1227 additions and 254 deletions

View File

@ -10,13 +10,28 @@ reference at(const typename object_t::key_type& key);
const_reference at(const typename object_t::key_type& key) const; const_reference at(const typename object_t::key_type& key) const;
// (3) // (3)
template<typename KeyType>
reference at(KeyType&& key);
template<typename KeyType>
const_reference at(KeyType&& key) const;
// (4)
reference at(const json_pointer& ptr); reference at(const json_pointer& ptr);
const_reference at(const json_pointer& ptr) const; const_reference at(const json_pointer& ptr) const;
``` ```
1. Returns a reference to the array element at specified location `idx`, with bounds checking. 1. Returns a reference to the array element at specified location `idx`, with bounds checking.
2. Returns a reference to the object element at with specified key `key`, with bounds checking. 2. Returns a reference to the object element with specified key `key`, with bounds checking.
3. Returns a reference to the element at with specified JSON pointer `ptr`, with bounds checking. 3. See 2. This overload is only available if `KeyType` is comparable with `#!cpp typename object_t::key_type` and
`#!cpp typename object_comparator_t::is_transparent` denotes a type.
4. Returns a reference to the element at specified JSON pointer `ptr`, with bounds checking.
## Template parameters
`KeyType`
: A type for an object key other than [`json_pointer`](../json_pointer/index.md) that is comparable with
[`string_t`](string_t.md) using [`object_comparator_t`](object_comparator_t.md).
This can also be a string view (C++17).
## Parameters ## Parameters
@ -33,7 +48,8 @@ const_reference at(const json_pointer& ptr) const;
1. reference to the element at index `idx` 1. reference to the element at index `idx`
2. reference to the element at key `key` 2. reference to the element at key `key`
3. reference to the element pointed to by `ptr` 3. reference to the element at key `key`
4. reference to the element pointed to by `ptr`
## Exception safety ## Exception safety
@ -51,7 +67,8 @@ Strong exception safety: if an exception occurs, the original value stays intact
in this case, calling `at` with a key makes no sense. See example below. in this case, calling `at` with a key makes no sense. See example below.
- Throws [`out_of_range.403`](../../home/exceptions.md#jsonexceptionout_of_range403) if the key `key` is not - Throws [`out_of_range.403`](../../home/exceptions.md#jsonexceptionout_of_range403) if the key `key` is not
stored in the object; that is, `find(key) == end()`. See example below. stored in the object; that is, `find(key) == end()`. See example below.
3. The function can throw the following exceptions: 3. See 2.
4. The function can throw the following exceptions:
- Throws [`parse_error.106`](../../home/exceptions.md#jsonexceptionparse_error106) if an array index in the passed - Throws [`parse_error.106`](../../home/exceptions.md#jsonexceptionparse_error106) if an array index in the passed
JSON pointer `ptr` begins with '0'. See example below. JSON pointer `ptr` begins with '0'. See example below.
- Throws [`parse_error.109`](../../home/exceptions.md#jsonexceptionparse_error109) if an array index in the passed - Throws [`parse_error.109`](../../home/exceptions.md#jsonexceptionparse_error109) if an array index in the passed
@ -68,9 +85,10 @@ Strong exception safety: if an exception occurs, the original value stays intact
## Complexity ## Complexity
1. Constant 1. Constant.
2. Logarithmic in the size of the container. 2. Logarithmic in the size of the container.
3. Constant 3. Logarithmic in the size of the container.
4. Logarithmic in the size of the container.
## Examples ## Examples
@ -134,7 +152,7 @@ Strong exception safety: if an exception occurs, the original value stays intact
--8<-- "examples/at__object_t_key_type_const.output" --8<-- "examples/at__object_t_key_type_const.output"
``` ```
??? example "Example (3) access specified element via JSON Pointer" ??? example "Example (4) access specified element via JSON Pointer"
The example below shows how object elements can be read and written using `at()`. It also demonstrates the different The example below shows how object elements can be read and written using `at()`. It also demonstrates the different
exceptions that can be thrown. exceptions that can be thrown.
@ -149,7 +167,7 @@ Strong exception safety: if an exception occurs, the original value stays intact
--8<-- "examples/at_json_pointer.output" --8<-- "examples/at_json_pointer.output"
``` ```
??? example "Example (3) access specified element via JSON Pointer" ??? example "Example (4) access specified element via JSON Pointer"
The example below shows how object elements can be read using `at()`. It also demonstrates the different exceptions The example below shows how object elements can be read using `at()`. It also demonstrates the different exceptions
that can be thrown. that can be thrown.
@ -173,4 +191,5 @@ Strong exception safety: if an exception occurs, the original value stays intact
1. Added in version 1.0.0. 1. Added in version 1.0.0.
2. Added in version 1.0.0. 2. Added in version 1.0.0.
3. Added in version 2.0.0. 3. Added in version 3.11.0.
4. Added in version 2.0.0.

View File

@ -201,16 +201,16 @@ basic_json(basic_json&& other) noexcept;
## Exceptions ## Exceptions
1. / 1. (none)
2. The function does not throw exceptions. 2. The function does not throw exceptions.
3. / 3. (none)
4. / 4. (none)
5. The function can throw the following exceptions: 5. The function can throw the following exceptions:
- Throws [`type_error.301`](../../home/exceptions.md#jsonexceptiontype_error301) if `type_deduction` is - Throws [`type_error.301`](../../home/exceptions.md#jsonexceptiontype_error301) if `type_deduction` is
`#!cpp false`, `manual_type` is `value_t::object`, but `init` contains an element which is not a pair whose first `#!cpp false`, `manual_type` is `value_t::object`, but `init` contains an element which is not a pair whose first
element is a string. In this case, the constructor could not create an object. If `type_deduction` would have been element is a string. In this case, the constructor could not create an object. If `type_deduction` would have been
`#!cpp true`, an array would have been created. See `object(initializer_list_t)` for an example. `#!cpp true`, an array would have been created. See `object(initializer_list_t)` for an example.
6. / 6. (none)
7. The function can throw the following exceptions: 7. The function can throw the following exceptions:
- Throws [`invalid_iterator.201`](../../home/exceptions.md#jsonexceptioninvalid_iterator201) if iterators `first` - Throws [`invalid_iterator.201`](../../home/exceptions.md#jsonexceptioninvalid_iterator201) if iterators `first`
and `last` are not compatible (i.e., do not belong to the same JSON value). In this case, the range and `last` are not compatible (i.e., do not belong to the same JSON value). In this case, the range
@ -220,7 +220,7 @@ basic_json(basic_json&& other) noexcept;
element anymore. In this case, the range `[first, last)` is undefined. See example code below. element anymore. In this case, the range `[first, last)` is undefined. See example code below.
- Throws [`invalid_iterator.206`](../../home/exceptions.md#jsonexceptioninvalid_iterator206) if iterators `first` - Throws [`invalid_iterator.206`](../../home/exceptions.md#jsonexceptioninvalid_iterator206) if iterators `first`
and `last` belong to a `#!json null` value. In this case, the range `[first, last)` is undefined. and `last` belong to a `#!json null` value. In this case, the range `[first, last)` is undefined.
8. / 8. (none)
9. The function does not throw exceptions. 9. The function does not throw exceptions.
## Complexity ## Complexity

View File

@ -2,21 +2,28 @@
```cpp ```cpp
// (1) // (1)
template<typename KeyT> bool contains(const typename object_t::key_type& key) const;
bool contains(KeyT && key) const;
// (2) // (2)
template<typename KeyType>
bool contains(KeyType&& key) const;
// (3)
bool contains(const json_pointer& ptr) const; bool contains(const json_pointer& ptr) const;
``` ```
1. Check whether an element exists in a JSON object with key equivalent to `key`. If the element is not found or the 1. Check whether an element exists in a JSON object with a key equivalent to `key`. If the element is not found or the
JSON value is not an object, `#!cpp false` is returned. JSON value is not an object, `#!cpp false` is returned.
2. Check whether the given JSON pointer `ptr` can be resolved in the current JSON value. 2. See 1. This overload is only available if `KeyType` is comparable with `#!cpp typename object_t::key_type` and
`#!cpp typename object_comparator_t::is_transparent` denotes a type.
3. Check whether the given JSON pointer `ptr` can be resolved in the current JSON value.
## Template parameters ## Template parameters
`KeyT` `KeyType`
: A type for an object key other than `basic_json::json_pointer`. : A type for an object key other than [`json_pointer`](../json_pointer/index.md) that is comparable with
[`string_t`](string_t.md) using [`object_comparator_t`](object_comparator_t.md).
This can also be a string view (C++17).
## Parameters ## Parameters
@ -30,7 +37,8 @@ bool contains(const json_pointer& ptr) const;
1. `#!cpp true` if an element with specified `key` exists. If no such element with such key is found or the JSON value 1. `#!cpp true` if an element with specified `key` exists. If no such element with such key is found or the JSON value
is not an object, `#!cpp false` is returned. is not an object, `#!cpp false` is returned.
2. `#!cpp true` if the JSON pointer can be resolved to a stored value, `#!cpp false` otherwise. 2. See 1.
3. `#!cpp true` if the JSON pointer can be resolved to a stored value, `#!cpp false` otherwise.
## Exception safety ## Exception safety
@ -39,7 +47,8 @@ Strong exception safety: if an exception occurs, the original value stays intact
## Exceptions ## Exceptions
1. The function does not throw exceptions. 1. The function does not throw exceptions.
2. The function can throw the following exceptions: 2. The function does not throw exceptions.
3. The function can throw the following exceptions:
- Throws [`parse_error.106`](../../home/exceptions.md#jsonexceptionparse_error106) if an array index begins with - Throws [`parse_error.106`](../../home/exceptions.md#jsonexceptionparse_error106) if an array index begins with
`0`. `0`.
- Throws [`parse_error.109`](../../home/exceptions.md#jsonexceptionparse_error109) if an array index was not a - Throws [`parse_error.109`](../../home/exceptions.md#jsonexceptionparse_error109) if an array index was not a
@ -74,7 +83,7 @@ Logarithmic in the size of the JSON object.
--8<-- "examples/contains.output" --8<-- "examples/contains.output"
``` ```
??? example "Example (1) check with JSON pointer" ??? example "Example (3) check with JSON pointer"
The example shows how `contains()` is used. The example shows how `contains()` is used.
@ -90,5 +99,6 @@ Logarithmic in the size of the JSON object.
## Version history ## Version history
1. Added in version 3.6.0. 1. Added in version 3.11.0.
2. Added in version 3.7.0. 2. Added in version 3.6.0. Extended template `KeyType` to support comparable types in version 3.11.0.
3. Added in version 3.7.0.

View File

@ -1,17 +1,25 @@
# <small>nlohmann::basic_json::</small>count # <small>nlohmann::basic_json::</small>count
```cpp ```cpp
template<typename KeyT> // (1)
size_type count(KeyT&& key) const; size_type count(const typename object_t::key_type& key) const;
// (2)
template<typename KeyType>
size_type count(KeyType&& key) const;
``` ```
Returns the number of elements with key `key`. If `ObjectType` is the default `std::map` type, the return value will 1. Returns the number of elements with key `key`. If `ObjectType` is the default `std::map` type, the return value will
always be `0` (`key` was not found) or `1` (`key` was found). always be `0` (`key` was not found) or `1` (`key` was found).
2. See 1. This overload is only available if `KeyType` is comparable with `#!cpp typename object_t::key_type` and
`#!cpp typename object_comparator_t::is_transparent` denotes a type.
## Template parameters ## Template parameters
`KeyT` `KeyType`
: A type for an object key. : A type for an object key other than [`json_pointer`](../json_pointer/index.md) that is comparable with
[`string_t`](string_t.md) using [`object_comparator_t`](object_comparator_t.md).
This can also be a string view (C++17).
## Parameters ## Parameters
@ -52,4 +60,5 @@ This method always returns `0` when executed on a JSON type that is not an objec
## Version history ## Version history
- Added in version 1.0.0. 1. Added in version 3.11.0.
2. Added in version 1.0.0. Changed parameter `key` type to `KeyType&&` in version 3.11.0.

View File

@ -8,7 +8,8 @@ using default_object_comparator_t = std::less<>; // since C++14
The default comparator used by [`object_t`](object_t.md). The default comparator used by [`object_t`](object_t.md).
Since C++14 a transparent comparator is used which prevents unnecessary string construction. Since C++14 a transparent comparator is used which prevents unnecessary string construction
when looking up a key in an object.
The actual comparator used depends on [`object_t`](object_t.md) and can be obtained via The actual comparator used depends on [`object_t`](object_t.md) and can be obtained via
[`object_comparator_t`](object_comparator_t.md). [`object_comparator_t`](object_comparator_t.md).

View File

@ -13,6 +13,10 @@ const_iterator erase(const_iterator first, const_iterator last);
size_type erase(const typename object_t::key_type& key); size_type erase(const typename object_t::key_type& key);
// (4) // (4)
template<typename KeyType>
size_type erase(KeyType&& key);
// (5)
void erase(const size_type idx); void erase(const size_type idx);
``` ```
@ -29,7 +33,17 @@ void erase(const size_type idx);
3. Removes an element from a JSON object by key. 3. Removes an element from a JSON object by key.
4. Removes an element from a JSON array by index. 4. See 3. This overload is only available if `KeyType` is comparable with `#!cpp typename object_t::key_type` and
`#!cpp typename object_comparator_t::is_transparent` denotes a type.
5. Removes an element from a JSON array by index.
## Template parameters
`KeyType`
: A type for an object key other than [`json_pointer`](../json_pointer/index.md) that is comparable with
[`string_t`](string_t.md) using [`object_comparator_t`](object_comparator_t.md).
This can also be a string view (C++17).
## Parameters ## Parameters
@ -56,7 +70,8 @@ void erase(const size_type idx);
is returned. is returned.
3. Number of elements removed. If `ObjectType` is the default `std::map` type, the return value will always be `0` 3. Number of elements removed. If `ObjectType` is the default `std::map` type, the return value will always be `0`
(`key` was not found) or `1` (`key` was found). (`key` was not found) or `1` (`key` was found).
4. / 4. See 3.
5. (none)
## Exception safety ## Exception safety
@ -83,7 +98,8 @@ Strong exception safety: if an exception occurs, the original value stays intact
3. The function can throw the following exceptions: 3. The function can throw the following exceptions:
- Throws [`type_error.307`](../../home/exceptions.md#jsonexceptiontype_error307) when called on a type other than - Throws [`type_error.307`](../../home/exceptions.md#jsonexceptiontype_error307) when called on a type other than
JSON object; example: `"cannot use erase() with null"` JSON object; example: `"cannot use erase() with null"`
4. The function can throw the following exceptions: 4. See 3.
5. The function can throw the following exceptions:
- Throws [`type_error.307`](../../home/exceptions.md#jsonexceptiontype_error307) when called on a type other than - Throws [`type_error.307`](../../home/exceptions.md#jsonexceptiontype_error307) when called on a type other than
JSON object; example: `"cannot use erase() with null"` JSON object; example: `"cannot use erase() with null"`
- Throws [`out_of_range.401`](../../home/exceptions.md#jsonexceptionout_of_range401) when `idx >= size()`; example: - Throws [`out_of_range.401`](../../home/exceptions.md#jsonexceptionout_of_range401) when `idx >= size()`; example:
@ -103,14 +119,16 @@ Strong exception safety: if an exception occurs, the original value stays intact
- strings and binary: linear in the length of the member - strings and binary: linear in the length of the member
- other types: constant - other types: constant
3. `log(size()) + count(key)` 3. `log(size()) + count(key)`
4. Linear in distance between `idx` and the end of the container. 4. `log(size()) + count(key)`
5. Linear in distance between `idx` and the end of the container.
## Notes ## Notes
1. Invalidates iterators and references at or after the point of the `erase`, including the `end()` iterator. 1. Invalidates iterators and references at or after the point of the `erase`, including the `end()` iterator.
2. / 2. (none)
3. References and iterators to the erased elements are invalidated. Other references and iterators are not affected. 3. References and iterators to the erased elements are invalidated. Other references and iterators are not affected.
4. / 4. See 3.
5. (none)
## Examples ## Examples
@ -156,7 +174,7 @@ Strong exception safety: if an exception occurs, the original value stays intact
--8<-- "examples/erase__key_type.output" --8<-- "examples/erase__key_type.output"
``` ```
??? example "Example: (4) remove element from a JSON array given an index" ??? example "Example: (5) remove element from a JSON array given an index"
The example shows the effect of `erase()` using an array index. The example shows the effect of `erase()` using an array index.
@ -172,5 +190,8 @@ Strong exception safety: if an exception occurs, the original value stays intact
## Version history ## Version history
- Added in version 1.0.0. 1. Added in version 1.0.0. Added support for binary types in version 3.8.0.
- Added support for binary types in version 3.8.0. 2. Added in version 1.0.0. Added support for binary types in version 3.8.0.
3. Added in version 1.0.0.
4. Added in version 3.11.0.
5. Added in version 1.0.0.

View File

@ -1,20 +1,28 @@
# <small>nlohmann::basic_json::</small>find # <small>nlohmann::basic_json::</small>find
```cpp ```cpp
template<typename KeyT> // (1)
iterator find(KeyT&& key); iterator find(const typename object_t::key_type& key);
const_iterator find(const typename object_t::key_type& key) const;
template<typename KeyT> // (2)
const_iterator find(KeyT&& key) const; template<typename KeyType>
iterator find(KeyType&& key);
template<typename KeyType>
const_iterator find(KeyType&& key) const;
``` ```
Finds an element in a JSON object with key equivalent to `key`. If the element is not found or the JSON value is not an 1. Finds an element in a JSON object with a key equivalent to `key`. If the element is not found or the
object, `end()` is returned. JSON value is not an object, `end()` is returned.
2. See 1. This overload is only available if `KeyType` is comparable with `#!cpp typename object_t::key_type` and
`#!cpp typename object_comparator_t::is_transparent` denotes a type.
## Template parameters ## Template parameters
`KeyT` `KeyType`
: A type for an object key. : A type for an object key other than [`json_pointer`](../json_pointer/index.md) that is comparable with
[`string_t`](string_t.md) using [`object_comparator_t`](object_comparator_t.md).
This can also be a string view (C++17).
## Parameters ## Parameters
@ -23,8 +31,8 @@ object, `end()` is returned.
## Return value ## Return value
Iterator to an element with key equivalent to `key`. If no such element is found or the JSON value is not an object, Iterator to an element with a key equivalent to `key`. If no such element is found or the JSON value is not an object,
past-the-end (see `end()`) iterator is returned. a past-the-end iterator (see `end()`) is returned.
## Exception safety ## Exception safety
@ -60,4 +68,5 @@ This method always returns `end()` when executed on a JSON type that is not an o
## Version history ## Version history
- Added in version 1.0.0. 1. Added in version 3.11.0.
2. Added in version 1.0.0. Changed to support comparable types in version 3.11.0.

View File

@ -50,7 +50,7 @@ void insert(const_iterator first, const_iterator last);
2. iterator pointing to the first element inserted, or `pos` if `#!cpp cnt==0` 2. iterator pointing to the first element inserted, or `pos` if `#!cpp cnt==0`
3. iterator pointing to the first element inserted, or `pos` if `#!cpp first==last` 3. iterator pointing to the first element inserted, or `pos` if `#!cpp first==last`
4. iterator pointing to the first element inserted, or `pos` if `ilist` is empty 4. iterator pointing to the first element inserted, or `pos` if `ilist` is empty
5. / 5. (none)
## Exception safety ## Exception safety

View File

@ -6,26 +6,32 @@ reference operator[](size_type idx);
const_reference operator[](size_type idx) const; const_reference operator[](size_type idx) const;
// (2) // (2)
reference operator[](const typename object_t::key_type& key); reference operator[](typename object_t::key_type key);
const_reference operator[](const typename object_t::key_type& key) const; const_reference operator[](const typename object_t::key_type& key) const;
template<typename T>
reference operator[](T* key);
template<typename T>
const_reference operator[](T* key) const;
// (3) // (3)
template<typename KeyType>
reference operator[](KeyType&& key);
template<typename KeyType>
const_reference operator[](KeyType&& key) const;
// (4)
reference operator[](const json_pointer& ptr); reference operator[](const json_pointer& ptr);
const_reference operator[](const json_pointer& ptr) const; const_reference operator[](const json_pointer& ptr) const;
``` ```
1. Returns a reference to the array element at specified location `idx`. 1. Returns a reference to the array element at specified location `idx`.
2. Returns a reference to the object element at with specified key `key`. 2. Returns a reference to the object element with specified key `key`. The non-const qualified overload takes the key by value.
3. Returns a reference to the element at with specified JSON pointer `ptr`. 3. See 2. This overload is only available if `KeyType` is comparable with `#!cpp typename object_t::key_type` and
`#!cpp typename object_comparator_t::is_transparent` denotes a type.
4. Returns a reference to the element with specified JSON pointer `ptr`.
## Template parameters ## Template parameters
`T` `KeyType`
: string literal convertible to `object_t::key_type` : A type for an object key other than [`json_pointer`](../json_pointer/index.md) that is comparable with
[`string_t`](string_t.md) using [`object_comparator_t`](object_comparator_t.md).
This can also be a string view (C++17).
## Parameters ## Parameters
@ -40,9 +46,10 @@ const_reference operator[](const json_pointer& ptr) const;
## Return value ## Return value
1. reference to the element at index `idx` 1. (const) reference to the element at index `idx`
2. reference to the element at key `key` 2. (const) reference to the element at key `key`
3. reference to the element pointed to by `ptr` 3. (const) reference to the element at key `key`
4. (const) reference to the element pointed to by `ptr`
## Exception safety ## Exception safety
@ -56,7 +63,8 @@ Strong exception safety: if an exception occurs, the original value stays intact
2. The function can throw the following exceptions: 2. The function can throw the following exceptions:
- Throws [`type_error.305`](../../home/exceptions.md#jsonexceptiontype_error305) if the JSON value is not an object - Throws [`type_error.305`](../../home/exceptions.md#jsonexceptiontype_error305) if the JSON value is not an object
or null; in that case, using the `[]` operator with a key makes no sense. or null; in that case, using the `[]` operator with a key makes no sense.
3. The function can throw the following exceptions: 3. See 2.
4. The function can throw the following exceptions:
- Throws [`parse_error.106`](../../home/exceptions.md#jsonexceptionparse_error106) if an array index in the passed - Throws [`parse_error.106`](../../home/exceptions.md#jsonexceptionparse_error106) if an array index in the passed
JSON pointer `ptr` begins with '0'. JSON pointer `ptr` begins with '0'.
- Throws [`parse_error.109`](../../home/exceptions.md#jsonexceptionparse_error109) if an array index in the passed - Throws [`parse_error.109`](../../home/exceptions.md#jsonexceptionparse_error109) if an array index in the passed
@ -70,7 +78,8 @@ Strong exception safety: if an exception occurs, the original value stays intact
1. Constant if `idx` is in the range of the array. Otherwise, linear in `idx - size()`. 1. Constant if `idx` is in the range of the array. Otherwise, linear in `idx - size()`.
2. Logarithmic in the size of the container. 2. Logarithmic in the size of the container.
3. Constant 3. Logarithmic in the size of the container.
4. Logarithmic in the size of the container.
## Notes ## Notes
@ -87,7 +96,9 @@ Strong exception safety: if an exception occurs, the original value stays intact
2. If `key` is not found in the object, then it is silently added to the object and filled with a `#!json null` value to 2. If `key` is not found in the object, then it is silently added to the object and filled with a `#!json null` value to
make `key` a valid reference. In case the value was `#!json null` before, it is converted to an object. make `key` a valid reference. In case the value was `#!json null` before, it is converted to an object.
3. `null` values are created in arrays and objects if necessary. 3. See 2.
4. `null` values are created in arrays and objects if necessary.
In particular: In particular:
@ -143,7 +154,7 @@ Strong exception safety: if an exception occurs, the original value stays intact
--8<-- "examples/operatorarray__key_type.output" --8<-- "examples/operatorarray__key_type.output"
``` ```
??? example "Example (2): access specified object element" ??? example "Example (2): access specified object element (const)"
The example below shows how object elements can be read using the `[]` operator. The example below shows how object elements can be read using the `[]` operator.
@ -157,7 +168,7 @@ Strong exception safety: if an exception occurs, the original value stays intact
--8<-- "examples/operatorarray__key_type_const.output" --8<-- "examples/operatorarray__key_type_const.output"
``` ```
??? example "Example (3): access specified element via JSON Pointer" ??? example "Example (4): access specified element via JSON Pointer"
The example below shows how values can be read and written using JSON Pointers. The example below shows how values can be read and written using JSON Pointers.
@ -171,7 +182,7 @@ Strong exception safety: if an exception occurs, the original value stays intact
--8<-- "examples/operatorjson_pointer.output" --8<-- "examples/operatorjson_pointer.output"
``` ```
??? example "Example (3): access specified element via JSON Pointer" ??? example "Example (4): access specified element via JSON Pointer (const)"
The example below shows how values can be read using JSON Pointers. The example below shows how values can be read using JSON Pointers.
@ -193,5 +204,6 @@ Strong exception safety: if an exception occurs, the original value stays intact
## Version history ## Version history
1. Added in version 1.0.0. 1. Added in version 1.0.0.
2. Added in version 1.0.0. Overloads for `T* key` added in version 1.1.0. 2. Added in version 1.0.0. Added overloads for `T* key` in version 1.1.0. Removed overloads for `T* key` (replaced by 3) in version 3.11.0.
3. Added in version 2.0.0. 3. Added in version 3.11.0.
4. Added in version 2.0.0.

View File

@ -28,7 +28,7 @@ The exact mapping and its limitations is described on a [dedicated page](../../f
## Return value ## Return value
1. BSON serialization as byte vector 1. BSON serialization as byte vector
2. / 2. (none)
## Exception safety ## Exception safety

View File

@ -29,7 +29,7 @@ The exact mapping and its limitations is described on a [dedicated page](../../f
## Return value ## Return value
1. CBOR serialization as byte vector 1. CBOR serialization as byte vector
2. / 2. (none)
## Exception safety ## Exception safety

View File

@ -28,7 +28,7 @@ The exact mapping and its limitations is described on a [dedicated page](../../f
## Return value ## Return value
1. MessagePack serialization as byte vector 1. MessagePack serialization as byte vector
2. / 2. (none)
## Exception safety ## Exception safety

View File

@ -39,7 +39,7 @@ The exact mapping and its limitations is described on a [dedicated page](../../f
## Return value ## Return value
1. UBJSON serialization as byte vector 1. UBJSON serialization as byte vector
2. / 2. (none)
## Exception safety ## Exception safety

View File

@ -4,9 +4,14 @@
// (1) // (1)
template<class ValueType> template<class ValueType>
ValueType value(const typename object_t::key_type& key, ValueType value(const typename object_t::key_type& key,
const ValueType& default_value) const; ValueType&& default_value) const;
// (2) // (2)
template<class KeyType, class ValueType>
ValueType value(KeyType&& key,
ValueType&& default_value) const;
// (3)
template<class ValueType> template<class ValueType>
ValueType value(const json_pointer& ptr, ValueType value(const json_pointer& ptr,
const ValueType& default_value) const; const ValueType& default_value) const;
@ -24,7 +29,10 @@ ValueType value(const json_pointer& ptr,
} }
``` ```
2. Returns either a copy of an object's element at the specified JSON pointer `ptr` or a given default value if no value 2. See 1. This overload is only available if `KeyType` is comparable with `#!cpp typename object_t::key_type` and
`#!cpp typename object_comparator_t::is_transparent` denotes a type.
3. Returns either a copy of an object's element at the specified JSON pointer `ptr` or a given default value if no value
at `ptr` exists. at `ptr` exists.
The function is basically equivalent to executing The function is basically equivalent to executing
@ -44,6 +52,10 @@ ValueType value(const json_pointer& ptr,
## Template parameters ## Template parameters
`KeyType`
: A type for an object key other than [`json_pointer`](../json_pointer/index.md) that is comparable with
[`string_t`](string_t.md) using [`object_comparator_t`](object_comparator_t.md).
This can also be a string view (C++17).
`ValueType` `ValueType`
: type compatible to JSON values, for instance `#!cpp int` for JSON integer numbers, `#!cpp bool` for JSON booleans, : type compatible to JSON values, for instance `#!cpp int` for JSON integer numbers, `#!cpp bool` for JSON booleans,
or `#!cpp std::vector` types for JSON arrays. Note the type of the expected value at `key`/`ptr` and the default or `#!cpp std::vector` types for JSON arrays. Note the type of the expected value at `key`/`ptr` and the default
@ -55,7 +67,7 @@ ValueType value(const json_pointer& ptr,
: key of the element to access : key of the element to access
`default_value` (in) `default_value` (in)
: the value to return if key/ptr found no value : the value to return if `key`/`ptr` found no value
`ptr` (in) `ptr` (in)
: a JSON pointer to the element to access : a JSON pointer to the element to access
@ -63,7 +75,8 @@ ValueType value(const json_pointer& ptr,
## Return value ## Return value
1. copy of the element at key `key` or `default_value` if `key` is not found 1. copy of the element at key `key` or `default_value` if `key` is not found
1. copy of the element at JSON Pointer `ptr` or `default_value` if no value for `ptr` is found 2. copy of the element at key `key` or `default_value` if `key` is not found
3. copy of the element at JSON Pointer `ptr` or `default_value` if no value for `ptr` is found
## Exception safety ## Exception safety
@ -77,7 +90,8 @@ changes to any JSON value.
the type of the value at `key` the type of the value at `key`
- Throws [`type_error.306`](../../home/exceptions.md#jsonexceptiontype_error306) if the JSON value is not an object; - Throws [`type_error.306`](../../home/exceptions.md#jsonexceptiontype_error306) if the JSON value is not an object;
in that case, using `value()` with a key makes no sense. in that case, using `value()` with a key makes no sense.
2. The function can throw the following exceptions: 2. See 1.
3. The function can throw the following exceptions:
- Throws [`type_error.302`](../../home/exceptions.md#jsonexceptiontype_error302) if `default_value` does not match - Throws [`type_error.302`](../../home/exceptions.md#jsonexceptiontype_error302) if `default_value` does not match
the type of the value at `ptr` the type of the value at `ptr`
- Throws [`type_error.306`](../../home/exceptions.md#jsonexceptiontype_error306) if the JSON value is not an object; - Throws [`type_error.306`](../../home/exceptions.md#jsonexceptiontype_error306) if the JSON value is not an object;
@ -87,6 +101,7 @@ changes to any JSON value.
1. Logarithmic in the size of the container. 1. Logarithmic in the size of the container.
2. Logarithmic in the size of the container. 2. Logarithmic in the size of the container.
3. Logarithmic in the size of the container.
## Examples ## Examples
@ -104,7 +119,7 @@ changes to any JSON value.
--8<-- "examples/basic_json__value.output" --8<-- "examples/basic_json__value.output"
``` ```
??? example "Example (2): access specified object element via JSON Pointer with default value" ??? example "Example (3): access specified object element via JSON Pointer with default value"
The example below shows how object elements can be queried with a default value. The example below shows how object elements can be queried with a default value.
@ -125,5 +140,6 @@ changes to any JSON value.
## Version history ## Version history
1. Added in version 1.0.0. 1. Added in version 1.0.0. Changed parameter `default_value` type from `const ValueType&` to `ValueType&&` in version 3.11.0.
2. Added in version 2.0.2. 2. Added in version 3.11.0.
3. Added in version 2.0.2.

View File

@ -2006,22 +2006,37 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
reference at(const typename object_t::key_type& key) reference at(const typename object_t::key_type& key)
{ {
// at only works for objects // at only works for objects
if (JSON_HEDLEY_LIKELY(is_object())) if (JSON_HEDLEY_UNLIKELY(!is_object()))
{
JSON_TRY
{
return set_parent(m_value.object->at(key));
}
JSON_CATCH (std::out_of_range&)
{
// create better exception explanation
JSON_THROW(out_of_range::create(403, detail::concat("key '", key, "' not found"), this));
}
}
else
{ {
JSON_THROW(type_error::create(304, detail::concat("cannot use at() with ", type_name()), this)); JSON_THROW(type_error::create(304, detail::concat("cannot use at() with ", type_name()), this));
} }
auto it = m_value.object->find(key);
if (it == m_value.object->end())
{
JSON_THROW(out_of_range::create(403, detail::concat("key '", key, "' not found"), this));
}
return set_parent(it->second);
}
/// @brief access specified object element with bounds checking
/// @sa https://json.nlohmann.me/api/basic_json/at/
template<class KeyType, detail::enable_if_t<
detail::is_usable_as_key_type<basic_json_t, KeyType>::value, int> = 0>
reference at(KeyType && key)
{
// at only works for objects
if (JSON_HEDLEY_UNLIKELY(!is_object()))
{
JSON_THROW(type_error::create(304, detail::concat("cannot use at() with ", type_name()), this));
}
auto it = m_value.object->find(std::forward<KeyType>(key));
if (it == m_value.object->end())
{
JSON_THROW(out_of_range::create(403, detail::concat("key '", string_t(std::forward<KeyType>(key)), "' not found"), this));
}
return set_parent(it->second);
} }
/// @brief access specified object element with bounds checking /// @brief access specified object element with bounds checking
@ -2029,22 +2044,37 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
const_reference at(const typename object_t::key_type& key) const const_reference at(const typename object_t::key_type& key) const
{ {
// at only works for objects // at only works for objects
if (JSON_HEDLEY_LIKELY(is_object())) if (JSON_HEDLEY_UNLIKELY(!is_object()))
{
JSON_TRY
{
return m_value.object->at(key);
}
JSON_CATCH (std::out_of_range&)
{
// create better exception explanation
JSON_THROW(out_of_range::create(403, detail::concat("key '", key, "' not found"), this));
}
}
else
{ {
JSON_THROW(type_error::create(304, detail::concat("cannot use at() with ", type_name()), this)); JSON_THROW(type_error::create(304, detail::concat("cannot use at() with ", type_name()), this));
} }
auto it = m_value.object->find(key);
if (it == m_value.object->end())
{
JSON_THROW(out_of_range::create(403, detail::concat("key '", key, "' not found"), this));
}
return it->second;
}
/// @brief access specified object element with bounds checking
/// @sa https://json.nlohmann.me/api/basic_json/at/
template<class KeyType, detail::enable_if_t<
detail::is_usable_as_key_type<basic_json_t, KeyType>::value, int> = 0>
const_reference at(KeyType && key) const
{
// at only works for objects
if (JSON_HEDLEY_UNLIKELY(!is_object()))
{
JSON_THROW(type_error::create(304, detail::concat("cannot use at() with ", type_name()), this));
}
auto it = m_value.object->find(std::forward<KeyType>(key));
if (it == m_value.object->end())
{
JSON_THROW(out_of_range::create(403, detail::concat("key '", string_t(std::forward<KeyType>(key)), "' not found"), this));
}
return it->second;
} }
/// @brief access specified array element /// @brief access specified array element
@ -2108,7 +2138,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @brief access specified object element /// @brief access specified object element
/// @sa https://json.nlohmann.me/api/basic_json/operator%5B%5D/ /// @sa https://json.nlohmann.me/api/basic_json/operator%5B%5D/
reference operator[](const typename object_t::key_type& key) reference operator[](typename object_t::key_type key)
{ {
// implicitly convert null value to an empty object // implicitly convert null value to an empty object
if (is_null()) if (is_null())
@ -2121,7 +2151,8 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
// operator[] only works for objects // operator[] only works for objects
if (JSON_HEDLEY_LIKELY(is_object())) if (JSON_HEDLEY_LIKELY(is_object()))
{ {
return set_parent(m_value.object->operator[](key)); auto result = m_value.object->emplace(std::move(key), nullptr);
return set_parent(result.first->second);
} }
JSON_THROW(type_error::create(305, detail::concat("cannot use operator[] with a string argument with ", type_name()), this)); JSON_THROW(type_error::create(305, detail::concat("cannot use operator[] with a string argument with ", type_name()), this));
@ -2134,31 +2165,47 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
// const operator[] only works for objects // const operator[] only works for objects
if (JSON_HEDLEY_LIKELY(is_object())) if (JSON_HEDLEY_LIKELY(is_object()))
{ {
JSON_ASSERT(m_value.object->find(key) != m_value.object->end()); auto it = m_value.object->find(key);
return m_value.object->find(key)->second; JSON_ASSERT(it != m_value.object->end());
return it->second;
} }
JSON_THROW(type_error::create(305, detail::concat("cannot use operator[] with a string argument with ", type_name()), this)); JSON_THROW(type_error::create(305, detail::concat("cannot use operator[] with a string argument with ", type_name()), this));
} }
/// @brief access specified object element // these two functions resolve a (const) char * ambiguity affecting Clang and MSVC
/// @sa https://json.nlohmann.me/api/basic_json/operator%5B%5D/ // (they seemingly cannot be constrained to resolve the ambiguity)
template<typename T> template<typename T>
JSON_HEDLEY_NON_NULL(2)
reference operator[](T* key) reference operator[](T* key)
{ {
// implicitly convert null to object return operator[](typename object_t::key_type(key));
}
template<typename T>
const_reference operator[](T* key) const
{
return operator[](typename object_t::key_type(key));
}
/// @brief access specified object element
/// @sa https://json.nlohmann.me/api/basic_json/operator%5B%5D/
template<class KeyType, detail::enable_if_t<
detail::is_usable_as_key_type<basic_json_t, KeyType>::value, int > = 0 >
reference operator[](KeyType && key)
{
// implicitly convert null value to an empty object
if (is_null()) if (is_null())
{ {
m_type = value_t::object; m_type = value_t::object;
m_value = value_t::object; m_value.object = create<object_t>();
assert_invariant(); assert_invariant();
} }
// at only works for objects // operator[] only works for objects
if (JSON_HEDLEY_LIKELY(is_object())) if (JSON_HEDLEY_LIKELY(is_object()))
{ {
return set_parent(m_value.object->operator[](key)); auto result = m_value.object->emplace(std::forward<KeyType>(key), nullptr);
return set_parent(result.first->second);
} }
JSON_THROW(type_error::create(305, detail::concat("cannot use operator[] with a string argument with ", type_name()), this)); JSON_THROW(type_error::create(305, detail::concat("cannot use operator[] with a string argument with ", type_name()), this));
@ -2166,15 +2213,16 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @brief access specified object element /// @brief access specified object element
/// @sa https://json.nlohmann.me/api/basic_json/operator%5B%5D/ /// @sa https://json.nlohmann.me/api/basic_json/operator%5B%5D/
template<typename T> template<class KeyType, detail::enable_if_t<
JSON_HEDLEY_NON_NULL(2) detail::is_usable_as_key_type<basic_json_t, KeyType>::value, int > = 0 >
const_reference operator[](T* key) const const_reference operator[](KeyType && key) const
{ {
// at only works for objects // const operator[] only works for objects
if (JSON_HEDLEY_LIKELY(is_object())) if (JSON_HEDLEY_LIKELY(is_object()))
{ {
JSON_ASSERT(m_value.object->find(key) != m_value.object->end()); auto it = m_value.object->find(std::forward<KeyType>(key));
return m_value.object->find(key)->second; JSON_ASSERT(it != m_value.object->end());
return it->second;
} }
JSON_THROW(type_error::create(305, detail::concat("cannot use operator[] with a string argument with ", type_name()), this)); JSON_THROW(type_error::create(305, detail::concat("cannot use operator[] with a string argument with ", type_name()), this));
@ -2182,23 +2230,24 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @brief access specified object element with default value /// @brief access specified object element with default value
/// @sa https://json.nlohmann.me/api/basic_json/value/ /// @sa https://json.nlohmann.me/api/basic_json/value/
/// using std::is_convertible in a std::enable_if will fail when using explicit conversions // this is the value(const typename object_t::key_type&) overload
template < class ValueType, typename std::enable_if < template < class KeyType, class ValueType, detail::enable_if_t <
detail::is_getable<basic_json_t, ValueType>::value std::is_same<KeyType, typename object_t::key_type>::value
&& !std::is_same<value_t, ValueType>::value, int >::type = 0 > && detail::is_getable<basic_json_t, ValueType>::value
ValueType value(const typename object_t::key_type& key, const ValueType& default_value) const && !std::is_same<value_t, ValueType>::value, int > = 0 >
typename std::decay<ValueType>::type value(const KeyType& key, ValueType && default_value) const
{ {
// at only works for objects // value only works for objects
if (JSON_HEDLEY_LIKELY(is_object())) if (JSON_HEDLEY_LIKELY(is_object()))
{ {
// if key is found, return value and given default value otherwise // if key is found, return value and given default value otherwise
const auto it = find(key); const auto it = find(key);
if (it != end()) if (it != end())
{ {
return it->template get<ValueType>(); return it->template get<typename std::decay<ValueType>::type>();
} }
return default_value; return std::forward<ValueType>(default_value);
} }
JSON_THROW(type_error::create(306, detail::concat("cannot use value() with ", type_name()), this)); JSON_THROW(type_error::create(306, detail::concat("cannot use value() with ", type_name()), this));
@ -2212,13 +2261,64 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
return value(key, string_t(default_value)); return value(key, string_t(default_value));
} }
// these two functions, in conjunction with value(const KeyType &, ValueType &&),
// resolve an ambiguity that would otherwise occur between the json_pointer and
// typename object_t::key_type & overloads
template < class ValueType, detail::enable_if_t <
detail::is_getable<basic_json_t, ValueType>::value
&& !std::is_same<value_t, ValueType>::value, int > = 0 >
typename std::decay<ValueType>::type value(const char* key, ValueType && default_value) const
{
return value(typename object_t::key_type(key), std::forward<ValueType>(default_value));
}
string_t value(const char* key, const char* default_value) const
{
return value(typename object_t::key_type(key), string_t(default_value));
}
/// @brief access specified object element with default value
/// @sa https://json.nlohmann.me/api/basic_json/value/
/// using std::is_convertible in a std::enable_if will fail when using explicit conversions
template < class KeyType, class ValueType, detail::enable_if_t <
detail::is_getable<basic_json_t, ValueType>::value
&& !std::is_same<value_t, ValueType>::value
&& detail::is_usable_as_key_type<basic_json_t, KeyType>::value, int > = 0 >
typename std::decay<ValueType>::type value(KeyType && key, ValueType && default_value) const
{
// value only works for objects
if (JSON_HEDLEY_LIKELY(is_object()))
{
// if key is found, return value and given default value otherwise
const auto it = find(std::forward<KeyType>(key));
if (it != end())
{
return it->template get<typename std::decay<ValueType>::type>();
}
return std::forward<ValueType>(default_value);
}
JSON_THROW(type_error::create(306, detail::concat("cannot use value() with ", type_name()), this));
}
/// @brief access specified object element with default value
/// @sa https://json.nlohmann.me/api/basic_json/value/
/// overload for a default value of type const char*
template < class KeyType, detail::enable_if_t <
!detail::is_json_pointer<KeyType>::value, int > = 0 >
string_t value(KeyType && key, const char* default_value) const
{
return value(std::forward<KeyType>(key), string_t(default_value));
}
/// @brief access specified object element via JSON Pointer with default value /// @brief access specified object element via JSON Pointer with default value
/// @sa https://json.nlohmann.me/api/basic_json/value/ /// @sa https://json.nlohmann.me/api/basic_json/value/
template<class ValueType, typename std::enable_if< template < class ValueType, detail::enable_if_t <
detail::is_getable<basic_json_t, ValueType>::value, int>::type = 0> detail::is_getable<basic_json_t, ValueType>::value, int> = 0 >
ValueType value(const json_pointer& ptr, const ValueType& default_value) const ValueType value(const json_pointer& ptr, const ValueType& default_value) const
{ {
// at only works for objects // value only works for objects
if (JSON_HEDLEY_LIKELY(is_object())) if (JSON_HEDLEY_LIKELY(is_object()))
{ {
// if pointer resolves a value, return it or use default value // if pointer resolves a value, return it or use default value
@ -2235,8 +2335,8 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
JSON_THROW(type_error::create(306, detail::concat("cannot use value() with ", type_name()), this)); JSON_THROW(type_error::create(306, detail::concat("cannot use value() with ", type_name()), this));
} }
template<class ValueType, class BasicJsonType, typename std::enable_if< template < class ValueType, class BasicJsonType, detail::enable_if_t <
detail::is_getable<basic_json_t, ValueType>::value, int>::type = 0> detail::is_getable<basic_json_t, ValueType>::value, int> = 0 >
JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens) JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens)
ValueType value(const ::nlohmann::json_pointer<BasicJsonType>& ptr, const ValueType& default_value) const ValueType value(const ::nlohmann::json_pointer<BasicJsonType>& ptr, const ValueType& default_value) const
{ {
@ -2294,10 +2394,9 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @brief remove element given an iterator /// @brief remove element given an iterator
/// @sa https://json.nlohmann.me/api/basic_json/erase/ /// @sa https://json.nlohmann.me/api/basic_json/erase/
template < class IteratorType, typename std::enable_if < template < class IteratorType, detail::enable_if_t <
std::is_same<IteratorType, typename basic_json_t::iterator>::value || std::is_same<IteratorType, typename basic_json_t::iterator>::value ||
std::is_same<IteratorType, typename basic_json_t::const_iterator>::value, int >::type std::is_same<IteratorType, typename basic_json_t::const_iterator>::value, int > = 0 >
= 0 >
IteratorType erase(IteratorType pos) IteratorType erase(IteratorType pos)
{ {
// make sure iterator fits the current value // make sure iterator fits the current value
@ -2365,10 +2464,9 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @brief remove elements given an iterator range /// @brief remove elements given an iterator range
/// @sa https://json.nlohmann.me/api/basic_json/erase/ /// @sa https://json.nlohmann.me/api/basic_json/erase/
template < class IteratorType, typename std::enable_if < template < class IteratorType, detail::enable_if_t <
std::is_same<IteratorType, typename basic_json_t::iterator>::value || std::is_same<IteratorType, typename basic_json_t::iterator>::value ||
std::is_same<IteratorType, typename basic_json_t::const_iterator>::value, int >::type std::is_same<IteratorType, typename basic_json_t::const_iterator>::value, int > = 0 >
= 0 >
IteratorType erase(IteratorType first, IteratorType last) IteratorType erase(IteratorType first, IteratorType last)
{ {
// make sure iterator fits the current value // make sure iterator fits the current value
@ -2437,17 +2535,57 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
return result; return result;
} }
private:
template < typename KeyType, detail::enable_if_t <
detail::has_erase_with_key_type<basic_json_t, KeyType>::value, int > = 0 >
size_type erase_internal(KeyType && key)
{
// this erase only works for objects
if (JSON_HEDLEY_UNLIKELY(!is_object()))
{
JSON_THROW(type_error::create(307, detail::concat("cannot use erase() with ", type_name()), this));
}
return m_value.object->erase(std::forward<KeyType>(key));
}
template < typename KeyType, detail::enable_if_t <
!detail::has_erase_with_key_type<basic_json_t, KeyType>::value, int > = 0 >
size_type erase_internal(KeyType && key)
{
// this erase only works for objects
if (JSON_HEDLEY_UNLIKELY(!is_object()))
{
JSON_THROW(type_error::create(307, detail::concat("cannot use erase() with ", type_name()), this));
}
const auto it = m_value.object->find(std::forward<KeyType>(key));
if (it != m_value.object->end())
{
m_value.object->erase(it);
return 1;
}
return 0;
}
public:
/// @brief remove element from a JSON object given a key /// @brief remove element from a JSON object given a key
/// @sa https://json.nlohmann.me/api/basic_json/erase/ /// @sa https://json.nlohmann.me/api/basic_json/erase/
size_type erase(const typename object_t::key_type& key) size_type erase(const typename object_t::key_type& key)
{ {
// this erase only works for objects // the indirection via erase_internal() is added to avoid making this
if (JSON_HEDLEY_LIKELY(is_object())) // function a template and thus de-rank it during overload resolution
{ return erase_internal(key);
return m_value.object->erase(key);
} }
JSON_THROW(type_error::create(307, detail::concat("cannot use erase() with ", type_name()), this)); /// @brief remove element from a JSON object given a key
/// @sa https://json.nlohmann.me/api/basic_json/erase/
template<class KeyType, detail::enable_if_t<
detail::is_usable_as_key_type<basic_json_t, KeyType>::value, int> = 0>
size_type erase(KeyType && key)
{
return erase_internal(std::forward<KeyType>(key));
} }
/// @brief remove element from a JSON array given an index /// @brief remove element from a JSON array given an index
@ -2482,14 +2620,13 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @brief find an element in a JSON object /// @brief find an element in a JSON object
/// @sa https://json.nlohmann.me/api/basic_json/find/ /// @sa https://json.nlohmann.me/api/basic_json/find/
template<typename KeyT> iterator find(const typename object_t::key_type& key)
iterator find(KeyT&& key)
{ {
auto result = end(); auto result = end();
if (is_object()) if (is_object())
{ {
result.m_it.object_iterator = m_value.object->find(std::forward<KeyT>(key)); result.m_it.object_iterator = m_value.object->find(key);
} }
return result; return result;
@ -2497,14 +2634,45 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @brief find an element in a JSON object /// @brief find an element in a JSON object
/// @sa https://json.nlohmann.me/api/basic_json/find/ /// @sa https://json.nlohmann.me/api/basic_json/find/
template<typename KeyT> const_iterator find(const typename object_t::key_type& key) const
const_iterator find(KeyT&& key) const
{ {
auto result = cend(); auto result = cend();
if (is_object()) if (is_object())
{ {
result.m_it.object_iterator = m_value.object->find(std::forward<KeyT>(key)); result.m_it.object_iterator = m_value.object->find(key);
}
return result;
}
/// @brief find an element in a JSON object
/// @sa https://json.nlohmann.me/api/basic_json/find/
template<class KeyType, detail::enable_if_t<
detail::is_usable_as_key_type<basic_json_t, KeyType>::value, int> = 0>
iterator find(KeyType && key)
{
auto result = end();
if (is_object())
{
result.m_it.object_iterator = m_value.object->find(std::forward<KeyType>(key));
}
return result;
}
/// @brief find an element in a JSON object
/// @sa https://json.nlohmann.me/api/basic_json/find/
template<class KeyType, detail::enable_if_t<
detail::is_usable_as_key_type<basic_json_t, KeyType>::value, int> = 0>
const_iterator find(KeyType && key) const
{
auto result = cend();
if (is_object())
{
result.m_it.object_iterator = m_value.object->find(std::forward<KeyType>(key));
} }
return result; return result;
@ -2512,20 +2680,36 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @brief returns the number of occurrences of a key in a JSON object /// @brief returns the number of occurrences of a key in a JSON object
/// @sa https://json.nlohmann.me/api/basic_json/count/ /// @sa https://json.nlohmann.me/api/basic_json/count/
template<typename KeyT> size_type count(const typename object_t::key_type& key) const
size_type count(KeyT&& key) const
{ {
// return 0 for all nonobject types // return 0 for all nonobject types
return is_object() ? m_value.object->count(std::forward<KeyT>(key)) : 0; return is_object() ? m_value.object->count(key) : 0;
}
/// @brief returns the number of occurrences of a key in a JSON object
/// @sa https://json.nlohmann.me/api/basic_json/count/
template<class KeyType, detail::enable_if_t<
detail::is_usable_as_key_type<basic_json_t, KeyType>::value, int> = 0>
size_type count(KeyType && key) const
{
// return 0 for all nonobject types
return is_object() ? m_value.object->count(std::forward<KeyType>(key)) : 0;
} }
/// @brief check the existence of an element in a JSON object /// @brief check the existence of an element in a JSON object
/// @sa https://json.nlohmann.me/api/basic_json/contains/ /// @sa https://json.nlohmann.me/api/basic_json/contains/
template < typename KeyT, typename std::enable_if < bool contains(const typename object_t::key_type& key) const
!detail::is_json_pointer<typename std::decay<KeyT>::type>::value, int >::type = 0 >
bool contains(KeyT && key) const
{ {
return is_object() && m_value.object->find(std::forward<KeyT>(key)) != m_value.object->end(); return is_object() && m_value.object->find(key) != m_value.object->end();
}
/// @brief check the existence of an element in a JSON object
/// @sa https://json.nlohmann.me/api/basic_json/contains/
template<class KeyType, detail::enable_if_t<
detail::is_usable_as_key_type<basic_json_t, KeyType>::value, int> = 0>
bool contains(KeyType && key) const
{
return is_object() && m_value.object->find(std::forward<KeyType>(key)) != m_value.object->end();
} }
/// @brief check the existence of an element in a JSON object given a JSON pointer /// @brief check the existence of an element in a JSON object given a JSON pointer
@ -4230,7 +4414,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
return ptr.get_unchecked(this); return ptr.get_unchecked(this);
} }
template<typename BasicJsonType> template<typename BasicJsonType, detail::enable_if_t<detail::is_basic_json<BasicJsonType>::value, int> = 0>
JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens) JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens)
reference operator[](const ::nlohmann::json_pointer<BasicJsonType>& ptr) reference operator[](const ::nlohmann::json_pointer<BasicJsonType>& ptr)
{ {
@ -4244,7 +4428,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
return ptr.get_unchecked(this); return ptr.get_unchecked(this);
} }
template<typename BasicJsonType> template<typename BasicJsonType, detail::enable_if_t<detail::is_basic_json<BasicJsonType>::value, int> = 0>
JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens) JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens)
const_reference operator[](const ::nlohmann::json_pointer<BasicJsonType>& ptr) const const_reference operator[](const ::nlohmann::json_pointer<BasicJsonType>& ptr) const
{ {

View File

@ -19553,22 +19553,37 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
reference at(const typename object_t::key_type& key) reference at(const typename object_t::key_type& key)
{ {
// at only works for objects // at only works for objects
if (JSON_HEDLEY_LIKELY(is_object())) if (JSON_HEDLEY_UNLIKELY(!is_object()))
{
JSON_TRY
{
return set_parent(m_value.object->at(key));
}
JSON_CATCH (std::out_of_range&)
{
// create better exception explanation
JSON_THROW(out_of_range::create(403, detail::concat("key '", key, "' not found"), this));
}
}
else
{ {
JSON_THROW(type_error::create(304, detail::concat("cannot use at() with ", type_name()), this)); JSON_THROW(type_error::create(304, detail::concat("cannot use at() with ", type_name()), this));
} }
auto it = m_value.object->find(key);
if (it == m_value.object->end())
{
JSON_THROW(out_of_range::create(403, detail::concat("key '", key, "' not found"), this));
}
return set_parent(it->second);
}
/// @brief access specified object element with bounds checking
/// @sa https://json.nlohmann.me/api/basic_json/at/
template<class KeyType, detail::enable_if_t<
detail::is_usable_as_key_type<basic_json_t, KeyType>::value, int> = 0>
reference at(KeyType && key)
{
// at only works for objects
if (JSON_HEDLEY_UNLIKELY(!is_object()))
{
JSON_THROW(type_error::create(304, detail::concat("cannot use at() with ", type_name()), this));
}
auto it = m_value.object->find(std::forward<KeyType>(key));
if (it == m_value.object->end())
{
JSON_THROW(out_of_range::create(403, detail::concat("key '", string_t(std::forward<KeyType>(key)), "' not found"), this));
}
return set_parent(it->second);
} }
/// @brief access specified object element with bounds checking /// @brief access specified object element with bounds checking
@ -19576,22 +19591,37 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
const_reference at(const typename object_t::key_type& key) const const_reference at(const typename object_t::key_type& key) const
{ {
// at only works for objects // at only works for objects
if (JSON_HEDLEY_LIKELY(is_object())) if (JSON_HEDLEY_UNLIKELY(!is_object()))
{
JSON_TRY
{
return m_value.object->at(key);
}
JSON_CATCH (std::out_of_range&)
{
// create better exception explanation
JSON_THROW(out_of_range::create(403, detail::concat("key '", key, "' not found"), this));
}
}
else
{ {
JSON_THROW(type_error::create(304, detail::concat("cannot use at() with ", type_name()), this)); JSON_THROW(type_error::create(304, detail::concat("cannot use at() with ", type_name()), this));
} }
auto it = m_value.object->find(key);
if (it == m_value.object->end())
{
JSON_THROW(out_of_range::create(403, detail::concat("key '", key, "' not found"), this));
}
return it->second;
}
/// @brief access specified object element with bounds checking
/// @sa https://json.nlohmann.me/api/basic_json/at/
template<class KeyType, detail::enable_if_t<
detail::is_usable_as_key_type<basic_json_t, KeyType>::value, int> = 0>
const_reference at(KeyType && key) const
{
// at only works for objects
if (JSON_HEDLEY_UNLIKELY(!is_object()))
{
JSON_THROW(type_error::create(304, detail::concat("cannot use at() with ", type_name()), this));
}
auto it = m_value.object->find(std::forward<KeyType>(key));
if (it == m_value.object->end())
{
JSON_THROW(out_of_range::create(403, detail::concat("key '", string_t(std::forward<KeyType>(key)), "' not found"), this));
}
return it->second;
} }
/// @brief access specified array element /// @brief access specified array element
@ -19655,7 +19685,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @brief access specified object element /// @brief access specified object element
/// @sa https://json.nlohmann.me/api/basic_json/operator%5B%5D/ /// @sa https://json.nlohmann.me/api/basic_json/operator%5B%5D/
reference operator[](const typename object_t::key_type& key) reference operator[](typename object_t::key_type key)
{ {
// implicitly convert null value to an empty object // implicitly convert null value to an empty object
if (is_null()) if (is_null())
@ -19668,7 +19698,8 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
// operator[] only works for objects // operator[] only works for objects
if (JSON_HEDLEY_LIKELY(is_object())) if (JSON_HEDLEY_LIKELY(is_object()))
{ {
return set_parent(m_value.object->operator[](key)); auto result = m_value.object->emplace(std::move(key), nullptr);
return set_parent(result.first->second);
} }
JSON_THROW(type_error::create(305, detail::concat("cannot use operator[] with a string argument with ", type_name()), this)); JSON_THROW(type_error::create(305, detail::concat("cannot use operator[] with a string argument with ", type_name()), this));
@ -19681,31 +19712,47 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
// const operator[] only works for objects // const operator[] only works for objects
if (JSON_HEDLEY_LIKELY(is_object())) if (JSON_HEDLEY_LIKELY(is_object()))
{ {
JSON_ASSERT(m_value.object->find(key) != m_value.object->end()); auto it = m_value.object->find(key);
return m_value.object->find(key)->second; JSON_ASSERT(it != m_value.object->end());
return it->second;
} }
JSON_THROW(type_error::create(305, detail::concat("cannot use operator[] with a string argument with ", type_name()), this)); JSON_THROW(type_error::create(305, detail::concat("cannot use operator[] with a string argument with ", type_name()), this));
} }
/// @brief access specified object element // these two functions resolve a (const) char * ambiguity affecting Clang and MSVC
/// @sa https://json.nlohmann.me/api/basic_json/operator%5B%5D/ // (they seemingly cannot be constrained to resolve the ambiguity)
template<typename T> template<typename T>
JSON_HEDLEY_NON_NULL(2)
reference operator[](T* key) reference operator[](T* key)
{ {
// implicitly convert null to object return operator[](typename object_t::key_type(key));
}
template<typename T>
const_reference operator[](T* key) const
{
return operator[](typename object_t::key_type(key));
}
/// @brief access specified object element
/// @sa https://json.nlohmann.me/api/basic_json/operator%5B%5D/
template<class KeyType, detail::enable_if_t<
detail::is_usable_as_key_type<basic_json_t, KeyType>::value, int > = 0 >
reference operator[](KeyType && key)
{
// implicitly convert null value to an empty object
if (is_null()) if (is_null())
{ {
m_type = value_t::object; m_type = value_t::object;
m_value = value_t::object; m_value.object = create<object_t>();
assert_invariant(); assert_invariant();
} }
// at only works for objects // operator[] only works for objects
if (JSON_HEDLEY_LIKELY(is_object())) if (JSON_HEDLEY_LIKELY(is_object()))
{ {
return set_parent(m_value.object->operator[](key)); auto result = m_value.object->emplace(std::forward<KeyType>(key), nullptr);
return set_parent(result.first->second);
} }
JSON_THROW(type_error::create(305, detail::concat("cannot use operator[] with a string argument with ", type_name()), this)); JSON_THROW(type_error::create(305, detail::concat("cannot use operator[] with a string argument with ", type_name()), this));
@ -19713,15 +19760,16 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @brief access specified object element /// @brief access specified object element
/// @sa https://json.nlohmann.me/api/basic_json/operator%5B%5D/ /// @sa https://json.nlohmann.me/api/basic_json/operator%5B%5D/
template<typename T> template<class KeyType, detail::enable_if_t<
JSON_HEDLEY_NON_NULL(2) detail::is_usable_as_key_type<basic_json_t, KeyType>::value, int > = 0 >
const_reference operator[](T* key) const const_reference operator[](KeyType && key) const
{ {
// at only works for objects // const operator[] only works for objects
if (JSON_HEDLEY_LIKELY(is_object())) if (JSON_HEDLEY_LIKELY(is_object()))
{ {
JSON_ASSERT(m_value.object->find(key) != m_value.object->end()); auto it = m_value.object->find(std::forward<KeyType>(key));
return m_value.object->find(key)->second; JSON_ASSERT(it != m_value.object->end());
return it->second;
} }
JSON_THROW(type_error::create(305, detail::concat("cannot use operator[] with a string argument with ", type_name()), this)); JSON_THROW(type_error::create(305, detail::concat("cannot use operator[] with a string argument with ", type_name()), this));
@ -19729,23 +19777,24 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @brief access specified object element with default value /// @brief access specified object element with default value
/// @sa https://json.nlohmann.me/api/basic_json/value/ /// @sa https://json.nlohmann.me/api/basic_json/value/
/// using std::is_convertible in a std::enable_if will fail when using explicit conversions // this is the value(const typename object_t::key_type&) overload
template < class ValueType, typename std::enable_if < template < class KeyType, class ValueType, detail::enable_if_t <
detail::is_getable<basic_json_t, ValueType>::value std::is_same<KeyType, typename object_t::key_type>::value
&& !std::is_same<value_t, ValueType>::value, int >::type = 0 > && detail::is_getable<basic_json_t, ValueType>::value
ValueType value(const typename object_t::key_type& key, const ValueType& default_value) const && !std::is_same<value_t, ValueType>::value, int > = 0 >
typename std::decay<ValueType>::type value(const KeyType& key, ValueType && default_value) const
{ {
// at only works for objects // value only works for objects
if (JSON_HEDLEY_LIKELY(is_object())) if (JSON_HEDLEY_LIKELY(is_object()))
{ {
// if key is found, return value and given default value otherwise // if key is found, return value and given default value otherwise
const auto it = find(key); const auto it = find(key);
if (it != end()) if (it != end())
{ {
return it->template get<ValueType>(); return it->template get<typename std::decay<ValueType>::type>();
} }
return default_value; return std::forward<ValueType>(default_value);
} }
JSON_THROW(type_error::create(306, detail::concat("cannot use value() with ", type_name()), this)); JSON_THROW(type_error::create(306, detail::concat("cannot use value() with ", type_name()), this));
@ -19759,13 +19808,64 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
return value(key, string_t(default_value)); return value(key, string_t(default_value));
} }
// these two functions, in conjunction with value(const KeyType &, ValueType &&),
// resolve an ambiguity that would otherwise occur between the json_pointer and
// typename object_t::key_type & overloads
template < class ValueType, detail::enable_if_t <
detail::is_getable<basic_json_t, ValueType>::value
&& !std::is_same<value_t, ValueType>::value, int > = 0 >
typename std::decay<ValueType>::type value(const char* key, ValueType && default_value) const
{
return value(typename object_t::key_type(key), std::forward<ValueType>(default_value));
}
string_t value(const char* key, const char* default_value) const
{
return value(typename object_t::key_type(key), string_t(default_value));
}
/// @brief access specified object element with default value
/// @sa https://json.nlohmann.me/api/basic_json/value/
/// using std::is_convertible in a std::enable_if will fail when using explicit conversions
template < class KeyType, class ValueType, detail::enable_if_t <
detail::is_getable<basic_json_t, ValueType>::value
&& !std::is_same<value_t, ValueType>::value
&& detail::is_usable_as_key_type<basic_json_t, KeyType>::value, int > = 0 >
typename std::decay<ValueType>::type value(KeyType && key, ValueType && default_value) const
{
// value only works for objects
if (JSON_HEDLEY_LIKELY(is_object()))
{
// if key is found, return value and given default value otherwise
const auto it = find(std::forward<KeyType>(key));
if (it != end())
{
return it->template get<typename std::decay<ValueType>::type>();
}
return std::forward<ValueType>(default_value);
}
JSON_THROW(type_error::create(306, detail::concat("cannot use value() with ", type_name()), this));
}
/// @brief access specified object element with default value
/// @sa https://json.nlohmann.me/api/basic_json/value/
/// overload for a default value of type const char*
template < class KeyType, detail::enable_if_t <
!detail::is_json_pointer<KeyType>::value, int > = 0 >
string_t value(KeyType && key, const char* default_value) const
{
return value(std::forward<KeyType>(key), string_t(default_value));
}
/// @brief access specified object element via JSON Pointer with default value /// @brief access specified object element via JSON Pointer with default value
/// @sa https://json.nlohmann.me/api/basic_json/value/ /// @sa https://json.nlohmann.me/api/basic_json/value/
template<class ValueType, typename std::enable_if< template < class ValueType, detail::enable_if_t <
detail::is_getable<basic_json_t, ValueType>::value, int>::type = 0> detail::is_getable<basic_json_t, ValueType>::value, int> = 0 >
ValueType value(const json_pointer& ptr, const ValueType& default_value) const ValueType value(const json_pointer& ptr, const ValueType& default_value) const
{ {
// at only works for objects // value only works for objects
if (JSON_HEDLEY_LIKELY(is_object())) if (JSON_HEDLEY_LIKELY(is_object()))
{ {
// if pointer resolves a value, return it or use default value // if pointer resolves a value, return it or use default value
@ -19782,8 +19882,8 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
JSON_THROW(type_error::create(306, detail::concat("cannot use value() with ", type_name()), this)); JSON_THROW(type_error::create(306, detail::concat("cannot use value() with ", type_name()), this));
} }
template<class ValueType, class BasicJsonType, typename std::enable_if< template < class ValueType, class BasicJsonType, detail::enable_if_t <
detail::is_getable<basic_json_t, ValueType>::value, int>::type = 0> detail::is_getable<basic_json_t, ValueType>::value, int> = 0 >
JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens) JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens)
ValueType value(const ::nlohmann::json_pointer<BasicJsonType>& ptr, const ValueType& default_value) const ValueType value(const ::nlohmann::json_pointer<BasicJsonType>& ptr, const ValueType& default_value) const
{ {
@ -19841,10 +19941,9 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @brief remove element given an iterator /// @brief remove element given an iterator
/// @sa https://json.nlohmann.me/api/basic_json/erase/ /// @sa https://json.nlohmann.me/api/basic_json/erase/
template < class IteratorType, typename std::enable_if < template < class IteratorType, detail::enable_if_t <
std::is_same<IteratorType, typename basic_json_t::iterator>::value || std::is_same<IteratorType, typename basic_json_t::iterator>::value ||
std::is_same<IteratorType, typename basic_json_t::const_iterator>::value, int >::type std::is_same<IteratorType, typename basic_json_t::const_iterator>::value, int > = 0 >
= 0 >
IteratorType erase(IteratorType pos) IteratorType erase(IteratorType pos)
{ {
// make sure iterator fits the current value // make sure iterator fits the current value
@ -19912,10 +20011,9 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @brief remove elements given an iterator range /// @brief remove elements given an iterator range
/// @sa https://json.nlohmann.me/api/basic_json/erase/ /// @sa https://json.nlohmann.me/api/basic_json/erase/
template < class IteratorType, typename std::enable_if < template < class IteratorType, detail::enable_if_t <
std::is_same<IteratorType, typename basic_json_t::iterator>::value || std::is_same<IteratorType, typename basic_json_t::iterator>::value ||
std::is_same<IteratorType, typename basic_json_t::const_iterator>::value, int >::type std::is_same<IteratorType, typename basic_json_t::const_iterator>::value, int > = 0 >
= 0 >
IteratorType erase(IteratorType first, IteratorType last) IteratorType erase(IteratorType first, IteratorType last)
{ {
// make sure iterator fits the current value // make sure iterator fits the current value
@ -19984,17 +20082,57 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
return result; return result;
} }
private:
template < typename KeyType, detail::enable_if_t <
detail::has_erase_with_key_type<basic_json_t, KeyType>::value, int > = 0 >
size_type erase_internal(KeyType && key)
{
// this erase only works for objects
if (JSON_HEDLEY_UNLIKELY(!is_object()))
{
JSON_THROW(type_error::create(307, detail::concat("cannot use erase() with ", type_name()), this));
}
return m_value.object->erase(std::forward<KeyType>(key));
}
template < typename KeyType, detail::enable_if_t <
!detail::has_erase_with_key_type<basic_json_t, KeyType>::value, int > = 0 >
size_type erase_internal(KeyType && key)
{
// this erase only works for objects
if (JSON_HEDLEY_UNLIKELY(!is_object()))
{
JSON_THROW(type_error::create(307, detail::concat("cannot use erase() with ", type_name()), this));
}
const auto it = m_value.object->find(std::forward<KeyType>(key));
if (it != m_value.object->end())
{
m_value.object->erase(it);
return 1;
}
return 0;
}
public:
/// @brief remove element from a JSON object given a key /// @brief remove element from a JSON object given a key
/// @sa https://json.nlohmann.me/api/basic_json/erase/ /// @sa https://json.nlohmann.me/api/basic_json/erase/
size_type erase(const typename object_t::key_type& key) size_type erase(const typename object_t::key_type& key)
{ {
// this erase only works for objects // the indirection via erase_internal() is added to avoid making this
if (JSON_HEDLEY_LIKELY(is_object())) // function a template and thus de-rank it during overload resolution
{ return erase_internal(key);
return m_value.object->erase(key);
} }
JSON_THROW(type_error::create(307, detail::concat("cannot use erase() with ", type_name()), this)); /// @brief remove element from a JSON object given a key
/// @sa https://json.nlohmann.me/api/basic_json/erase/
template<class KeyType, detail::enable_if_t<
detail::is_usable_as_key_type<basic_json_t, KeyType>::value, int> = 0>
size_type erase(KeyType && key)
{
return erase_internal(std::forward<KeyType>(key));
} }
/// @brief remove element from a JSON array given an index /// @brief remove element from a JSON array given an index
@ -20029,14 +20167,13 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @brief find an element in a JSON object /// @brief find an element in a JSON object
/// @sa https://json.nlohmann.me/api/basic_json/find/ /// @sa https://json.nlohmann.me/api/basic_json/find/
template<typename KeyT> iterator find(const typename object_t::key_type& key)
iterator find(KeyT&& key)
{ {
auto result = end(); auto result = end();
if (is_object()) if (is_object())
{ {
result.m_it.object_iterator = m_value.object->find(std::forward<KeyT>(key)); result.m_it.object_iterator = m_value.object->find(key);
} }
return result; return result;
@ -20044,14 +20181,45 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @brief find an element in a JSON object /// @brief find an element in a JSON object
/// @sa https://json.nlohmann.me/api/basic_json/find/ /// @sa https://json.nlohmann.me/api/basic_json/find/
template<typename KeyT> const_iterator find(const typename object_t::key_type& key) const
const_iterator find(KeyT&& key) const
{ {
auto result = cend(); auto result = cend();
if (is_object()) if (is_object())
{ {
result.m_it.object_iterator = m_value.object->find(std::forward<KeyT>(key)); result.m_it.object_iterator = m_value.object->find(key);
}
return result;
}
/// @brief find an element in a JSON object
/// @sa https://json.nlohmann.me/api/basic_json/find/
template<class KeyType, detail::enable_if_t<
detail::is_usable_as_key_type<basic_json_t, KeyType>::value, int> = 0>
iterator find(KeyType && key)
{
auto result = end();
if (is_object())
{
result.m_it.object_iterator = m_value.object->find(std::forward<KeyType>(key));
}
return result;
}
/// @brief find an element in a JSON object
/// @sa https://json.nlohmann.me/api/basic_json/find/
template<class KeyType, detail::enable_if_t<
detail::is_usable_as_key_type<basic_json_t, KeyType>::value, int> = 0>
const_iterator find(KeyType && key) const
{
auto result = cend();
if (is_object())
{
result.m_it.object_iterator = m_value.object->find(std::forward<KeyType>(key));
} }
return result; return result;
@ -20059,20 +20227,36 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @brief returns the number of occurrences of a key in a JSON object /// @brief returns the number of occurrences of a key in a JSON object
/// @sa https://json.nlohmann.me/api/basic_json/count/ /// @sa https://json.nlohmann.me/api/basic_json/count/
template<typename KeyT> size_type count(const typename object_t::key_type& key) const
size_type count(KeyT&& key) const
{ {
// return 0 for all nonobject types // return 0 for all nonobject types
return is_object() ? m_value.object->count(std::forward<KeyT>(key)) : 0; return is_object() ? m_value.object->count(key) : 0;
}
/// @brief returns the number of occurrences of a key in a JSON object
/// @sa https://json.nlohmann.me/api/basic_json/count/
template<class KeyType, detail::enable_if_t<
detail::is_usable_as_key_type<basic_json_t, KeyType>::value, int> = 0>
size_type count(KeyType && key) const
{
// return 0 for all nonobject types
return is_object() ? m_value.object->count(std::forward<KeyType>(key)) : 0;
} }
/// @brief check the existence of an element in a JSON object /// @brief check the existence of an element in a JSON object
/// @sa https://json.nlohmann.me/api/basic_json/contains/ /// @sa https://json.nlohmann.me/api/basic_json/contains/
template < typename KeyT, typename std::enable_if < bool contains(const typename object_t::key_type& key) const
!detail::is_json_pointer<typename std::decay<KeyT>::type>::value, int >::type = 0 >
bool contains(KeyT && key) const
{ {
return is_object() && m_value.object->find(std::forward<KeyT>(key)) != m_value.object->end(); return is_object() && m_value.object->find(key) != m_value.object->end();
}
/// @brief check the existence of an element in a JSON object
/// @sa https://json.nlohmann.me/api/basic_json/contains/
template<class KeyType, detail::enable_if_t<
detail::is_usable_as_key_type<basic_json_t, KeyType>::value, int> = 0>
bool contains(KeyType && key) const
{
return is_object() && m_value.object->find(std::forward<KeyType>(key)) != m_value.object->end();
} }
/// @brief check the existence of an element in a JSON object given a JSON pointer /// @brief check the existence of an element in a JSON object given a JSON pointer
@ -21777,7 +21961,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
return ptr.get_unchecked(this); return ptr.get_unchecked(this);
} }
template<typename BasicJsonType> template<typename BasicJsonType, detail::enable_if_t<detail::is_basic_json<BasicJsonType>::value, int> = 0>
JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens) JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens)
reference operator[](const ::nlohmann::json_pointer<BasicJsonType>& ptr) reference operator[](const ::nlohmann::json_pointer<BasicJsonType>& ptr)
{ {
@ -21791,7 +21975,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
return ptr.get_unchecked(this); return ptr.get_unchecked(this);
} }
template<typename BasicJsonType> template<typename BasicJsonType, detail::enable_if_t<detail::is_basic_json<BasicJsonType>::value, int> = 0>
JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens) JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens)
const_reference operator[](const ::nlohmann::json_pointer<BasicJsonType>& ptr) const const_reference operator[](const ::nlohmann::json_pointer<BasicJsonType>& ptr) const
{ {

View File

@ -60,12 +60,38 @@ TEST_CASE("element access 2")
CHECK(j_const.at("floating") == json(42.23)); CHECK(j_const.at("floating") == json(42.23));
CHECK(j_const.at("object") == json::object()); CHECK(j_const.at("object") == json::object());
CHECK(j_const.at("array") == json({1, 2, 3})); CHECK(j_const.at("array") == json({1, 2, 3}));
#ifdef JSON_HAS_CPP_17
CHECK(j.at(std::string_view("integer")) == json(1));
CHECK(j.at(std::string_view("unsigned")) == json(1u));
CHECK(j.at(std::string_view("boolean")) == json(true));
CHECK(j.at(std::string_view("null")) == json(nullptr));
CHECK(j.at(std::string_view("string")) == json("hello world"));
CHECK(j.at(std::string_view("floating")) == json(42.23));
CHECK(j.at(std::string_view("object")) == json::object());
CHECK(j.at(std::string_view("array")) == json({1, 2, 3}));
CHECK(j_const.at(std::string_view("integer")) == json(1));
CHECK(j_const.at(std::string_view("unsigned")) == json(1u));
CHECK(j_const.at(std::string_view("boolean")) == json(true));
CHECK(j_const.at(std::string_view("null")) == json(nullptr));
CHECK(j_const.at(std::string_view("string")) == json("hello world"));
CHECK(j_const.at(std::string_view("floating")) == json(42.23));
CHECK(j_const.at(std::string_view("object")) == json::object());
CHECK(j_const.at(std::string_view("array")) == json({1, 2, 3}));
#endif
} }
SECTION("access outside bounds") SECTION("access outside bounds")
{ {
CHECK_THROWS_WITH_AS(j.at("foo"), "[json.exception.out_of_range.403] key 'foo' not found", json::out_of_range&); CHECK_THROWS_WITH_AS(j.at("foo"), "[json.exception.out_of_range.403] key 'foo' not found", json::out_of_range&);
CHECK_THROWS_WITH_AS(j_const.at("foo"), "[json.exception.out_of_range.403] key 'foo' not found", json::out_of_range&); CHECK_THROWS_WITH_AS(j_const.at("foo"), "[json.exception.out_of_range.403] key 'foo' not found", json::out_of_range&);
#ifdef JSON_HAS_CPP_17
CHECK_THROWS_WITH_AS(j.at(std::string_view("foo")), "[json.exception.out_of_range.403] key 'foo' not found", json::out_of_range&);
CHECK_THROWS_WITH_AS(j_const.at(std::string_view("foo")), "[json.exception.out_of_range.403] key 'foo' not found", json::out_of_range&);
#endif
} }
SECTION("access on non-object type") SECTION("access on non-object type")
@ -76,6 +102,11 @@ TEST_CASE("element access 2")
const json j_nonobject_const(j_nonobject); const json j_nonobject_const(j_nonobject);
CHECK_THROWS_WITH_AS(j_nonobject.at("foo"), "[json.exception.type_error.304] cannot use at() with null", json::type_error&); CHECK_THROWS_WITH_AS(j_nonobject.at("foo"), "[json.exception.type_error.304] cannot use at() with null", json::type_error&);
CHECK_THROWS_WITH_AS(j_nonobject_const.at("foo"), "[json.exception.type_error.304] cannot use at() with null", json::type_error&); CHECK_THROWS_WITH_AS(j_nonobject_const.at("foo"), "[json.exception.type_error.304] cannot use at() with null", json::type_error&);
#ifdef JSON_HAS_CPP_17
CHECK_THROWS_WITH_AS(j_nonobject.at(std::string_view(std::string_view("foo"))), "[json.exception.type_error.304] cannot use at() with null", json::type_error&);
CHECK_THROWS_WITH_AS(j_nonobject_const.at(std::string_view(std::string_view("foo"))), "[json.exception.type_error.304] cannot use at() with null", json::type_error&);
#endif
} }
SECTION("boolean") SECTION("boolean")
@ -84,6 +115,11 @@ TEST_CASE("element access 2")
const json j_nonobject_const(j_nonobject); const json j_nonobject_const(j_nonobject);
CHECK_THROWS_WITH_AS(j_nonobject.at("foo"), "[json.exception.type_error.304] cannot use at() with boolean", json::type_error&); CHECK_THROWS_WITH_AS(j_nonobject.at("foo"), "[json.exception.type_error.304] cannot use at() with boolean", json::type_error&);
CHECK_THROWS_WITH_AS(j_nonobject_const.at("foo"), "[json.exception.type_error.304] cannot use at() with boolean", json::type_error&); CHECK_THROWS_WITH_AS(j_nonobject_const.at("foo"), "[json.exception.type_error.304] cannot use at() with boolean", json::type_error&);
#ifdef JSON_HAS_CPP_17
CHECK_THROWS_WITH_AS(j_nonobject.at(std::string_view("foo")), "[json.exception.type_error.304] cannot use at() with boolean", json::type_error&);
CHECK_THROWS_WITH_AS(j_nonobject_const.at(std::string_view("foo")), "[json.exception.type_error.304] cannot use at() with boolean", json::type_error&);
#endif
} }
SECTION("string") SECTION("string")
@ -92,6 +128,11 @@ TEST_CASE("element access 2")
const json j_nonobject_const(j_nonobject); const json j_nonobject_const(j_nonobject);
CHECK_THROWS_WITH_AS(j_nonobject.at("foo"), "[json.exception.type_error.304] cannot use at() with string", json::type_error&); CHECK_THROWS_WITH_AS(j_nonobject.at("foo"), "[json.exception.type_error.304] cannot use at() with string", json::type_error&);
CHECK_THROWS_WITH_AS(j_nonobject_const.at("foo"), "[json.exception.type_error.304] cannot use at() with string", json::type_error&); CHECK_THROWS_WITH_AS(j_nonobject_const.at("foo"), "[json.exception.type_error.304] cannot use at() with string", json::type_error&);
#ifdef JSON_HAS_CPP_17
CHECK_THROWS_WITH_AS(j_nonobject.at(std::string_view("foo")), "[json.exception.type_error.304] cannot use at() with string", json::type_error&);
CHECK_THROWS_WITH_AS(j_nonobject_const.at(std::string_view("foo")), "[json.exception.type_error.304] cannot use at() with string", json::type_error&);
#endif
} }
SECTION("array") SECTION("array")
@ -100,6 +141,11 @@ TEST_CASE("element access 2")
const json j_nonobject_const(j_nonobject); const json j_nonobject_const(j_nonobject);
CHECK_THROWS_WITH_AS(j_nonobject.at("foo"), "[json.exception.type_error.304] cannot use at() with array", json::type_error&); CHECK_THROWS_WITH_AS(j_nonobject.at("foo"), "[json.exception.type_error.304] cannot use at() with array", json::type_error&);
CHECK_THROWS_WITH_AS(j_nonobject_const.at("foo"), "[json.exception.type_error.304] cannot use at() with array", json::type_error&); CHECK_THROWS_WITH_AS(j_nonobject_const.at("foo"), "[json.exception.type_error.304] cannot use at() with array", json::type_error&);
#ifdef JSON_HAS_CPP_17
CHECK_THROWS_WITH_AS(j_nonobject.at(std::string_view("foo")), "[json.exception.type_error.304] cannot use at() with array", json::type_error&);
CHECK_THROWS_WITH_AS(j_nonobject_const.at(std::string_view("foo")), "[json.exception.type_error.304] cannot use at() with array", json::type_error&);
#endif
} }
SECTION("number (integer)") SECTION("number (integer)")
@ -108,6 +154,11 @@ TEST_CASE("element access 2")
const json j_nonobject_const(j_nonobject); const json j_nonobject_const(j_nonobject);
CHECK_THROWS_WITH_AS(j_nonobject.at("foo"), "[json.exception.type_error.304] cannot use at() with number", json::type_error&); CHECK_THROWS_WITH_AS(j_nonobject.at("foo"), "[json.exception.type_error.304] cannot use at() with number", json::type_error&);
CHECK_THROWS_WITH_AS(j_nonobject_const.at("foo"), "[json.exception.type_error.304] cannot use at() with number", json::type_error&); CHECK_THROWS_WITH_AS(j_nonobject_const.at("foo"), "[json.exception.type_error.304] cannot use at() with number", json::type_error&);
#ifdef JSON_HAS_CPP_17
CHECK_THROWS_WITH_AS(j_nonobject.at(std::string_view("foo")), "[json.exception.type_error.304] cannot use at() with number", json::type_error&);
CHECK_THROWS_WITH_AS(j_nonobject_const.at(std::string_view("foo")), "[json.exception.type_error.304] cannot use at() with number", json::type_error&);
#endif
} }
SECTION("number (unsigned)") SECTION("number (unsigned)")
@ -116,6 +167,11 @@ TEST_CASE("element access 2")
const json j_nonobject_const(j_nonobject); const json j_nonobject_const(j_nonobject);
CHECK_THROWS_WITH_AS(j_nonobject.at("foo"), "[json.exception.type_error.304] cannot use at() with number", json::type_error&); CHECK_THROWS_WITH_AS(j_nonobject.at("foo"), "[json.exception.type_error.304] cannot use at() with number", json::type_error&);
CHECK_THROWS_WITH_AS(j_nonobject_const.at("foo"), "[json.exception.type_error.304] cannot use at() with number", json::type_error&); CHECK_THROWS_WITH_AS(j_nonobject_const.at("foo"), "[json.exception.type_error.304] cannot use at() with number", json::type_error&);
#ifdef JSON_HAS_CPP_17
CHECK_THROWS_WITH_AS(j_nonobject.at(std::string_view("foo")), "[json.exception.type_error.304] cannot use at() with number", json::type_error&);
CHECK_THROWS_WITH_AS(j_nonobject_const.at(std::string_view("foo")), "[json.exception.type_error.304] cannot use at() with number", json::type_error&);
#endif
} }
SECTION("number (floating-point)") SECTION("number (floating-point)")
@ -124,6 +180,11 @@ TEST_CASE("element access 2")
const json j_nonobject_const(j_nonobject); const json j_nonobject_const(j_nonobject);
CHECK_THROWS_WITH_AS(j_nonobject.at("foo"), "[json.exception.type_error.304] cannot use at() with number", json::type_error&); CHECK_THROWS_WITH_AS(j_nonobject.at("foo"), "[json.exception.type_error.304] cannot use at() with number", json::type_error&);
CHECK_THROWS_WITH_AS(j_nonobject_const.at("foo"), "[json.exception.type_error.304] cannot use at() with number", json::type_error&); CHECK_THROWS_WITH_AS(j_nonobject_const.at("foo"), "[json.exception.type_error.304] cannot use at() with number", json::type_error&);
#ifdef JSON_HAS_CPP_17
CHECK_THROWS_WITH_AS(j_nonobject.at(std::string_view("foo")), "[json.exception.type_error.304] cannot use at() with number", json::type_error&);
CHECK_THROWS_WITH_AS(j_nonobject_const.at(std::string_view("foo")), "[json.exception.type_error.304] cannot use at() with number", json::type_error&);
#endif
} }
} }
} }
@ -158,6 +219,33 @@ TEST_CASE("element access 2")
CHECK(j_const.value("floating", 12) == 42); CHECK(j_const.value("floating", 12) == 42);
CHECK(j_const.value("object", json({{"foo", "bar"}})) == json::object()); CHECK(j_const.value("object", json({{"foo", "bar"}})) == json::object());
CHECK(j_const.value("array", json({10, 100})) == json({1, 2, 3})); CHECK(j_const.value("array", json({10, 100})) == json({1, 2, 3}));
#ifdef JSON_HAS_CPP_17
CHECK(j.value(std::string_view("integer"), 2) == 1);
CHECK(j.value(std::string_view("integer"), 1.0) == Approx(1));
CHECK(j.value(std::string_view("unsigned"), 2) == 1u);
CHECK(j.value(std::string_view("unsigned"), 1.0) == Approx(1u));
CHECK(j.value(std::string_view("null"), json(1)) == json());
CHECK(j.value(std::string_view("boolean"), false) == true);
CHECK(j.value(std::string_view("string"), "bar") == "hello world");
CHECK(j.value(std::string_view("string"), std::string("bar")) == "hello world");
CHECK(j.value(std::string_view("floating"), 12.34) == Approx(42.23));
CHECK(j.value(std::string_view("floating"), 12) == 42);
CHECK(j.value(std::string_view("object"), json({{"foo", "bar"}})) == json::object());
CHECK(j.value(std::string_view("array"), json({10, 100})) == json({1, 2, 3}));
CHECK(j_const.value(std::string_view("integer"), 2) == 1);
CHECK(j_const.value(std::string_view("integer"), 1.0) == Approx(1));
CHECK(j_const.value(std::string_view("unsigned"), 2) == 1u);
CHECK(j_const.value(std::string_view("unsigned"), 1.0) == Approx(1u));
CHECK(j_const.value(std::string_view("boolean"), false) == true);
CHECK(j_const.value(std::string_view("string"), "bar") == "hello world");
CHECK(j_const.value(std::string_view("string"), std::string("bar")) == "hello world");
CHECK(j_const.value(std::string_view("floating"), 12.34) == Approx(42.23));
CHECK(j_const.value(std::string_view("floating"), 12) == 42);
CHECK(j_const.value(std::string_view("object"), json({{"foo", "bar"}})) == json::object());
CHECK(j_const.value(std::string_view("array"), json({10, 100})) == json({1, 2, 3}));
#endif
} }
SECTION("access non-existing value") SECTION("access non-existing value")
@ -177,6 +265,24 @@ TEST_CASE("element access 2")
CHECK(j_const.value("_", 12.34) == Approx(12.34)); CHECK(j_const.value("_", 12.34) == Approx(12.34));
CHECK(j_const.value("_", json({{"foo", "bar"}})) == json({{"foo", "bar"}})); CHECK(j_const.value("_", json({{"foo", "bar"}})) == json({{"foo", "bar"}}));
CHECK(j_const.value("_", json({10, 100})) == json({10, 100})); CHECK(j_const.value("_", json({10, 100})) == json({10, 100}));
#ifdef JSON_HAS_CPP_17
CHECK(j.value(std::string_view("_"), 2) == 2);
CHECK(j.value(std::string_view("_"), 2u) == 2u);
CHECK(j.value(std::string_view("_"), false) == false);
CHECK(j.value(std::string_view("_"), "bar") == "bar");
CHECK(j.value(std::string_view("_"), 12.34) == Approx(12.34));
CHECK(j.value(std::string_view("_"), json({{"foo", "bar"}})) == json({{"foo", "bar"}}));
CHECK(j.value(std::string_view("_"), json({10, 100})) == json({10, 100}));
CHECK(j_const.value(std::string_view("_"), 2) == 2);
CHECK(j_const.value(std::string_view("_"), 2u) == 2u);
CHECK(j_const.value(std::string_view("_"), false) == false);
CHECK(j_const.value(std::string_view("_"), "bar") == "bar");
CHECK(j_const.value(std::string_view("_"), 12.34) == Approx(12.34));
CHECK(j_const.value(std::string_view("_"), json({{"foo", "bar"}})) == json({{"foo", "bar"}}));
CHECK(j_const.value(std::string_view("_"), json({10, 100})) == json({10, 100}));
#endif
} }
SECTION("access on non-object type") SECTION("access on non-object type")
@ -187,6 +293,11 @@ TEST_CASE("element access 2")
const json j_nonobject_const(json::value_t::null); const json j_nonobject_const(json::value_t::null);
CHECK_THROWS_WITH_AS(j_nonobject.value("foo", 1), "[json.exception.type_error.306] cannot use value() with null", json::type_error&); CHECK_THROWS_WITH_AS(j_nonobject.value("foo", 1), "[json.exception.type_error.306] cannot use value() with null", json::type_error&);
CHECK_THROWS_WITH_AS(j_nonobject_const.value("foo", 1), "[json.exception.type_error.306] cannot use value() with null", json::type_error&); CHECK_THROWS_WITH_AS(j_nonobject_const.value("foo", 1), "[json.exception.type_error.306] cannot use value() with null", json::type_error&);
#ifdef JSON_HAS_CPP_17
CHECK_THROWS_WITH_AS(j_nonobject.value(std::string_view("foo"), 1), "[json.exception.type_error.306] cannot use value() with null", json::type_error&);
CHECK_THROWS_WITH_AS(j_nonobject_const.value(std::string_view("foo"), 1), "[json.exception.type_error.306] cannot use value() with null", json::type_error&);
#endif
} }
SECTION("boolean") SECTION("boolean")
@ -195,6 +306,11 @@ TEST_CASE("element access 2")
const json j_nonobject_const(json::value_t::boolean); const json j_nonobject_const(json::value_t::boolean);
CHECK_THROWS_WITH_AS(j_nonobject.value("foo", 1), "[json.exception.type_error.306] cannot use value() with boolean", json::type_error&); CHECK_THROWS_WITH_AS(j_nonobject.value("foo", 1), "[json.exception.type_error.306] cannot use value() with boolean", json::type_error&);
CHECK_THROWS_WITH_AS(j_nonobject_const.value("foo", 1), "[json.exception.type_error.306] cannot use value() with boolean", json::type_error&); CHECK_THROWS_WITH_AS(j_nonobject_const.value("foo", 1), "[json.exception.type_error.306] cannot use value() with boolean", json::type_error&);
#ifdef JSON_HAS_CPP_17
CHECK_THROWS_WITH_AS(j_nonobject.value(std::string_view("foo"), 1), "[json.exception.type_error.306] cannot use value() with boolean", json::type_error&);
CHECK_THROWS_WITH_AS(j_nonobject_const.value(std::string_view("foo"), 1), "[json.exception.type_error.306] cannot use value() with boolean", json::type_error&);
#endif
} }
SECTION("string") SECTION("string")
@ -203,6 +319,11 @@ TEST_CASE("element access 2")
const json j_nonobject_const(json::value_t::string); const json j_nonobject_const(json::value_t::string);
CHECK_THROWS_WITH_AS(j_nonobject.value("foo", 1), "[json.exception.type_error.306] cannot use value() with string", json::type_error&); CHECK_THROWS_WITH_AS(j_nonobject.value("foo", 1), "[json.exception.type_error.306] cannot use value() with string", json::type_error&);
CHECK_THROWS_WITH_AS(j_nonobject_const.value("foo", 1), "[json.exception.type_error.306] cannot use value() with string", json::type_error&); CHECK_THROWS_WITH_AS(j_nonobject_const.value("foo", 1), "[json.exception.type_error.306] cannot use value() with string", json::type_error&);
#ifdef JSON_HAS_CPP_17
CHECK_THROWS_WITH_AS(j_nonobject.value(std::string_view("foo"), 1), "[json.exception.type_error.306] cannot use value() with string", json::type_error&);
CHECK_THROWS_WITH_AS(j_nonobject_const.value(std::string_view("foo"), 1), "[json.exception.type_error.306] cannot use value() with string", json::type_error&);
#endif
} }
SECTION("array") SECTION("array")
@ -211,6 +332,11 @@ TEST_CASE("element access 2")
const json j_nonobject_const(json::value_t::array); const json j_nonobject_const(json::value_t::array);
CHECK_THROWS_WITH_AS(j_nonobject.value("foo", 1), "[json.exception.type_error.306] cannot use value() with array", json::type_error&); CHECK_THROWS_WITH_AS(j_nonobject.value("foo", 1), "[json.exception.type_error.306] cannot use value() with array", json::type_error&);
CHECK_THROWS_WITH_AS(j_nonobject_const.value("foo", 1), "[json.exception.type_error.306] cannot use value() with array", json::type_error&); CHECK_THROWS_WITH_AS(j_nonobject_const.value("foo", 1), "[json.exception.type_error.306] cannot use value() with array", json::type_error&);
#ifdef JSON_HAS_CPP_17
CHECK_THROWS_WITH_AS(j_nonobject.value(std::string_view("foo"), 1), "[json.exception.type_error.306] cannot use value() with array", json::type_error&);
CHECK_THROWS_WITH_AS(j_nonobject_const.value(std::string_view("foo"), 1), "[json.exception.type_error.306] cannot use value() with array", json::type_error&);
#endif
} }
SECTION("number (integer)") SECTION("number (integer)")
@ -219,6 +345,11 @@ TEST_CASE("element access 2")
const json j_nonobject_const(json::value_t::number_integer); const json j_nonobject_const(json::value_t::number_integer);
CHECK_THROWS_WITH_AS(j_nonobject.value("foo", 1), "[json.exception.type_error.306] cannot use value() with number", json::type_error&); CHECK_THROWS_WITH_AS(j_nonobject.value("foo", 1), "[json.exception.type_error.306] cannot use value() with number", json::type_error&);
CHECK_THROWS_WITH_AS(j_nonobject_const.value("foo", 1), "[json.exception.type_error.306] cannot use value() with number", json::type_error&); CHECK_THROWS_WITH_AS(j_nonobject_const.value("foo", 1), "[json.exception.type_error.306] cannot use value() with number", json::type_error&);
#ifdef JSON_HAS_CPP_17
CHECK_THROWS_WITH_AS(j_nonobject.value(std::string_view("foo"), 1), "[json.exception.type_error.306] cannot use value() with number", json::type_error&);
CHECK_THROWS_WITH_AS(j_nonobject_const.value(std::string_view("foo"), 1), "[json.exception.type_error.306] cannot use value() with number", json::type_error&);
#endif
} }
SECTION("number (unsigned)") SECTION("number (unsigned)")
@ -227,6 +358,11 @@ TEST_CASE("element access 2")
const json j_nonobject_const(json::value_t::number_unsigned); const json j_nonobject_const(json::value_t::number_unsigned);
CHECK_THROWS_WITH_AS(j_nonobject.value("foo", 1), "[json.exception.type_error.306] cannot use value() with number", json::type_error&); CHECK_THROWS_WITH_AS(j_nonobject.value("foo", 1), "[json.exception.type_error.306] cannot use value() with number", json::type_error&);
CHECK_THROWS_WITH_AS(j_nonobject_const.value("foo", 1), "[json.exception.type_error.306] cannot use value() with number", json::type_error&); CHECK_THROWS_WITH_AS(j_nonobject_const.value("foo", 1), "[json.exception.type_error.306] cannot use value() with number", json::type_error&);
#ifdef JSON_HAS_CPP_17
CHECK_THROWS_WITH_AS(j_nonobject.value(std::string_view("foo"), 1), "[json.exception.type_error.306] cannot use value() with number", json::type_error&);
CHECK_THROWS_WITH_AS(j_nonobject_const.value(std::string_view("foo"), 1), "[json.exception.type_error.306] cannot use value() with number", json::type_error&);
#endif
} }
SECTION("number (floating-point)") SECTION("number (floating-point)")
@ -235,6 +371,11 @@ TEST_CASE("element access 2")
const json j_nonobject_const(json::value_t::number_float); const json j_nonobject_const(json::value_t::number_float);
CHECK_THROWS_WITH_AS(j_nonobject.value("foo", 1), "[json.exception.type_error.306] cannot use value() with number", json::type_error&); CHECK_THROWS_WITH_AS(j_nonobject.value("foo", 1), "[json.exception.type_error.306] cannot use value() with number", json::type_error&);
CHECK_THROWS_WITH_AS(j_nonobject_const.value("foo", 1), "[json.exception.type_error.306] cannot use value() with number", json::type_error&); CHECK_THROWS_WITH_AS(j_nonobject_const.value("foo", 1), "[json.exception.type_error.306] cannot use value() with number", json::type_error&);
#ifdef JSON_HAS_CPP_17
CHECK_THROWS_WITH_AS(j_nonobject.value(std::string_view("foo"), 1), "[json.exception.type_error.306] cannot use value() with number", json::type_error&);
CHECK_THROWS_WITH_AS(j_nonobject_const.value(std::string_view("foo"), 1), "[json.exception.type_error.306] cannot use value() with number", json::type_error&);
#endif
} }
} }
} }
@ -330,6 +471,31 @@ TEST_CASE("element access 2")
} }
} }
SECTION("non-const operator[]")
{
{
json j_null;
CHECK(j_null.is_null());
j_null["key"] = 1;
CHECK(j_null.is_object());
CHECK(j_null.size() == 1);
j_null["key"] = 2;
CHECK(j_null.size() == 1);
}
#ifdef JSON_HAS_CPP_17
{
std::string_view key = "key";
json j_null;
CHECK(j_null.is_null());
j_null[key] = 1;
CHECK(j_null.is_object());
CHECK(j_null.size() == 1);
j_null[key] = 2;
CHECK(j_null.size() == 1);
}
#endif
}
SECTION("front and back") SECTION("front and back")
{ {
// "array" is the smallest key // "array" is the smallest key
@ -390,6 +556,56 @@ TEST_CASE("element access 2")
CHECK(j_const[json::object_t::key_type("array")] == j["array"]); CHECK(j_const[json::object_t::key_type("array")] == j["array"]);
} }
#ifdef JSON_HAS_CPP_17
SECTION("access within bounds (string_view)")
{
CHECK(j["integer"] == json(1));
CHECK(j[std::string_view("integer")] == j["integer"]);
CHECK(j["unsigned"] == json(1u));
CHECK(j[std::string_view("unsigned")] == j["unsigned"]);
CHECK(j["boolean"] == json(true));
CHECK(j[std::string_view("boolean")] == j["boolean"]);
CHECK(j["null"] == json(nullptr));
CHECK(j[std::string_view("null")] == j["null"]);
CHECK(j["string"] == json("hello world"));
CHECK(j[std::string_view("string")] == j["string"]);
CHECK(j["floating"] == json(42.23));
CHECK(j[std::string_view("floating")] == j["floating"]);
CHECK(j["object"] == json::object());
CHECK(j[std::string_view("object")] == j["object"]);
CHECK(j["array"] == json({1, 2, 3}));
CHECK(j[std::string_view("array")] == j["array"]);
CHECK(j_const["integer"] == json(1));
CHECK(j_const[std::string_view("integer")] == j["integer"]);
CHECK(j_const["boolean"] == json(true));
CHECK(j_const[std::string_view("boolean")] == j["boolean"]);
CHECK(j_const["null"] == json(nullptr));
CHECK(j_const[std::string_view("null")] == j["null"]);
CHECK(j_const["string"] == json("hello world"));
CHECK(j_const[std::string_view("string")] == j["string"]);
CHECK(j_const["floating"] == json(42.23));
CHECK(j_const[std::string_view("floating")] == j["floating"]);
CHECK(j_const["object"] == json::object());
CHECK(j_const[std::string_view("object")] == j["object"]);
CHECK(j_const["array"] == json({1, 2, 3}));
CHECK(j_const[std::string_view("array")] == j["array"]);
}
#endif
SECTION("access on non-object type") SECTION("access on non-object type")
{ {
SECTION("null") SECTION("null")
@ -397,10 +613,16 @@ TEST_CASE("element access 2")
json j_nonobject(json::value_t::null); json j_nonobject(json::value_t::null);
json j_nonobject2(json::value_t::null); json j_nonobject2(json::value_t::null);
const json j_const_nonobject(j_nonobject); const json j_const_nonobject(j_nonobject);
CHECK_NOTHROW(j_nonobject["foo"]); CHECK_NOTHROW(j_nonobject["foo"]);
CHECK_NOTHROW(j_nonobject2[json::object_t::key_type("foo")]); CHECK_NOTHROW(j_nonobject2[json::object_t::key_type("foo")]);
CHECK_THROWS_WITH_AS(j_const_nonobject["foo"], "[json.exception.type_error.305] cannot use operator[] with a string argument with null", json::type_error&); CHECK_THROWS_WITH_AS(j_const_nonobject["foo"], "[json.exception.type_error.305] cannot use operator[] with a string argument with null", json::type_error&);
CHECK_THROWS_WITH_AS(j_const_nonobject[json::object_t::key_type("foo")], "[json.exception.type_error.305] cannot use operator[] with a string argument with null", json::type_error&); CHECK_THROWS_WITH_AS(j_const_nonobject[json::object_t::key_type("foo")], "[json.exception.type_error.305] cannot use operator[] with a string argument with null", json::type_error&);
#ifdef JSON_HAS_CPP_17
CHECK_NOTHROW(j_nonobject2[std::string_view("foo")]);
CHECK_THROWS_WITH_AS(j_const_nonobject[std::string_view("foo")], "[json.exception.type_error.305] cannot use operator[] with a string argument with null", json::type_error&);
#endif
} }
SECTION("boolean") SECTION("boolean")
@ -415,6 +637,11 @@ TEST_CASE("element access 2")
"[json.exception.type_error.305] cannot use operator[] with a string argument with boolean", json::type_error&); "[json.exception.type_error.305] cannot use operator[] with a string argument with boolean", json::type_error&);
CHECK_THROWS_WITH_AS(j_const_nonobject[json::object_t::key_type("foo")], CHECK_THROWS_WITH_AS(j_const_nonobject[json::object_t::key_type("foo")],
"[json.exception.type_error.305] cannot use operator[] with a string argument with boolean", json::type_error&); "[json.exception.type_error.305] cannot use operator[] with a string argument with boolean", json::type_error&);
#ifdef JSON_HAS_CPP_17
CHECK_THROWS_WITH_AS(j_nonobject[std::string_view("foo")], "[json.exception.type_error.305] cannot use operator[] with a string argument with boolean", json::type_error&);
CHECK_THROWS_WITH_AS(j_const_nonobject[std::string_view("foo")], "[json.exception.type_error.305] cannot use operator[] with a string argument with boolean", json::type_error&);
#endif
} }
SECTION("string") SECTION("string")
@ -429,6 +656,11 @@ TEST_CASE("element access 2")
"[json.exception.type_error.305] cannot use operator[] with a string argument with string", json::type_error&); "[json.exception.type_error.305] cannot use operator[] with a string argument with string", json::type_error&);
CHECK_THROWS_WITH_AS(j_const_nonobject[json::object_t::key_type("foo")], CHECK_THROWS_WITH_AS(j_const_nonobject[json::object_t::key_type("foo")],
"[json.exception.type_error.305] cannot use operator[] with a string argument with string", json::type_error&); "[json.exception.type_error.305] cannot use operator[] with a string argument with string", json::type_error&);
#ifdef JSON_HAS_CPP_17
CHECK_THROWS_WITH_AS(j_nonobject[std::string_view("foo")], "[json.exception.type_error.305] cannot use operator[] with a string argument with string", json::type_error&);
CHECK_THROWS_WITH_AS(j_const_nonobject[std::string_view("foo")], "[json.exception.type_error.305] cannot use operator[] with a string argument with string", json::type_error&);
#endif
} }
SECTION("array") SECTION("array")
@ -442,6 +674,11 @@ TEST_CASE("element access 2")
"[json.exception.type_error.305] cannot use operator[] with a string argument with array", json::type_error&); "[json.exception.type_error.305] cannot use operator[] with a string argument with array", json::type_error&);
CHECK_THROWS_WITH_AS(j_const_nonobject[json::object_t::key_type("foo")], CHECK_THROWS_WITH_AS(j_const_nonobject[json::object_t::key_type("foo")],
"[json.exception.type_error.305] cannot use operator[] with a string argument with array", json::type_error&); "[json.exception.type_error.305] cannot use operator[] with a string argument with array", json::type_error&);
#ifdef JSON_HAS_CPP_17
CHECK_THROWS_WITH_AS(j_nonobject[std::string_view("foo")], "[json.exception.type_error.305] cannot use operator[] with a string argument with array", json::type_error&);
CHECK_THROWS_WITH_AS(j_const_nonobject[std::string_view("foo")], "[json.exception.type_error.305] cannot use operator[] with a string argument with array", json::type_error&);
#endif
} }
SECTION("number (integer)") SECTION("number (integer)")
@ -456,6 +693,11 @@ TEST_CASE("element access 2")
"[json.exception.type_error.305] cannot use operator[] with a string argument with number", json::type_error&); "[json.exception.type_error.305] cannot use operator[] with a string argument with number", json::type_error&);
CHECK_THROWS_WITH_AS(j_const_nonobject[json::object_t::key_type("foo")], CHECK_THROWS_WITH_AS(j_const_nonobject[json::object_t::key_type("foo")],
"[json.exception.type_error.305] cannot use operator[] with a string argument with number", json::type_error&); "[json.exception.type_error.305] cannot use operator[] with a string argument with number", json::type_error&);
#ifdef JSON_HAS_CPP_17
CHECK_THROWS_WITH_AS(j_nonobject[std::string_view("foo")], "[json.exception.type_error.305] cannot use operator[] with a string argument with number", json::type_error&);
CHECK_THROWS_WITH_AS(j_const_nonobject[std::string_view("foo")], "[json.exception.type_error.305] cannot use operator[] with a string argument with number", json::type_error&);
#endif
} }
SECTION("number (unsigned)") SECTION("number (unsigned)")
@ -470,6 +712,11 @@ TEST_CASE("element access 2")
"[json.exception.type_error.305] cannot use operator[] with a string argument with number", json::type_error&); "[json.exception.type_error.305] cannot use operator[] with a string argument with number", json::type_error&);
CHECK_THROWS_WITH_AS(j_const_nonobject[json::object_t::key_type("foo")], CHECK_THROWS_WITH_AS(j_const_nonobject[json::object_t::key_type("foo")],
"[json.exception.type_error.305] cannot use operator[] with a string argument with number", json::type_error&); "[json.exception.type_error.305] cannot use operator[] with a string argument with number", json::type_error&);
#ifdef JSON_HAS_CPP_17
CHECK_THROWS_WITH_AS(j_nonobject[std::string_view("foo")], "[json.exception.type_error.305] cannot use operator[] with a string argument with number", json::type_error&);
CHECK_THROWS_WITH_AS(j_const_nonobject[std::string_view("foo")], "[json.exception.type_error.305] cannot use operator[] with a string argument with number", json::type_error&);
#endif
} }
SECTION("number (floating-point)") SECTION("number (floating-point)")
@ -484,6 +731,11 @@ TEST_CASE("element access 2")
"[json.exception.type_error.305] cannot use operator[] with a string argument with number", json::type_error&); "[json.exception.type_error.305] cannot use operator[] with a string argument with number", json::type_error&);
CHECK_THROWS_WITH_AS(j_const_nonobject[json::object_t::key_type("foo")], CHECK_THROWS_WITH_AS(j_const_nonobject[json::object_t::key_type("foo")],
"[json.exception.type_error.305] cannot use operator[] with a string argument with number", json::type_error&); "[json.exception.type_error.305] cannot use operator[] with a string argument with number", json::type_error&);
#ifdef JSON_HAS_CPP_17
CHECK_THROWS_WITH_AS(j_nonobject[std::string_view("foo")], "[json.exception.type_error.305] cannot use operator[] with a string argument with number", json::type_error&);
CHECK_THROWS_WITH_AS(j_const_nonobject[std::string_view("foo")], "[json.exception.type_error.305] cannot use operator[] with a string argument with number", json::type_error&);
#endif
} }
} }
} }
@ -533,6 +785,51 @@ TEST_CASE("element access 2")
CHECK(j.erase("array") == 0); CHECK(j.erase("array") == 0);
} }
#ifdef JSON_HAS_CPP_17
SECTION("remove element by key (string_view)")
{
CHECK(j.find(std::string_view("integer")) != j.end());
CHECK(j.erase(std::string_view("integer")) == 1);
CHECK(j.find(std::string_view("integer")) == j.end());
CHECK(j.erase(std::string_view("integer")) == 0);
CHECK(j.find(std::string_view("unsigned")) != j.end());
CHECK(j.erase(std::string_view("unsigned")) == 1);
CHECK(j.find(std::string_view("unsigned")) == j.end());
CHECK(j.erase(std::string_view("unsigned")) == 0);
CHECK(j.find(std::string_view("boolean")) != j.end());
CHECK(j.erase(std::string_view("boolean")) == 1);
CHECK(j.find(std::string_view("boolean")) == j.end());
CHECK(j.erase(std::string_view("boolean")) == 0);
CHECK(j.find(std::string_view("null")) != j.end());
CHECK(j.erase(std::string_view("null")) == 1);
CHECK(j.find(std::string_view("null")) == j.end());
CHECK(j.erase(std::string_view("null")) == 0);
CHECK(j.find(std::string_view("string")) != j.end());
CHECK(j.erase(std::string_view("string")) == 1);
CHECK(j.find(std::string_view("string")) == j.end());
CHECK(j.erase(std::string_view("string")) == 0);
CHECK(j.find(std::string_view("floating")) != j.end());
CHECK(j.erase(std::string_view("floating")) == 1);
CHECK(j.find(std::string_view("floating")) == j.end());
CHECK(j.erase(std::string_view("floating")) == 0);
CHECK(j.find(std::string_view("object")) != j.end());
CHECK(j.erase(std::string_view("object")) == 1);
CHECK(j.find(std::string_view("object")) == j.end());
CHECK(j.erase(std::string_view("object")) == 0);
CHECK(j.find(std::string_view("array")) != j.end());
CHECK(j.erase(std::string_view("array")) == 1);
CHECK(j.find(std::string_view("array")) == j.end());
CHECK(j.erase(std::string_view("array")) == 0);
}
#endif
SECTION("remove element by iterator") SECTION("remove element by iterator")
{ {
SECTION("erase(begin())") SECTION("erase(begin())")
@ -652,36 +949,60 @@ TEST_CASE("element access 2")
{ {
json j_nonobject(json::value_t::null); json j_nonobject(json::value_t::null);
CHECK_THROWS_WITH_AS(j_nonobject.erase("foo"), "[json.exception.type_error.307] cannot use erase() with null", json::type_error&); CHECK_THROWS_WITH_AS(j_nonobject.erase("foo"), "[json.exception.type_error.307] cannot use erase() with null", json::type_error&);
#ifdef JSON_HAS_CPP_17
CHECK_THROWS_WITH_AS(j_nonobject.erase(std::string_view("foo")), "[json.exception.type_error.307] cannot use erase() with null", json::type_error&);
#endif
} }
SECTION("boolean") SECTION("boolean")
{ {
json j_nonobject(json::value_t::boolean); json j_nonobject(json::value_t::boolean);
CHECK_THROWS_WITH_AS(j_nonobject.erase("foo"), "[json.exception.type_error.307] cannot use erase() with boolean", json::type_error&); CHECK_THROWS_WITH_AS(j_nonobject.erase("foo"), "[json.exception.type_error.307] cannot use erase() with boolean", json::type_error&);
#ifdef JSON_HAS_CPP_17
CHECK_THROWS_WITH_AS(j_nonobject.erase(std::string_view("foo")), "[json.exception.type_error.307] cannot use erase() with boolean", json::type_error&);
#endif
} }
SECTION("string") SECTION("string")
{ {
json j_nonobject(json::value_t::string); json j_nonobject(json::value_t::string);
CHECK_THROWS_WITH_AS(j_nonobject.erase("foo"), "[json.exception.type_error.307] cannot use erase() with string", json::type_error&); CHECK_THROWS_WITH_AS(j_nonobject.erase("foo"), "[json.exception.type_error.307] cannot use erase() with string", json::type_error&);
#ifdef JSON_HAS_CPP_17
CHECK_THROWS_WITH_AS(j_nonobject.erase(std::string_view("foo")), "[json.exception.type_error.307] cannot use erase() with string", json::type_error&);
#endif
} }
SECTION("array") SECTION("array")
{ {
json j_nonobject(json::value_t::array); json j_nonobject(json::value_t::array);
CHECK_THROWS_WITH_AS(j_nonobject.erase("foo"), "[json.exception.type_error.307] cannot use erase() with array", json::type_error&); CHECK_THROWS_WITH_AS(j_nonobject.erase("foo"), "[json.exception.type_error.307] cannot use erase() with array", json::type_error&);
#ifdef JSON_HAS_CPP_17
CHECK_THROWS_WITH_AS(j_nonobject.erase(std::string_view("foo")), "[json.exception.type_error.307] cannot use erase() with array", json::type_error&);
#endif
} }
SECTION("number (integer)") SECTION("number (integer)")
{ {
json j_nonobject(json::value_t::number_integer); json j_nonobject(json::value_t::number_integer);
CHECK_THROWS_WITH_AS(j_nonobject.erase("foo"), "[json.exception.type_error.307] cannot use erase() with number", json::type_error&); CHECK_THROWS_WITH_AS(j_nonobject.erase("foo"), "[json.exception.type_error.307] cannot use erase() with number", json::type_error&);
#ifdef JSON_HAS_CPP_17
CHECK_THROWS_WITH_AS(j_nonobject.erase(std::string_view("foo")), "[json.exception.type_error.307] cannot use erase() with number", json::type_error&);
#endif
} }
SECTION("number (floating-point)") SECTION("number (floating-point)")
{ {
json j_nonobject(json::value_t::number_float); json j_nonobject(json::value_t::number_float);
CHECK_THROWS_WITH_AS(j_nonobject.erase("foo"), "[json.exception.type_error.307] cannot use erase() with number", json::type_error&); CHECK_THROWS_WITH_AS(j_nonobject.erase("foo"), "[json.exception.type_error.307] cannot use erase() with number", json::type_error&);
#ifdef JSON_HAS_CPP_17
CHECK_THROWS_WITH_AS(j_nonobject.erase(std::string_view("foo")), "[json.exception.type_error.307] cannot use erase() with number", json::type_error&);
#endif
} }
} }
} }
@ -699,12 +1020,28 @@ TEST_CASE("element access 2")
CHECK(j_const.find(key) != j_const.end()); CHECK(j_const.find(key) != j_const.end());
CHECK(*j_const.find(key) == j_const.at(key)); CHECK(*j_const.find(key) == j_const.at(key));
} }
#ifdef JSON_HAS_CPP_17
for (const std::string_view key :
{"integer", "unsigned", "floating", "null", "string", "boolean", "object", "array"
})
{
CHECK(j.find(key) != j.end());
CHECK(*j.find(key) == j.at(key));
CHECK(j_const.find(key) != j_const.end());
CHECK(*j_const.find(key) == j_const.at(key));
}
#endif
} }
SECTION("nonexisting element") SECTION("nonexisting element")
{ {
CHECK(j.find("foo") == j.end()); CHECK(j.find("foo") == j.end());
CHECK(j_const.find("foo") == j_const.end()); CHECK(j_const.find("foo") == j_const.end());
#ifdef JSON_HAS_CPP_17
CHECK(j.find(std::string_view("foo")) == j.end());
CHECK(j_const.find(std::string_view("foo")) == j_const.end());
#endif
} }
SECTION("all types") SECTION("all types")
@ -713,64 +1050,112 @@ TEST_CASE("element access 2")
{ {
json j_nonarray(json::value_t::null); json j_nonarray(json::value_t::null);
const json j_nonarray_const(j_nonarray); const json j_nonarray_const(j_nonarray);
CHECK(j_nonarray.find("foo") == j_nonarray.end()); CHECK(j_nonarray.find("foo") == j_nonarray.end());
CHECK(j_nonarray_const.find("foo") == j_nonarray_const.end()); CHECK(j_nonarray_const.find("foo") == j_nonarray_const.end());
#ifdef JSON_HAS_CPP_17
CHECK(j_nonarray.find(std::string_view("foo")) == j_nonarray.end());
CHECK(j_nonarray_const.find(std::string_view("foo")) == j_nonarray_const.end());
#endif
} }
SECTION("string") SECTION("string")
{ {
json j_nonarray(json::value_t::string); json j_nonarray(json::value_t::string);
const json j_nonarray_const(j_nonarray); const json j_nonarray_const(j_nonarray);
CHECK(j_nonarray.find("foo") == j_nonarray.end()); CHECK(j_nonarray.find("foo") == j_nonarray.end());
CHECK(j_nonarray_const.find("foo") == j_nonarray_const.end()); CHECK(j_nonarray_const.find("foo") == j_nonarray_const.end());
#ifdef JSON_HAS_CPP_17
CHECK(j_nonarray.find(std::string_view("foo")) == j_nonarray.end());
CHECK(j_nonarray_const.find(std::string_view("foo")) == j_nonarray_const.end());
#endif
} }
SECTION("object") SECTION("object")
{ {
json j_nonarray(json::value_t::object); json j_nonarray(json::value_t::object);
const json j_nonarray_const(j_nonarray); const json j_nonarray_const(j_nonarray);
CHECK(j_nonarray.find("foo") == j_nonarray.end()); CHECK(j_nonarray.find("foo") == j_nonarray.end());
CHECK(j_nonarray_const.find("foo") == j_nonarray_const.end()); CHECK(j_nonarray_const.find("foo") == j_nonarray_const.end());
#ifdef JSON_HAS_CPP_17
CHECK(j_nonarray.find(std::string_view("foo")) == j_nonarray.end());
CHECK(j_nonarray_const.find(std::string_view("foo")) == j_nonarray_const.end());
#endif
} }
SECTION("array") SECTION("array")
{ {
json j_nonarray(json::value_t::array); json j_nonarray(json::value_t::array);
const json j_nonarray_const(j_nonarray); const json j_nonarray_const(j_nonarray);
CHECK(j_nonarray.find("foo") == j_nonarray.end()); CHECK(j_nonarray.find("foo") == j_nonarray.end());
CHECK(j_nonarray_const.find("foo") == j_nonarray_const.end()); CHECK(j_nonarray_const.find("foo") == j_nonarray_const.end());
#ifdef JSON_HAS_CPP_17
CHECK(j_nonarray.find(std::string_view("foo")) == j_nonarray.end());
CHECK(j_nonarray_const.find(std::string_view("foo")) == j_nonarray_const.end());
#endif
} }
SECTION("boolean") SECTION("boolean")
{ {
json j_nonarray(json::value_t::boolean); json j_nonarray(json::value_t::boolean);
const json j_nonarray_const(j_nonarray); const json j_nonarray_const(j_nonarray);
CHECK(j_nonarray.find("foo") == j_nonarray.end()); CHECK(j_nonarray.find("foo") == j_nonarray.end());
CHECK(j_nonarray_const.find("foo") == j_nonarray_const.end()); CHECK(j_nonarray_const.find("foo") == j_nonarray_const.end());
#ifdef JSON_HAS_CPP_17
CHECK(j_nonarray.find(std::string_view("foo")) == j_nonarray.end());
CHECK(j_nonarray_const.find(std::string_view("foo")) == j_nonarray_const.end());
#endif
} }
SECTION("number (integer)") SECTION("number (integer)")
{ {
json j_nonarray(json::value_t::number_integer); json j_nonarray(json::value_t::number_integer);
const json j_nonarray_const(j_nonarray); const json j_nonarray_const(j_nonarray);
CHECK(j_nonarray.find("foo") == j_nonarray.end()); CHECK(j_nonarray.find("foo") == j_nonarray.end());
CHECK(j_nonarray_const.find("foo") == j_nonarray_const.end()); CHECK(j_nonarray_const.find("foo") == j_nonarray_const.end());
#ifdef JSON_HAS_CPP_17
CHECK(j_nonarray.find(std::string_view("foo")) == j_nonarray.end());
CHECK(j_nonarray_const.find(std::string_view("foo")) == j_nonarray_const.end());
#endif
} }
SECTION("number (unsigned)") SECTION("number (unsigned)")
{ {
json j_nonarray(json::value_t::number_unsigned); json j_nonarray(json::value_t::number_unsigned);
const json j_nonarray_const(j_nonarray); const json j_nonarray_const(j_nonarray);
CHECK(j_nonarray.find("foo") == j_nonarray.end()); CHECK(j_nonarray.find("foo") == j_nonarray.end());
CHECK(j_nonarray_const.find("foo") == j_nonarray_const.end()); CHECK(j_nonarray_const.find("foo") == j_nonarray_const.end());
#ifdef JSON_HAS_CPP_17
CHECK(j_nonarray.find(std::string_view("foo")) == j_nonarray.end());
CHECK(j_nonarray_const.find(std::string_view("foo")) == j_nonarray_const.end());
#endif
} }
SECTION("number (floating-point)") SECTION("number (floating-point)")
{ {
json j_nonarray(json::value_t::number_float); json j_nonarray(json::value_t::number_float);
const json j_nonarray_const(j_nonarray); const json j_nonarray_const(j_nonarray);
CHECK(j_nonarray.find("foo") == j_nonarray.end()); CHECK(j_nonarray.find("foo") == j_nonarray.end());
CHECK(j_nonarray_const.find("foo") == j_nonarray_const.end()); CHECK(j_nonarray_const.find("foo") == j_nonarray_const.end());
#ifdef JSON_HAS_CPP_17
CHECK(j_nonarray.find(std::string_view("foo")) == j_nonarray.end());
CHECK(j_nonarray_const.find(std::string_view("foo")) == j_nonarray_const.end());
#endif
} }
} }
} }
@ -786,12 +1171,26 @@ TEST_CASE("element access 2")
CHECK(j.count(key) == 1); CHECK(j.count(key) == 1);
CHECK(j_const.count(key) == 1); CHECK(j_const.count(key) == 1);
} }
#ifdef JSON_HAS_CPP_17
for (const std::string_view key :
{"integer", "unsigned", "floating", "null", "string", "boolean", "object", "array"
})
{
CHECK(j.count(key) == 1);
CHECK(j_const.count(key) == 1);
}
#endif
} }
SECTION("nonexisting element") SECTION("nonexisting element")
{ {
CHECK(j.count("foo") == 0); CHECK(j.count("foo") == 0);
CHECK(j_const.count("foo") == 0); CHECK(j_const.count("foo") == 0);
#ifdef JSON_HAS_CPP_17
CHECK(j.count(std::string_view("foo")) == 0);
CHECK(j_const.count(std::string_view("foo")) == 0);
#endif
} }
SECTION("all types") SECTION("all types")
@ -800,64 +1199,112 @@ TEST_CASE("element access 2")
{ {
json j_nonobject(json::value_t::null); json j_nonobject(json::value_t::null);
const json j_nonobject_const(json::value_t::null); const json j_nonobject_const(json::value_t::null);
CHECK(j_nonobject.count("foo") == 0); CHECK(j_nonobject.count("foo") == 0);
CHECK(j_nonobject_const.count("foo") == 0); CHECK(j_nonobject_const.count("foo") == 0);
#ifdef JSON_HAS_CPP_17
CHECK(j.count(std::string_view("foo")) == 0);
CHECK(j_const.count(std::string_view("foo")) == 0);
#endif
} }
SECTION("string") SECTION("string")
{ {
json j_nonobject(json::value_t::string); json j_nonobject(json::value_t::string);
const json j_nonobject_const(json::value_t::string); const json j_nonobject_const(json::value_t::string);
CHECK(j_nonobject.count("foo") == 0); CHECK(j_nonobject.count("foo") == 0);
CHECK(j_nonobject_const.count("foo") == 0); CHECK(j_nonobject_const.count("foo") == 0);
#ifdef JSON_HAS_CPP_17
CHECK(j.count(std::string_view("foo")) == 0);
CHECK(j_const.count(std::string_view("foo")) == 0);
#endif
} }
SECTION("object") SECTION("object")
{ {
json j_nonobject(json::value_t::object); json j_nonobject(json::value_t::object);
const json j_nonobject_const(json::value_t::object); const json j_nonobject_const(json::value_t::object);
CHECK(j_nonobject.count("foo") == 0); CHECK(j_nonobject.count("foo") == 0);
CHECK(j_nonobject_const.count("foo") == 0); CHECK(j_nonobject_const.count("foo") == 0);
#ifdef JSON_HAS_CPP_17
CHECK(j.count(std::string_view("foo")) == 0);
CHECK(j_const.count(std::string_view("foo")) == 0);
#endif
} }
SECTION("array") SECTION("array")
{ {
json j_nonobject(json::value_t::array); json j_nonobject(json::value_t::array);
const json j_nonobject_const(json::value_t::array); const json j_nonobject_const(json::value_t::array);
CHECK(j_nonobject.count("foo") == 0); CHECK(j_nonobject.count("foo") == 0);
CHECK(j_nonobject_const.count("foo") == 0); CHECK(j_nonobject_const.count("foo") == 0);
#ifdef JSON_HAS_CPP_17
CHECK(j.count(std::string_view("foo")) == 0);
CHECK(j_const.count(std::string_view("foo")) == 0);
#endif
} }
SECTION("boolean") SECTION("boolean")
{ {
json j_nonobject(json::value_t::boolean); json j_nonobject(json::value_t::boolean);
const json j_nonobject_const(json::value_t::boolean); const json j_nonobject_const(json::value_t::boolean);
CHECK(j_nonobject.count("foo") == 0); CHECK(j_nonobject.count("foo") == 0);
CHECK(j_nonobject_const.count("foo") == 0); CHECK(j_nonobject_const.count("foo") == 0);
#ifdef JSON_HAS_CPP_17
CHECK(j.count(std::string_view("foo")) == 0);
CHECK(j_const.count(std::string_view("foo")) == 0);
#endif
} }
SECTION("number (integer)") SECTION("number (integer)")
{ {
json j_nonobject(json::value_t::number_integer); json j_nonobject(json::value_t::number_integer);
const json j_nonobject_const(json::value_t::number_integer); const json j_nonobject_const(json::value_t::number_integer);
CHECK(j_nonobject.count("foo") == 0); CHECK(j_nonobject.count("foo") == 0);
CHECK(j_nonobject_const.count("foo") == 0); CHECK(j_nonobject_const.count("foo") == 0);
#ifdef JSON_HAS_CPP_17
CHECK(j.count(std::string_view("foo")) == 0);
CHECK(j_const.count(std::string_view("foo")) == 0);
#endif
} }
SECTION("number (unsigned)") SECTION("number (unsigned)")
{ {
json j_nonobject(json::value_t::number_unsigned); json j_nonobject(json::value_t::number_unsigned);
const json j_nonobject_const(json::value_t::number_unsigned); const json j_nonobject_const(json::value_t::number_unsigned);
CHECK(j_nonobject.count("foo") == 0); CHECK(j_nonobject.count("foo") == 0);
CHECK(j_nonobject_const.count("foo") == 0); CHECK(j_nonobject_const.count("foo") == 0);
#ifdef JSON_HAS_CPP_17
CHECK(j.count(std::string_view("foo")) == 0);
CHECK(j_const.count(std::string_view("foo")) == 0);
#endif
} }
SECTION("number (floating-point)") SECTION("number (floating-point)")
{ {
json j_nonobject(json::value_t::number_float); json j_nonobject(json::value_t::number_float);
const json j_nonobject_const(json::value_t::number_float); const json j_nonobject_const(json::value_t::number_float);
CHECK(j_nonobject.count("foo") == 0); CHECK(j_nonobject.count("foo") == 0);
CHECK(j_nonobject_const.count("foo") == 0); CHECK(j_nonobject_const.count("foo") == 0);
#ifdef JSON_HAS_CPP_17
CHECK(j.count(std::string_view("foo")) == 0);
CHECK(j_const.count(std::string_view("foo")) == 0);
#endif
} }
} }
} }
@ -873,12 +1320,27 @@ TEST_CASE("element access 2")
CHECK(j.contains(key) == true); CHECK(j.contains(key) == true);
CHECK(j_const.contains(key) == true); CHECK(j_const.contains(key) == true);
} }
#ifdef JSON_HAS_CPP_17
for (const std::string_view key :
{"integer", "unsigned", "floating", "null", "string", "boolean", "object", "array"
})
{
CHECK(j.contains(key) == true);
CHECK(j_const.contains(key) == true);
}
#endif
} }
SECTION("nonexisting element") SECTION("nonexisting element")
{ {
CHECK(j.contains("foo") == false); CHECK(j.contains("foo") == false);
CHECK(j_const.contains("foo") == false); CHECK(j_const.contains("foo") == false);
#ifdef JSON_HAS_CPP_17
CHECK(j.contains(std::string_view("foo")) == false);
CHECK(j_const.contains(std::string_view("foo")) == false);
#endif
} }
SECTION("all types") SECTION("all types")
@ -887,56 +1349,98 @@ TEST_CASE("element access 2")
{ {
json j_nonobject(json::value_t::null); json j_nonobject(json::value_t::null);
const json j_nonobject_const(json::value_t::null); const json j_nonobject_const(json::value_t::null);
CHECK(j_nonobject.contains("foo") == false); CHECK(j_nonobject.contains("foo") == false);
CHECK(j_nonobject_const.contains("foo") == false); CHECK(j_nonobject_const.contains("foo") == false);
#ifdef JSON_HAS_CPP_17
CHECK(j_nonobject.contains(std::string_view("foo")) == false);
CHECK(j_nonobject_const.contains(std::string_view("foo")) == false);
#endif
} }
SECTION("string") SECTION("string")
{ {
json j_nonobject(json::value_t::string); json j_nonobject(json::value_t::string);
const json j_nonobject_const(json::value_t::string); const json j_nonobject_const(json::value_t::string);
CHECK(j_nonobject.contains("foo") == false); CHECK(j_nonobject.contains("foo") == false);
CHECK(j_nonobject_const.contains("foo") == false); CHECK(j_nonobject_const.contains("foo") == false);
#ifdef JSON_HAS_CPP_17
CHECK(j_nonobject.contains(std::string_view("foo")) == false);
CHECK(j_nonobject_const.contains(std::string_view("foo")) == false);
#endif
} }
SECTION("object") SECTION("object")
{ {
json j_nonobject(json::value_t::object); json j_nonobject(json::value_t::object);
const json j_nonobject_const(json::value_t::object); const json j_nonobject_const(json::value_t::object);
CHECK(j_nonobject.contains("foo") == false); CHECK(j_nonobject.contains("foo") == false);
CHECK(j_nonobject_const.contains("foo") == false); CHECK(j_nonobject_const.contains("foo") == false);
#ifdef JSON_HAS_CPP_17
CHECK(j_nonobject.contains(std::string_view("foo")) == false);
CHECK(j_nonobject_const.contains(std::string_view("foo")) == false);
#endif
} }
SECTION("array") SECTION("array")
{ {
json j_nonobject(json::value_t::array); json j_nonobject(json::value_t::array);
const json j_nonobject_const(json::value_t::array); const json j_nonobject_const(json::value_t::array);
CHECK(j_nonobject.contains("foo") == false); CHECK(j_nonobject.contains("foo") == false);
CHECK(j_nonobject_const.contains("foo") == false); CHECK(j_nonobject_const.contains("foo") == false);
#ifdef JSON_HAS_CPP_17
CHECK(j_nonobject.contains(std::string_view("foo")) == false);
CHECK(j_nonobject_const.contains(std::string_view("foo")) == false);
#endif
} }
SECTION("boolean") SECTION("boolean")
{ {
json j_nonobject(json::value_t::boolean); json j_nonobject(json::value_t::boolean);
const json j_nonobject_const(json::value_t::boolean); const json j_nonobject_const(json::value_t::boolean);
CHECK(j_nonobject.contains("foo") == false); CHECK(j_nonobject.contains("foo") == false);
CHECK(j_nonobject_const.contains("foo") == false); CHECK(j_nonobject_const.contains("foo") == false);
#ifdef JSON_HAS_CPP_17
CHECK(j_nonobject.contains(std::string_view("foo")) == false);
CHECK(j_nonobject_const.contains(std::string_view("foo")) == false);
#endif
} }
SECTION("number (integer)") SECTION("number (integer)")
{ {
json j_nonobject(json::value_t::number_integer); json j_nonobject(json::value_t::number_integer);
const json j_nonobject_const(json::value_t::number_integer); const json j_nonobject_const(json::value_t::number_integer);
CHECK(j_nonobject.contains("foo") == false); CHECK(j_nonobject.contains("foo") == false);
CHECK(j_nonobject_const.contains("foo") == false); CHECK(j_nonobject_const.contains("foo") == false);
#ifdef JSON_HAS_CPP_17
CHECK(j_nonobject.contains(std::string_view("foo")) == false);
CHECK(j_nonobject_const.contains(std::string_view("foo")) == false);
#endif
} }
SECTION("number (unsigned)") SECTION("number (unsigned)")
{ {
json j_nonobject(json::value_t::number_unsigned); json j_nonobject(json::value_t::number_unsigned);
const json j_nonobject_const(json::value_t::number_unsigned); const json j_nonobject_const(json::value_t::number_unsigned);
CHECK(j_nonobject.contains("foo") == false); CHECK(j_nonobject.contains("foo") == false);
CHECK(j_nonobject_const.contains("foo") == false); CHECK(j_nonobject_const.contains("foo") == false);
#ifdef JSON_HAS_CPP_17
CHECK(j_nonobject.contains(std::string_view("foo")) == false);
CHECK(j_nonobject_const.contains(std::string_view("foo")) == false);
#endif
} }
SECTION("number (floating-point)") SECTION("number (floating-point)")
@ -945,6 +1449,10 @@ TEST_CASE("element access 2")
const json j_nonobject_const(json::value_t::number_float); const json j_nonobject_const(json::value_t::number_float);
CHECK(j_nonobject.contains("foo") == false); CHECK(j_nonobject.contains("foo") == false);
CHECK(j_nonobject_const.contains("foo") == false); CHECK(j_nonobject_const.contains("foo") == false);
#ifdef JSON_HAS_CPP_17
CHECK(j_nonobject.contains(std::string_view("foo")) == false);
CHECK(j_nonobject_const.contains(std::string_view("foo")) == false);
#endif
} }
} }
} }