Implement support for string_view (attempt no. 3) (#3423)

* Add key_compare member to ordered_map

* Replace == with key_compare in ordered_map

* Expose the actual comparison function used by object_t

nlohmann::ordered_map uses a different comparison function than the one
provided via template parameter.
* Introduce a type trait to detect if object_t has a key_compare member.
* Rename object_comparator_t to default_object_comparator_t.
* Add object_comparator_t to be conditionally defined as
  object_t::key_compare, if available, or default_object_comparator_t
  otherwise.
* Update the documentation accordingly.

Co-authored-by: Niels Lohmann <niels.lohmann@gmail.com>

* Add type traits to check if a type is usable as object key

Add type trait to check:
* if a type is a specialization of a template.
* if a type is a json_pointer.
* if a type is a basic_json::{const_,}iterator.
* if two types are comparable using a given comparison functor.
* if a type is comparable to basic_json::object_t::key_type.
* if a type has a member type is_transparent.
* if a type is usable as object key.
* if a type has an erase() function accepting a given KeyType.

Co-authored-by: Niels Lohmann <niels.lohmann@gmail.com>

* 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>

Co-authored-by: Niels Lohmann <niels.lohmann@gmail.com>
This commit is contained in:
Florian Albrechtskirchinger 2022-04-29 21:40:02 +02:00 committed by GitHub
parent ee51661481
commit 5352856f04
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
26 changed files with 1517 additions and 305 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;
// (3)
template<typename KeyType>
reference at(KeyType&& key);
template<typename KeyType>
const_reference at(KeyType&& key) const;
// (4)
reference at(const json_pointer& ptr);
const_reference at(const json_pointer& ptr) const;
```
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.
3. Returns a reference to the element at with specified JSON pointer `ptr`, with bounds checking.
2. Returns a reference to the object element with specified key `key`, 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
@ -25,15 +40,16 @@ const_reference at(const json_pointer& ptr) const;
`key` (in)
: object key of the elements to access
`ptr` (in)
: JSON pointer to the desired element
## Return value
1. reference to the element at index `idx`
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
@ -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.
- 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.
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
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
@ -68,9 +85,10 @@ Strong exception safety: if an exception occurs, the original value stays intact
## Complexity
1. Constant
1. Constant.
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
@ -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"
```
??? 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
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"
```
??? 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
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.
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
1. /
1. (none)
2. The function does not throw exceptions.
3. /
4. /
3. (none)
4. (none)
5. The function can throw the following exceptions:
- 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
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.
6. /
6. (none)
7. The function can throw the following exceptions:
- 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
@ -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.
- 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.
8. /
8. (none)
9. The function does not throw exceptions.
## Complexity

View File

@ -2,21 +2,28 @@
```cpp
// (1)
template<typename KeyT>
bool contains(KeyT && key) const;
bool contains(const typename object_t::key_type& key) const;
// (2)
template<typename KeyType>
bool contains(KeyType&& key) const;
// (3)
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.
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
`KeyT`
: A type for an object key other than `basic_json::json_pointer`.
`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
@ -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
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
@ -39,7 +47,8 @@ Strong exception safety: if an exception occurs, the original value stays intact
## 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
`0`.
- 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"
```
??? example "Example (1) check with JSON pointer"
??? example "Example (3) check with JSON pointer"
The example shows how `contains()` is used.
@ -90,5 +99,6 @@ Logarithmic in the size of the JSON object.
## Version history
1. Added in version 3.6.0.
2. Added in version 3.7.0.
1. Added in version 3.11.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
```cpp
template<typename KeyT>
size_type count(KeyT&& key) const;
// (1)
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
always be `0` (`key` was not found) or `1` (`key` was found).
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).
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
`KeyT`
: A type for an object key.
`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
@ -52,4 +60,5 @@ This method always returns `0` when executed on a JSON type that is not an objec
## 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

@ -0,0 +1,19 @@
# <small>nlohmann::basic_json::</small>default_object_comparator_t
```cpp
using default_object_comparator_t = std::less<StringType>; // until C++14
using default_object_comparator_t = std::less<>; // since C++14
```
The default comparator used by [`object_t`](object_t.md).
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
[`object_comparator_t`](object_comparator_t.md).
## Version history
- Added in version 3.11.0.

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);
// (4)
template<typename KeyType>
size_type erase(KeyType&& key);
// (5)
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.
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
@ -56,7 +70,8 @@ void erase(const size_type idx);
is returned.
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).
4. /
4. See 3.
5. (none)
## 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:
- Throws [`type_error.307`](../../home/exceptions.md#jsonexceptiontype_error307) when called on a type other than
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
JSON object; example: `"cannot use erase() with null"`
- 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
- other types: constant
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
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.
4. /
4. See 3.
5. (none)
## Examples
@ -156,7 +174,7 @@ Strong exception safety: if an exception occurs, the original value stays intact
--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.
@ -172,5 +190,8 @@ Strong exception safety: if an exception occurs, the original value stays intact
## Version history
- Added in version 1.0.0.
- Added support for binary types in version 3.8.0.
1. Added in version 1.0.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
```cpp
template<typename KeyT>
iterator find(KeyT&& key);
// (1)
iterator find(const typename object_t::key_type& key);
const_iterator find(const typename object_t::key_type& key) const;
template<typename KeyT>
const_iterator find(KeyT&& key) const;
// (2)
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
object, `end()` is returned.
1. Finds an element in a JSON object with a key equivalent to `key`. If the element is not found or the
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
`KeyT`
: A type for an object key.
`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
@ -23,8 +31,8 @@ object, `end()` is returned.
## 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,
past-the-end (see `end()`) iterator is returned.
Iterator to an element with a key equivalent to `key`. If no such element is found or the JSON value is not an object,
a past-the-end iterator (see `end()`) is returned.
## Exception safety
@ -60,4 +68,5 @@ This method always returns `end()` when executed on a JSON type that is not an o
## 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

@ -128,6 +128,7 @@ The class satisfies the following concept requirements:
- [**array_t**](array_t.md) - type for arrays
- [**binary_t**](binary_t.md) - type for binary arrays
- [**boolean_t**](boolean_t.md) - type for booleans
- [**default_object_comparator_t**](default_object_comparator_t.md) - default comparator for objects
- [**number_float_t**](number_float_t.md) - type for numbers (floating-point)
- [**number_integer_t**](number_integer_t.md) - type for numbers (integer)
- [**number_unsigned_t**](number_unsigned_t.md) - type for numbers (unsigned)

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`
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
5. /
5. (none)
## Exception safety

View File

@ -1,16 +1,16 @@
# <small>nlohmann::basic_json::</small>object_comparator_t
```cpp
using object_comparator_t = std::less<StringType>; // until C++14
using object_comparator_t = std::less<>; // since C++14
```cpp
using object_comparator_t = typename object_t::key_compare;
// or
using object_comparator_t = default_object_comparator_t;
```
The comparator used in [`object_t`](object_t.md).
When C++14 is detected, a transparent comparator is used which, when combined with perfect forwarding on find() and
count() calls, prevents unnecessary string construction.
The comparator used by [`object_t`](object_t.md). Defined as `#!cpp typename object_t::key_compare` if available,
and [`default_object_comparator_t`](default_object_comparator_t.md) otherwise.
## Version history
- Unknown.
- Added in version 3.0.0.
- Changed to be conditionally defined as `#!cpp typename object_t::key_compare` or `default_object_comparator_t` in version 3.11.0.

View File

@ -3,7 +3,7 @@
```cpp
using object_t = ObjectType<StringType,
basic_json,
object_comparator_t,
default_object_comparator_t,
AllocatorType<std::pair<const StringType, basic_json>>>;
```
@ -52,7 +52,7 @@ std::map<
>
```
See [`object_comparator_t`](object_comparator_t.md) for more information.
See [`default_object_comparator_t`](default_object_comparator_t.md) for more information.
#### Behavior

View File

@ -6,26 +6,32 @@ reference operator[](size_type idx);
const_reference operator[](size_type idx) const;
// (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;
template<typename T>
reference operator[](T* key);
template<typename T>
const_reference operator[](T* key) const;
// (3)
template<typename KeyType>
reference operator[](KeyType&& key);
template<typename KeyType>
const_reference operator[](KeyType&& key) const;
// (4)
reference operator[](const json_pointer& ptr);
const_reference operator[](const json_pointer& ptr) const;
```
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`.
3. Returns a reference to the element at with specified JSON pointer `ptr`.
2. Returns a reference to the object element with specified key `key`. The non-const qualified overload takes the key by value.
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
`T`
: string literal convertible to `object_t::key_type`
`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
@ -40,9 +46,10 @@ const_reference operator[](const json_pointer& ptr) const;
## Return value
1. reference to the element at index `idx`
2. reference to the element at key `key`
3. reference to the element pointed to by `ptr`
1. (const) reference to the element at index `idx`
2. (const) reference to the element at key `key`
3. (const) reference to the element at key `key`
4. (const) reference to the element pointed to by `ptr`
## 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:
- 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.
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
JSON pointer `ptr` begins with '0'.
- 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()`.
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
@ -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
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:
@ -143,7 +154,7 @@ Strong exception safety: if an exception occurs, the original value stays intact
--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.
@ -157,7 +168,7 @@ Strong exception safety: if an exception occurs, the original value stays intact
--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.
@ -171,7 +182,7 @@ Strong exception safety: if an exception occurs, the original value stays intact
--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.
@ -193,5 +204,6 @@ Strong exception safety: if an exception occurs, the original value stays intact
## Version history
1. Added in version 1.0.0.
2. Added in version 1.0.0. Overloads for `T* key` added in version 1.1.0.
3. Added in version 2.0.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 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
1. BSON serialization as byte vector
2. /
2. (none)
## Exception safety

View File

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

View File

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

View File

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

View File

@ -4,9 +4,14 @@
// (1)
template<class ValueType>
ValueType value(const typename object_t::key_type& key,
const ValueType& default_value) const;
ValueType&& default_value) const;
// (2)
template<class KeyType, class ValueType>
ValueType value(KeyType&& key,
ValueType&& default_value) const;
// (3)
template<class ValueType>
ValueType value(const json_pointer& ptr,
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.
The function is basically equivalent to executing
@ -44,6 +52,10 @@ ValueType value(const json_pointer& ptr,
## 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`
: 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
@ -55,7 +67,7 @@ ValueType value(const json_pointer& ptr,
: key of the element to access
`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)
: a JSON pointer to the element to access
@ -63,7 +75,8 @@ ValueType value(const json_pointer& ptr,
## Return value
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
@ -77,7 +90,8 @@ changes to any JSON value.
the type of the value at `key`
- 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.
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
the type of the value at `ptr`
- 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.
2. Logarithmic in the size of the container.
3. Logarithmic in the size of the container.
## Examples
@ -104,7 +119,7 @@ changes to any JSON value.
--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.
@ -125,5 +140,6 @@ changes to any JSON value.
## Version history
1. Added in version 1.0.0.
2. Added in version 2.0.2.
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 3.11.0.
3. Added in version 2.0.2.

View File

@ -32,6 +32,12 @@ A minimal map-like container that preserves insertion order for use within [`nlo
- **const_iterator**
- **size_type**
- **value_type**
- **key_compare** - key comparison function
```cpp
std::equal_to<Key> // until C++14
std::equal_to<> // since C++14
```
## Member functions
@ -68,3 +74,4 @@ A minimal map-like container that preserves insertion order for use within [`nlo
## Version history
- Added in version 3.9.0 to implement [`nlohmann::ordered_json`](ordered_json.md).
- Added **key_compare** member in version 3.11.0.

View File

@ -97,6 +97,7 @@ nav:
- 'count': api/basic_json/count.md
- 'crbegin': api/basic_json/crbegin.md
- 'crend': api/basic_json/crend.md
- 'default_object_comparator_t': api/basic_json/default_object_comparator_t.md
- 'diff': api/basic_json/diff.md
- 'dump': api/basic_json/dump.md
- 'emplace': api/basic_json/emplace.md

View File

@ -106,6 +106,12 @@
#endif
#endif
#if JSON_HEDLEY_HAS_ATTRIBUTE(no_unique_address)
#define JSON_NO_UNIQUE_ADDRESS [[no_unique_address]]
#else
#define JSON_NO_UNIQUE_ADDRESS
#endif
// disable documentation warnings on clang
#if defined(__clang__)
#pragma clang diagnostic push

View File

@ -14,6 +14,7 @@
#undef NLOHMANN_BASIC_JSON_TPL
#undef JSON_EXPLICIT
#undef NLOHMANN_CAN_CALL_STD_FUNC_IMPL
#undef JSON_NO_UNIQUE_ADDRESS
#ifndef JSON_TEST_KEEP_MACROS
#undef JSON_CATCH

View File

@ -54,11 +54,6 @@ struct is_basic_json_context :
|| std::is_same<BasicJsonContext, std::nullptr_t>::value >
{};
template<typename> struct is_json_pointer : std::false_type {};
template<typename RefStringType>
struct is_json_pointer<json_pointer<RefStringType>> : std::true_type {};
//////////////////////
// json_ref helpers //
//////////////////////
@ -160,6 +155,24 @@ struct has_to_json < BasicJsonType, T, enable_if_t < !is_basic_json<T>::value >>
T>::value;
};
template<typename T>
using detect_key_compare = typename T::key_compare;
template<typename T>
struct has_key_compare : std::integral_constant<bool, is_detected<detect_key_compare, T>::value> {};
// obtains the actual object key comparator
template<typename BasicJsonType>
struct actual_object_comparator
{
using object_t = typename BasicJsonType::object_t;
using object_comparator_t = typename BasicJsonType::default_object_comparator_t;
using type = typename std::conditional < has_key_compare<object_t>::value,
typename object_t::key_compare, object_comparator_t>::type;
};
template<typename BasicJsonType>
using actual_object_comparator_t = typename actual_object_comparator<BasicJsonType>::type;
///////////////////
// is_ functions //
@ -454,6 +467,78 @@ struct is_constructible_tuple : std::false_type {};
template<typename T1, typename... Args>
struct is_constructible_tuple<T1, std::tuple<Args...>> : conjunction<is_constructible<T1, Args>...> {};
template<typename BasicJsonType, typename T>
struct is_json_iterator_of : std::false_type {};
template<typename BasicJsonType>
struct is_json_iterator_of<BasicJsonType, typename BasicJsonType::iterator> : std::true_type {};
template<typename BasicJsonType>
struct is_json_iterator_of<BasicJsonType, typename BasicJsonType::const_iterator> : std::true_type
{};
// checks if a given type T is a template specialization of Primary
template<template <typename...> class Primary, typename T>
struct is_specialization_of : std::false_type {};
template<template <typename...> class Primary, typename... Args>
struct is_specialization_of<Primary, Primary<Args...>> : std::true_type {};
template<typename T>
using is_json_pointer = is_specialization_of<::nlohmann::json_pointer, uncvref_t<T>>;
// checks if A and B are comparable using Compare functor
template<typename Compare, typename A, typename B, typename = void>
struct is_comparable : std::false_type {};
template<typename Compare, typename A, typename B>
struct is_comparable<Compare, A, B, void_t<
decltype(std::declval<Compare>()(std::declval<A>(), std::declval<B>())),
decltype(std::declval<Compare>()(std::declval<B>(), std::declval<A>()))
>> : std::true_type {};
// checks if BasicJsonType::object_t::key_type and KeyType are comparable using Compare functor
template<typename BasicJsonType, typename KeyType>
using is_key_type_comparable = typename is_comparable <
typename BasicJsonType::object_comparator_t,
const key_type_t<typename BasicJsonType::object_t>&,
KeyType >::type;
template<typename T>
using detect_is_transparent = typename T::is_transparent;
// type trait to check if KeyType can be used as object key
// true if:
// - KeyType is comparable with BasicJsonType::object_t::key_type
// - if ExcludeObjectKeyType is true, KeyType is not BasicJsonType::object_t::key_type
// - the comparator is transparent or RequireTransparentComparator is false
// - KeyType is not a JSON iterator or json_pointer
template<typename BasicJsonType, typename KeyTypeCVRef, bool RequireTransparentComparator = true,
bool ExcludeObjectKeyType = RequireTransparentComparator, typename KeyType = uncvref_t<KeyTypeCVRef>>
using is_usable_as_key_type = typename std::conditional <
is_key_type_comparable<BasicJsonType, KeyTypeCVRef>::value
&& !(ExcludeObjectKeyType && std::is_same<KeyType,
typename BasicJsonType::object_t::key_type>::value)
&& (!RequireTransparentComparator || is_detected <
detect_is_transparent,
typename BasicJsonType::object_comparator_t >::value)
&& !is_json_iterator_of<BasicJsonType, KeyType>::value
&& !is_json_pointer<KeyType>::value,
std::true_type,
std::false_type >::type;
template<typename ObjectType, typename KeyType>
using detect_erase_with_key_type = decltype(std::declval<ObjectType&>().erase(std::declval<KeyType>()));
// type trait to check if object_t has an erase() member functions accepting KeyType
template<typename BasicJsonType, typename KeyType>
using has_erase_with_key_type = typename std::conditional <
is_detected <
detect_erase_with_key_type,
typename BasicJsonType::object_t, KeyType >::value,
std::true_type,
std::false_type >::type;
// a naive helper to check if a type is an ordered_map (exploits the fact that
// ordered_map inherits capacity() from std::vector)
template <typename T>

View File

@ -350,21 +350,23 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// the template arguments passed to class @ref basic_json.
/// @{
/// @brief object key comparator type
/// @sa https://json.nlohmann.me/api/basic_json/object_comparator_t/
/// @brief default object key comparator type
/// The actual object key comparator type (@ref object_comparator_t) may be
/// different.
/// @sa https://json.nlohmann.me/api/basic_json/default_object_comparator_t/
#if defined(JSON_HAS_CPP_14)
// Use transparent comparator if possible, combined with perfect forwarding
// on find() and count() calls prevents unnecessary string construction.
using object_comparator_t = std::less<>;
// use of transparent comparator avoids unnecessary repeated construction of temporaries
// in functions involving lookup by key with types other than object_t::key_type (aka. StringType)
using default_object_comparator_t = std::less<>;
#else
using object_comparator_t = std::less<StringType>;
using default_object_comparator_t = std::less<StringType>;
#endif
/// @brief a type for an object
/// @sa https://json.nlohmann.me/api/basic_json/object_t/
using object_t = ObjectType<StringType,
basic_json,
object_comparator_t,
default_object_comparator_t,
AllocatorType<std::pair<const StringType,
basic_json>>>;
@ -396,6 +398,10 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @sa https://json.nlohmann.me/api/basic_json/binary_t/
using binary_t = nlohmann::byte_container_with_subtype<BinaryType>;
/// @brief object key comparator type
/// @sa https://json.nlohmann.me/api/basic_json/object_comparator_t/
using object_comparator_t = detail::actual_object_comparator_t<basic_json>;
/// @}
private:
@ -2000,22 +2006,37 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
reference at(const typename object_t::key_type& key)
{
// at only works for objects
if (JSON_HEDLEY_LIKELY(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
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(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
@ -2023,22 +2044,37 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
const_reference at(const typename object_t::key_type& key) const
{
// at only works for objects
if (JSON_HEDLEY_LIKELY(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
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(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
@ -2102,7 +2138,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @brief access specified object element
/// @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
if (is_null())
@ -2115,7 +2151,8 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
// operator[] only works for objects
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));
@ -2128,31 +2165,47 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
// const operator[] only works for objects
if (JSON_HEDLEY_LIKELY(is_object()))
{
JSON_ASSERT(m_value.object->find(key) != m_value.object->end());
return m_value.object->find(key)->second;
auto it = m_value.object->find(key);
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));
}
/// @brief access specified object element
/// @sa https://json.nlohmann.me/api/basic_json/operator%5B%5D/
// these two functions resolve a (const) char * ambiguity affecting Clang and MSVC
// (they seemingly cannot be constrained to resolve the ambiguity)
template<typename T>
JSON_HEDLEY_NON_NULL(2)
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())
{
m_type = value_t::object;
m_value = value_t::object;
m_value.object = create<object_t>();
assert_invariant();
}
// at only works for objects
// operator[] only works for objects
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));
@ -2160,15 +2213,16 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @brief access specified object element
/// @sa https://json.nlohmann.me/api/basic_json/operator%5B%5D/
template<typename T>
JSON_HEDLEY_NON_NULL(2)
const_reference operator[](T* key) const
template<class KeyType, detail::enable_if_t<
detail::is_usable_as_key_type<basic_json_t, KeyType>::value, int > = 0 >
const_reference operator[](KeyType && key) const
{
// at only works for objects
// const operator[] only works for objects
if (JSON_HEDLEY_LIKELY(is_object()))
{
JSON_ASSERT(m_value.object->find(key) != m_value.object->end());
return m_value.object->find(key)->second;
auto it = m_value.object->find(std::forward<KeyType>(key));
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));
@ -2176,23 +2230,24 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @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 ValueType, typename std::enable_if <
detail::is_getable<basic_json_t, ValueType>::value
&& !std::is_same<value_t, ValueType>::value, int >::type = 0 >
ValueType value(const typename object_t::key_type& key, const ValueType& default_value) const
// this is the value(const typename object_t::key_type&) overload
template < class KeyType, class ValueType, detail::enable_if_t <
std::is_same<KeyType, typename object_t::key_type>::value
&& detail::is_getable<basic_json_t, ValueType>::value
&& !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 key is found, return value and given default value otherwise
const auto it = find(key);
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));
@ -2206,13 +2261,64 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
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
/// @sa https://json.nlohmann.me/api/basic_json/value/
template<class ValueType, typename std::enable_if<
detail::is_getable<basic_json_t, ValueType>::value, int>::type = 0>
template < class ValueType, detail::enable_if_t <
detail::is_getable<basic_json_t, ValueType>::value, int> = 0 >
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 pointer resolves a value, return it or use default value
@ -2229,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));
}
template<class ValueType, class BasicJsonType, typename std::enable_if<
detail::is_getable<basic_json_t, ValueType>::value, int>::type = 0>
template < class ValueType, class BasicJsonType, detail::enable_if_t <
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)
ValueType value(const ::nlohmann::json_pointer<BasicJsonType>& ptr, const ValueType& default_value) const
{
@ -2288,10 +2394,9 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @brief remove element given an iterator
/// @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::const_iterator>::value, int >::type
= 0 >
std::is_same<IteratorType, typename basic_json_t::const_iterator>::value, int > = 0 >
IteratorType erase(IteratorType pos)
{
// make sure iterator fits the current value
@ -2359,10 +2464,9 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @brief remove elements given an iterator range
/// @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::const_iterator>::value, int >::type
= 0 >
std::is_same<IteratorType, typename basic_json_t::const_iterator>::value, int > = 0 >
IteratorType erase(IteratorType first, IteratorType last)
{
// make sure iterator fits the current value
@ -2431,17 +2535,57 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
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
/// @sa https://json.nlohmann.me/api/basic_json/erase/
size_type erase(const typename object_t::key_type& key)
{
// this erase only works for objects
if (JSON_HEDLEY_LIKELY(is_object()))
{
return m_value.object->erase(key);
}
// the indirection via erase_internal() is added to avoid making this
// function a template and thus de-rank it during overload resolution
return erase_internal(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
@ -2476,14 +2620,13 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @brief find an element in a JSON object
/// @sa https://json.nlohmann.me/api/basic_json/find/
template<typename KeyT>
iterator find(KeyT&& key)
iterator find(const typename object_t::key_type& key)
{
auto result = end();
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;
@ -2491,14 +2634,45 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @brief find an element in a JSON object
/// @sa https://json.nlohmann.me/api/basic_json/find/
template<typename KeyT>
const_iterator find(KeyT&& key) const
const_iterator find(const typename object_t::key_type& key) const
{
auto result = cend();
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;
@ -2506,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
/// @sa https://json.nlohmann.me/api/basic_json/count/
template<typename KeyT>
size_type count(KeyT&& key) const
size_type count(const typename object_t::key_type& key) const
{
// 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
/// @sa https://json.nlohmann.me/api/basic_json/contains/
template < typename KeyT, typename std::enable_if <
!detail::is_json_pointer<typename std::decay<KeyT>::type>::value, int >::type = 0 >
bool contains(KeyT && key) const
bool contains(const typename object_t::key_type& 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
@ -4305,7 +4495,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
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)
reference operator[](const ::nlohmann::json_pointer<BasicJsonType>& ptr)
{
@ -4319,7 +4509,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
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)
const_reference operator[](const ::nlohmann::json_pointer<BasicJsonType>& ptr) const
{

View File

@ -1,6 +1,6 @@
#pragma once
#include <functional> // less
#include <functional> // equal_to, less
#include <initializer_list> // initializer_list
#include <iterator> // input_iterator_tag, iterator_traits
#include <memory> // allocator
@ -27,6 +27,11 @@ template <class Key, class T, class IgnoredLess = std::less<Key>,
using const_iterator = typename Container::const_iterator;
using size_type = typename Container::size_type;
using value_type = typename Container::value_type;
#ifdef JSON_HAS_CPP_14
using key_compare = std::equal_to<>;
#else
using key_compare = std::equal_to<Key>;
#endif
// Explicit constructors instead of `using Container::Container`
// otherwise older compilers choke on it (GCC <= 5.5, xcode <= 9.4)
@ -42,7 +47,7 @@ template <class Key, class T, class IgnoredLess = std::less<Key>,
{
for (auto it = this->begin(); it != this->end(); ++it)
{
if (it->first == key)
if (m_compare(it->first, key))
{
return {it, false};
}
@ -65,7 +70,7 @@ template <class Key, class T, class IgnoredLess = std::less<Key>,
{
for (auto it = this->begin(); it != this->end(); ++it)
{
if (it->first == key)
if (m_compare(it->first, key))
{
return it->second;
}
@ -78,7 +83,7 @@ template <class Key, class T, class IgnoredLess = std::less<Key>,
{
for (auto it = this->begin(); it != this->end(); ++it)
{
if (it->first == key)
if (m_compare(it->first, key))
{
return it->second;
}
@ -91,7 +96,7 @@ template <class Key, class T, class IgnoredLess = std::less<Key>,
{
for (auto it = this->begin(); it != this->end(); ++it)
{
if (it->first == key)
if (m_compare(it->first, key))
{
// Since we cannot move const Keys, re-construct them in place
for (auto next = it; ++next != this->end(); ++it)
@ -163,7 +168,7 @@ template <class Key, class T, class IgnoredLess = std::less<Key>,
{
for (auto it = this->begin(); it != this->end(); ++it)
{
if (it->first == key)
if (m_compare(it->first, key))
{
return 1;
}
@ -175,7 +180,7 @@ template <class Key, class T, class IgnoredLess = std::less<Key>,
{
for (auto it = this->begin(); it != this->end(); ++it)
{
if (it->first == key)
if (m_compare(it->first, key))
{
return it;
}
@ -187,7 +192,7 @@ template <class Key, class T, class IgnoredLess = std::less<Key>,
{
for (auto it = this->begin(); it != this->end(); ++it)
{
if (it->first == key)
if (m_compare(it->first, key))
{
return it;
}
@ -204,7 +209,7 @@ template <class Key, class T, class IgnoredLess = std::less<Key>,
{
for (auto it = this->begin(); it != this->end(); ++it)
{
if (it->first == value.first)
if (m_compare(it->first, value.first))
{
return {it, false};
}
@ -225,6 +230,9 @@ template <class Key, class T, class IgnoredLess = std::less<Key>,
insert(*it);
}
}
private:
JSON_NO_UNIQUE_ADDRESS key_compare m_compare = key_compare();
};
} // namespace nlohmann

View File

@ -2411,6 +2411,12 @@ using is_detected_convertible =
#endif
#endif
#if JSON_HEDLEY_HAS_ATTRIBUTE(no_unique_address)
#define JSON_NO_UNIQUE_ADDRESS [[no_unique_address]]
#else
#define JSON_NO_UNIQUE_ADDRESS
#endif
// disable documentation warnings on clang
#if defined(__clang__)
#pragma clang diagnostic push
@ -3183,11 +3189,6 @@ struct is_basic_json_context :
|| std::is_same<BasicJsonContext, std::nullptr_t>::value >
{};
template<typename> struct is_json_pointer : std::false_type {};
template<typename RefStringType>
struct is_json_pointer<json_pointer<RefStringType>> : std::true_type {};
//////////////////////
// json_ref helpers //
//////////////////////
@ -3289,6 +3290,24 @@ struct has_to_json < BasicJsonType, T, enable_if_t < !is_basic_json<T>::value >>
T>::value;
};
template<typename T>
using detect_key_compare = typename T::key_compare;
template<typename T>
struct has_key_compare : std::integral_constant<bool, is_detected<detect_key_compare, T>::value> {};
// obtains the actual object key comparator
template<typename BasicJsonType>
struct actual_object_comparator
{
using object_t = typename BasicJsonType::object_t;
using object_comparator_t = typename BasicJsonType::default_object_comparator_t;
using type = typename std::conditional < has_key_compare<object_t>::value,
typename object_t::key_compare, object_comparator_t>::type;
};
template<typename BasicJsonType>
using actual_object_comparator_t = typename actual_object_comparator<BasicJsonType>::type;
///////////////////
// is_ functions //
@ -3583,6 +3602,78 @@ struct is_constructible_tuple : std::false_type {};
template<typename T1, typename... Args>
struct is_constructible_tuple<T1, std::tuple<Args...>> : conjunction<is_constructible<T1, Args>...> {};
template<typename BasicJsonType, typename T>
struct is_json_iterator_of : std::false_type {};
template<typename BasicJsonType>
struct is_json_iterator_of<BasicJsonType, typename BasicJsonType::iterator> : std::true_type {};
template<typename BasicJsonType>
struct is_json_iterator_of<BasicJsonType, typename BasicJsonType::const_iterator> : std::true_type
{};
// checks if a given type T is a template specialization of Primary
template<template <typename...> class Primary, typename T>
struct is_specialization_of : std::false_type {};
template<template <typename...> class Primary, typename... Args>
struct is_specialization_of<Primary, Primary<Args...>> : std::true_type {};
template<typename T>
using is_json_pointer = is_specialization_of<::nlohmann::json_pointer, uncvref_t<T>>;
// checks if A and B are comparable using Compare functor
template<typename Compare, typename A, typename B, typename = void>
struct is_comparable : std::false_type {};
template<typename Compare, typename A, typename B>
struct is_comparable<Compare, A, B, void_t<
decltype(std::declval<Compare>()(std::declval<A>(), std::declval<B>())),
decltype(std::declval<Compare>()(std::declval<B>(), std::declval<A>()))
>> : std::true_type {};
// checks if BasicJsonType::object_t::key_type and KeyType are comparable using Compare functor
template<typename BasicJsonType, typename KeyType>
using is_key_type_comparable = typename is_comparable <
typename BasicJsonType::object_comparator_t,
const key_type_t<typename BasicJsonType::object_t>&,
KeyType >::type;
template<typename T>
using detect_is_transparent = typename T::is_transparent;
// type trait to check if KeyType can be used as object key
// true if:
// - KeyType is comparable with BasicJsonType::object_t::key_type
// - if ExcludeObjectKeyType is true, KeyType is not BasicJsonType::object_t::key_type
// - the comparator is transparent or RequireTransparentComparator is false
// - KeyType is not a JSON iterator or json_pointer
template<typename BasicJsonType, typename KeyTypeCVRef, bool RequireTransparentComparator = true,
bool ExcludeObjectKeyType = RequireTransparentComparator, typename KeyType = uncvref_t<KeyTypeCVRef>>
using is_usable_as_key_type = typename std::conditional <
is_key_type_comparable<BasicJsonType, KeyTypeCVRef>::value
&& !(ExcludeObjectKeyType && std::is_same<KeyType,
typename BasicJsonType::object_t::key_type>::value)
&& (!RequireTransparentComparator || is_detected <
detect_is_transparent,
typename BasicJsonType::object_comparator_t >::value)
&& !is_json_iterator_of<BasicJsonType, KeyType>::value
&& !is_json_pointer<KeyType>::value,
std::true_type,
std::false_type >::type;
template<typename ObjectType, typename KeyType>
using detect_erase_with_key_type = decltype(std::declval<ObjectType&>().erase(std::declval<KeyType>()));
// type trait to check if object_t has an erase() member functions accepting KeyType
template<typename BasicJsonType, typename KeyType>
using has_erase_with_key_type = typename std::conditional <
is_detected <
detect_erase_with_key_type,
typename BasicJsonType::object_t, KeyType >::value,
std::true_type,
std::false_type >::type;
// a naive helper to check if a type is an ordered_map (exploits the fact that
// ordered_map inherits capacity() from std::vector)
template <typename T>
@ -17834,7 +17925,7 @@ class serializer
// #include <nlohmann/ordered_map.hpp>
#include <functional> // less
#include <functional> // equal_to, less
#include <initializer_list> // initializer_list
#include <iterator> // input_iterator_tag, iterator_traits
#include <memory> // allocator
@ -17862,6 +17953,11 @@ template <class Key, class T, class IgnoredLess = std::less<Key>,
using const_iterator = typename Container::const_iterator;
using size_type = typename Container::size_type;
using value_type = typename Container::value_type;
#ifdef JSON_HAS_CPP_14
using key_compare = std::equal_to<>;
#else
using key_compare = std::equal_to<Key>;
#endif
// Explicit constructors instead of `using Container::Container`
// otherwise older compilers choke on it (GCC <= 5.5, xcode <= 9.4)
@ -17877,7 +17973,7 @@ template <class Key, class T, class IgnoredLess = std::less<Key>,
{
for (auto it = this->begin(); it != this->end(); ++it)
{
if (it->first == key)
if (m_compare(it->first, key))
{
return {it, false};
}
@ -17900,7 +17996,7 @@ template <class Key, class T, class IgnoredLess = std::less<Key>,
{
for (auto it = this->begin(); it != this->end(); ++it)
{
if (it->first == key)
if (m_compare(it->first, key))
{
return it->second;
}
@ -17913,7 +18009,7 @@ template <class Key, class T, class IgnoredLess = std::less<Key>,
{
for (auto it = this->begin(); it != this->end(); ++it)
{
if (it->first == key)
if (m_compare(it->first, key))
{
return it->second;
}
@ -17926,7 +18022,7 @@ template <class Key, class T, class IgnoredLess = std::less<Key>,
{
for (auto it = this->begin(); it != this->end(); ++it)
{
if (it->first == key)
if (m_compare(it->first, key))
{
// Since we cannot move const Keys, re-construct them in place
for (auto next = it; ++next != this->end(); ++it)
@ -17998,7 +18094,7 @@ template <class Key, class T, class IgnoredLess = std::less<Key>,
{
for (auto it = this->begin(); it != this->end(); ++it)
{
if (it->first == key)
if (m_compare(it->first, key))
{
return 1;
}
@ -18010,7 +18106,7 @@ template <class Key, class T, class IgnoredLess = std::less<Key>,
{
for (auto it = this->begin(); it != this->end(); ++it)
{
if (it->first == key)
if (m_compare(it->first, key))
{
return it;
}
@ -18022,7 +18118,7 @@ template <class Key, class T, class IgnoredLess = std::less<Key>,
{
for (auto it = this->begin(); it != this->end(); ++it)
{
if (it->first == key)
if (m_compare(it->first, key))
{
return it;
}
@ -18039,7 +18135,7 @@ template <class Key, class T, class IgnoredLess = std::less<Key>,
{
for (auto it = this->begin(); it != this->end(); ++it)
{
if (it->first == value.first)
if (m_compare(it->first, value.first))
{
return {it, false};
}
@ -18060,6 +18156,9 @@ template <class Key, class T, class IgnoredLess = std::less<Key>,
insert(*it);
}
}
private:
JSON_NO_UNIQUE_ADDRESS key_compare m_compare = key_compare();
};
} // namespace nlohmann
@ -18321,21 +18420,23 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// the template arguments passed to class @ref basic_json.
/// @{
/// @brief object key comparator type
/// @sa https://json.nlohmann.me/api/basic_json/object_comparator_t/
/// @brief default object key comparator type
/// The actual object key comparator type (@ref object_comparator_t) may be
/// different.
/// @sa https://json.nlohmann.me/api/basic_json/default_object_comparator_t/
#if defined(JSON_HAS_CPP_14)
// Use transparent comparator if possible, combined with perfect forwarding
// on find() and count() calls prevents unnecessary string construction.
using object_comparator_t = std::less<>;
// use of transparent comparator avoids unnecessary repeated construction of temporaries
// in functions involving lookup by key with types other than object_t::key_type (aka. StringType)
using default_object_comparator_t = std::less<>;
#else
using object_comparator_t = std::less<StringType>;
using default_object_comparator_t = std::less<StringType>;
#endif
/// @brief a type for an object
/// @sa https://json.nlohmann.me/api/basic_json/object_t/
using object_t = ObjectType<StringType,
basic_json,
object_comparator_t,
default_object_comparator_t,
AllocatorType<std::pair<const StringType,
basic_json>>>;
@ -18367,6 +18468,10 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @sa https://json.nlohmann.me/api/basic_json/binary_t/
using binary_t = nlohmann::byte_container_with_subtype<BinaryType>;
/// @brief object key comparator type
/// @sa https://json.nlohmann.me/api/basic_json/object_comparator_t/
using object_comparator_t = detail::actual_object_comparator_t<basic_json>;
/// @}
private:
@ -19971,22 +20076,37 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
reference at(const typename object_t::key_type& key)
{
// at only works for objects
if (JSON_HEDLEY_LIKELY(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
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(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
@ -19994,22 +20114,37 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
const_reference at(const typename object_t::key_type& key) const
{
// at only works for objects
if (JSON_HEDLEY_LIKELY(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
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(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
@ -20073,7 +20208,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @brief access specified object element
/// @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
if (is_null())
@ -20086,7 +20221,8 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
// operator[] only works for objects
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));
@ -20099,31 +20235,47 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
// const operator[] only works for objects
if (JSON_HEDLEY_LIKELY(is_object()))
{
JSON_ASSERT(m_value.object->find(key) != m_value.object->end());
return m_value.object->find(key)->second;
auto it = m_value.object->find(key);
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));
}
/// @brief access specified object element
/// @sa https://json.nlohmann.me/api/basic_json/operator%5B%5D/
// these two functions resolve a (const) char * ambiguity affecting Clang and MSVC
// (they seemingly cannot be constrained to resolve the ambiguity)
template<typename T>
JSON_HEDLEY_NON_NULL(2)
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())
{
m_type = value_t::object;
m_value = value_t::object;
m_value.object = create<object_t>();
assert_invariant();
}
// at only works for objects
// operator[] only works for objects
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));
@ -20131,15 +20283,16 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @brief access specified object element
/// @sa https://json.nlohmann.me/api/basic_json/operator%5B%5D/
template<typename T>
JSON_HEDLEY_NON_NULL(2)
const_reference operator[](T* key) const
template<class KeyType, detail::enable_if_t<
detail::is_usable_as_key_type<basic_json_t, KeyType>::value, int > = 0 >
const_reference operator[](KeyType && key) const
{
// at only works for objects
// const operator[] only works for objects
if (JSON_HEDLEY_LIKELY(is_object()))
{
JSON_ASSERT(m_value.object->find(key) != m_value.object->end());
return m_value.object->find(key)->second;
auto it = m_value.object->find(std::forward<KeyType>(key));
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));
@ -20147,23 +20300,24 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @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 ValueType, typename std::enable_if <
detail::is_getable<basic_json_t, ValueType>::value
&& !std::is_same<value_t, ValueType>::value, int >::type = 0 >
ValueType value(const typename object_t::key_type& key, const ValueType& default_value) const
// this is the value(const typename object_t::key_type&) overload
template < class KeyType, class ValueType, detail::enable_if_t <
std::is_same<KeyType, typename object_t::key_type>::value
&& detail::is_getable<basic_json_t, ValueType>::value
&& !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 key is found, return value and given default value otherwise
const auto it = find(key);
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));
@ -20177,13 +20331,64 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
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
/// @sa https://json.nlohmann.me/api/basic_json/value/
template<class ValueType, typename std::enable_if<
detail::is_getable<basic_json_t, ValueType>::value, int>::type = 0>
template < class ValueType, detail::enable_if_t <
detail::is_getable<basic_json_t, ValueType>::value, int> = 0 >
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 pointer resolves a value, return it or use default value
@ -20200,8 +20405,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));
}
template<class ValueType, class BasicJsonType, typename std::enable_if<
detail::is_getable<basic_json_t, ValueType>::value, int>::type = 0>
template < class ValueType, class BasicJsonType, detail::enable_if_t <
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)
ValueType value(const ::nlohmann::json_pointer<BasicJsonType>& ptr, const ValueType& default_value) const
{
@ -20259,10 +20464,9 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @brief remove element given an iterator
/// @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::const_iterator>::value, int >::type
= 0 >
std::is_same<IteratorType, typename basic_json_t::const_iterator>::value, int > = 0 >
IteratorType erase(IteratorType pos)
{
// make sure iterator fits the current value
@ -20330,10 +20534,9 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @brief remove elements given an iterator range
/// @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::const_iterator>::value, int >::type
= 0 >
std::is_same<IteratorType, typename basic_json_t::const_iterator>::value, int > = 0 >
IteratorType erase(IteratorType first, IteratorType last)
{
// make sure iterator fits the current value
@ -20402,17 +20605,57 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
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
/// @sa https://json.nlohmann.me/api/basic_json/erase/
size_type erase(const typename object_t::key_type& key)
{
// this erase only works for objects
if (JSON_HEDLEY_LIKELY(is_object()))
{
return m_value.object->erase(key);
}
// the indirection via erase_internal() is added to avoid making this
// function a template and thus de-rank it during overload resolution
return erase_internal(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
@ -20447,14 +20690,13 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @brief find an element in a JSON object
/// @sa https://json.nlohmann.me/api/basic_json/find/
template<typename KeyT>
iterator find(KeyT&& key)
iterator find(const typename object_t::key_type& key)
{
auto result = end();
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;
@ -20462,14 +20704,45 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @brief find an element in a JSON object
/// @sa https://json.nlohmann.me/api/basic_json/find/
template<typename KeyT>
const_iterator find(KeyT&& key) const
const_iterator find(const typename object_t::key_type& key) const
{
auto result = cend();
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;
@ -20477,20 +20750,36 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @brief returns the number of occurrences of a key in a JSON object
/// @sa https://json.nlohmann.me/api/basic_json/count/
template<typename KeyT>
size_type count(KeyT&& key) const
size_type count(const typename object_t::key_type& key) const
{
// 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
/// @sa https://json.nlohmann.me/api/basic_json/contains/
template < typename KeyT, typename std::enable_if <
!detail::is_json_pointer<typename std::decay<KeyT>::type>::value, int >::type = 0 >
bool contains(KeyT && key) const
bool contains(const typename object_t::key_type& 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
@ -22276,7 +22565,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
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)
reference operator[](const ::nlohmann::json_pointer<BasicJsonType>& ptr)
{
@ -22290,7 +22579,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
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)
const_reference operator[](const ::nlohmann::json_pointer<BasicJsonType>& ptr) const
{
@ -22892,6 +23181,7 @@ inline nlohmann::json::json_pointer operator "" _json_pointer(const char* s, std
#undef NLOHMANN_BASIC_JSON_TPL
#undef JSON_EXPLICIT
#undef NLOHMANN_CAN_CALL_STD_FUNC_IMPL
#undef JSON_NO_UNIQUE_ADDRESS
#ifndef JSON_TEST_KEEP_MACROS
#undef JSON_CATCH

View File

@ -60,12 +60,38 @@ TEST_CASE("element access 2")
CHECK(j_const.at("floating") == json(42.23));
CHECK(j_const.at("object") == json::object());
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")
{
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&);
#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")
@ -76,6 +102,11 @@ TEST_CASE("element access 2")
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_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")
@ -84,6 +115,11 @@ TEST_CASE("element access 2")
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_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")
@ -92,6 +128,11 @@ TEST_CASE("element access 2")
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_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")
@ -100,6 +141,11 @@ TEST_CASE("element access 2")
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_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)")
@ -108,6 +154,11 @@ TEST_CASE("element access 2")
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_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)")
@ -116,6 +167,11 @@ TEST_CASE("element access 2")
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_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)")
@ -124,6 +180,11 @@ TEST_CASE("element access 2")
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_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("object", json({{"foo", "bar"}})) == json::object());
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")
@ -177,6 +265,24 @@ TEST_CASE("element access 2")
CHECK(j_const.value("_", 12.34) == Approx(12.34));
CHECK(j_const.value("_", json({{"foo", "bar"}})) == json({{"foo", "bar"}}));
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")
@ -187,6 +293,11 @@ TEST_CASE("element access 2")
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_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")
@ -195,6 +306,11 @@ TEST_CASE("element access 2")
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_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")
@ -203,6 +319,11 @@ TEST_CASE("element access 2")
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_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")
@ -211,6 +332,11 @@ TEST_CASE("element access 2")
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_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)")
@ -219,6 +345,11 @@ TEST_CASE("element access 2")
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_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)")
@ -227,6 +358,11 @@ TEST_CASE("element access 2")
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_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)")
@ -235,6 +371,11 @@ TEST_CASE("element access 2")
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_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")
{
// "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"]);
}
#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("null")
@ -397,10 +613,16 @@ TEST_CASE("element access 2")
json j_nonobject(json::value_t::null);
json j_nonobject2(json::value_t::null);
const json j_const_nonobject(j_nonobject);
CHECK_NOTHROW(j_nonobject["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[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")
@ -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&);
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&);
#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")
@ -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&);
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&);
#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")
@ -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&);
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&);
#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)")
@ -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&);
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&);
#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)")
@ -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&);
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&);
#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)")
@ -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&);
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&);
#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);
}
#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("erase(begin())")
@ -652,36 +949,60 @@ TEST_CASE("element access 2")
{
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&);
#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")
{
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&);
#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")
{
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&);
#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")
{
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&);
#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)")
{
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&);
#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)")
{
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&);
#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.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")
{
CHECK(j.find("foo") == j.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")
@ -713,64 +1050,112 @@ TEST_CASE("element access 2")
{
json j_nonarray(json::value_t::null);
const json j_nonarray_const(j_nonarray);
CHECK(j_nonarray.find("foo") == j_nonarray.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")
{
json j_nonarray(json::value_t::string);
const json j_nonarray_const(j_nonarray);
CHECK(j_nonarray.find("foo") == j_nonarray.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")
{
json j_nonarray(json::value_t::object);
const json j_nonarray_const(j_nonarray);
CHECK(j_nonarray.find("foo") == j_nonarray.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")
{
json j_nonarray(json::value_t::array);
const json j_nonarray_const(j_nonarray);
CHECK(j_nonarray.find("foo") == j_nonarray.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")
{
json j_nonarray(json::value_t::boolean);
const json j_nonarray_const(j_nonarray);
CHECK(j_nonarray.find("foo") == j_nonarray.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)")
{
json j_nonarray(json::value_t::number_integer);
const json j_nonarray_const(j_nonarray);
CHECK(j_nonarray.find("foo") == j_nonarray.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)")
{
json j_nonarray(json::value_t::number_unsigned);
const json j_nonarray_const(j_nonarray);
CHECK(j_nonarray.find("foo") == j_nonarray.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)")
{
json j_nonarray(json::value_t::number_float);
const json j_nonarray_const(j_nonarray);
CHECK(j_nonarray.find("foo") == j_nonarray.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_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")
{
CHECK(j.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")
@ -800,64 +1199,112 @@ TEST_CASE("element access 2")
{
json j_nonobject(json::value_t::null);
const json j_nonobject_const(json::value_t::null);
CHECK(j_nonobject.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")
{
json j_nonobject(json::value_t::string);
const json j_nonobject_const(json::value_t::string);
CHECK(j_nonobject.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")
{
json j_nonobject(json::value_t::object);
const json j_nonobject_const(json::value_t::object);
CHECK(j_nonobject.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")
{
json j_nonobject(json::value_t::array);
const json j_nonobject_const(json::value_t::array);
CHECK(j_nonobject.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")
{
json j_nonobject(json::value_t::boolean);
const json j_nonobject_const(json::value_t::boolean);
CHECK(j_nonobject.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)")
{
json j_nonobject(json::value_t::number_integer);
const json j_nonobject_const(json::value_t::number_integer);
CHECK(j_nonobject.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)")
{
json j_nonobject(json::value_t::number_unsigned);
const json j_nonobject_const(json::value_t::number_unsigned);
CHECK(j_nonobject.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)")
{
json j_nonobject(json::value_t::number_float);
const json j_nonobject_const(json::value_t::number_float);
CHECK(j_nonobject.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_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")
{
CHECK(j.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")
@ -887,56 +1349,98 @@ TEST_CASE("element access 2")
{
json j_nonobject(json::value_t::null);
const json j_nonobject_const(json::value_t::null);
CHECK(j_nonobject.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")
{
json j_nonobject(json::value_t::string);
const json j_nonobject_const(json::value_t::string);
CHECK(j_nonobject.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")
{
json j_nonobject(json::value_t::object);
const json j_nonobject_const(json::value_t::object);
CHECK(j_nonobject.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")
{
json j_nonobject(json::value_t::array);
const json j_nonobject_const(json::value_t::array);
CHECK(j_nonobject.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")
{
json j_nonobject(json::value_t::boolean);
const json j_nonobject_const(json::value_t::boolean);
CHECK(j_nonobject.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)")
{
json j_nonobject(json::value_t::number_integer);
const json j_nonobject_const(json::value_t::number_integer);
CHECK(j_nonobject.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)")
{
json j_nonobject(json::value_t::number_unsigned);
const json j_nonobject_const(json::value_t::number_unsigned);
CHECK(j_nonobject.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)")
@ -945,6 +1449,10 @@ TEST_CASE("element access 2")
const json j_nonobject_const(json::value_t::number_float);
CHECK(j_nonobject.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
}
}
}