mirror of
https://github.com/nlohmann/json.git
synced 2026-09-30 19:50:34 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bc9370c291 | ||
|
|
6a073dbae4 | ||
|
|
fdcc569eee | ||
|
|
666801a2c6 |
@@ -224,5 +224,7 @@ 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 3.11.0.
|
||||
3. Added in version 3.11.0. Fixed in version 3.13.0 to consistently accept `std::string_view`-convertible keys, as
|
||||
already supported by [`operator[]`](operator[].md), [`value`](value.md), [`find`](find.md), and other lookup
|
||||
functions.
|
||||
4. Added in version 2.0.0.
|
||||
|
||||
@@ -119,7 +119,9 @@ Logarithmic in the size of the JSON object.
|
||||
## Version history
|
||||
|
||||
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.
|
||||
2. Added in version 3.6.0. Extended template `KeyType` to support comparable types in version 3.11.0. Fixed in
|
||||
version 3.13.0 to consistently accept `std::string_view`-convertible keys, as already supported by
|
||||
[`operator[]`](operator[].md), [`at`](at.md), [`value`](value.md), and other lookup functions.
|
||||
3. Added in version 3.7.0.
|
||||
4. Deleted overloads for integral key types added in version 3.13.0 to reject such calls at compile time instead of
|
||||
causing undefined behavior at runtime.
|
||||
|
||||
@@ -84,6 +84,8 @@ Logarithmic in the size of the JSON object.
|
||||
## Version history
|
||||
|
||||
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.
|
||||
2. Added in version 1.0.0. Changed parameter `key` type to `KeyType&&` in version 3.11.0. Fixed in version 3.13.0 to
|
||||
consistently accept `std::string_view`-convertible keys, as already supported by [`operator[]`](operator[].md),
|
||||
[`at`](at.md), [`value`](value.md), and other lookup functions.
|
||||
3. Deleted overload for integral key types added in version 3.13.0 to reject such calls at compile time instead of
|
||||
causing undefined behavior at runtime.
|
||||
|
||||
@@ -213,5 +213,7 @@ Strong exception safety: if an exception occurs, the original value stays intact
|
||||
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.
|
||||
4. Added in version 3.11.0. Fixed in version 3.13.0 to consistently accept `std::string_view`-convertible keys, as
|
||||
already supported by [`operator[]`](operator[].md), [`at`](at.md), [`value`](value.md), and other lookup
|
||||
functions.
|
||||
5. Added in version 1.0.0.
|
||||
|
||||
@@ -88,6 +88,8 @@ Logarithmic in the size of the JSON object.
|
||||
## Version history
|
||||
|
||||
1. Added in version 3.11.0.
|
||||
2. Added in version 1.0.0. Changed to support comparable types in version 3.11.0.
|
||||
2. Added in version 1.0.0. Changed to support comparable types in version 3.11.0. Fixed in version 3.13.0 to
|
||||
consistently accept `std::string_view`-convertible keys, as already supported by [`operator[]`](operator[].md),
|
||||
[`at`](at.md), [`value`](value.md), and other lookup functions.
|
||||
3. Deleted overloads for integral key types added in version 3.13.0 to reject such calls at compile time instead of
|
||||
causing undefined behavior at runtime.
|
||||
|
||||
@@ -195,7 +195,9 @@ changes to any JSON value.
|
||||
1. Added in version 1.0.0. Changed parameter `default_value` type from `const ValueType&` to `ValueType&&` in version
|
||||
3.11.0. Deleted overload for integral key types added in version 3.13.0 to reject such calls at compile time
|
||||
instead of causing undefined behavior at runtime.
|
||||
2. Added in version 3.11.0. Made `ValueType` the first template parameter in version 3.11.2.
|
||||
2. Added in version 3.11.0. Made `ValueType` the first template parameter in version 3.11.2. Fixed in version 3.13.0
|
||||
to consistently accept `std::string_view`-convertible keys, as already supported by
|
||||
[`operator[]`](operator[].md), [`at`](at.md), [`find`](find.md), and other lookup functions.
|
||||
3. Added in version 2.0.2. Extended to work with arrays in version 3.13.0, including fixing an issue where resolving
|
||||
`ptr` through an array unexpectedly threw `out_of_range` instead of returning the resolved element (or
|
||||
`default_value`, as documented).
|
||||
|
||||
@@ -62,7 +62,6 @@ By default, `#!cpp JSON_NO_AUTOMATIC_UDLS` is not defined, and `<nlohmann/json.h
|
||||
- [`operator""_json`](../operator_literal_json.md)
|
||||
- [`operator""_json_pointer`](../operator_literal_json_pointer.md)
|
||||
- [`JSON_USE_GLOBAL_UDLS`](json_use_global_udls.md) - place user-defined string literals (UDLs) into the global namespace
|
||||
- [Compile times](../../integration/compile_times.md) - options to reduce compile times
|
||||
|
||||
## Version history
|
||||
|
||||
|
||||
@@ -18,6 +18,10 @@ Deserializes an input stream to a JSON value.
|
||||
|
||||
the stream `i`
|
||||
|
||||
## Exception safety
|
||||
|
||||
Strong guarantee: if an exception is thrown, there are no changes in `j`.
|
||||
|
||||
## Exceptions
|
||||
|
||||
- Throws [`parse_error.101`](../home/exceptions.md#jsonexceptionparse_error101) in case of an unexpected token, or if
|
||||
@@ -125,3 +129,5 @@ being read.
|
||||
the stream; planned to become the default in version 4.0.0.
|
||||
- Fixed a null pointer dereference for an `std::istream` without a stream buffer (now throws `parse_error.101`), and a
|
||||
crash (`std::terminate`) when `i` has `eofbit` in its exception mask, in version 3.13.0.
|
||||
- Changed to the strong exception safety guarantee in version 3.13.0: `j` is no longer left with a partially parsed
|
||||
value if parsing throws.
|
||||
|
||||
@@ -389,6 +389,7 @@ using array_t = ArrayType<basic_json, AllocatorType<basic_json>>;
|
||||
| Functionality | Additional requirement |
|
||||
|-----------------------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| [`diff`](../../api/basic_json/diff.md), [`items`](../../api/basic_json/items.md), [`std::hash`](../../api/basic_json/std_hash.md) | conversion of a `#!cpp std::size_t` to `StringType`: either assignability from the result of `#!cpp std::to_string`, or an ADL overload `#!cpp void int_to_string(StringType&, std::size_t)` |
|
||||
| [`operator/(std::size_t)`](../../api/json_pointer/operator_slash.md) | the same conversion of a `#!cpp std::size_t` to `StringType` as `diff`, `items`, and `std::hash` above |
|
||||
| [`std::hash<basic_json>`](../../api/basic_json/std_hash.md) | additionally a specialization of `#!cpp std::hash<StringType>` |
|
||||
| [`to_bson`](../../api/basic_json/to_bson.md) | `find(value_type)` and `npos` |
|
||||
| [`parse`](../../api/basic_json/parse.md) from a `string_t` | the input adapters must accept it; otherwise pass a character range |
|
||||
|
||||
@@ -1,149 +0,0 @@
|
||||
# Compile times
|
||||
|
||||
The library is header-only and makes heavy use of templates, so every translation unit that includes
|
||||
`<nlohmann/json.hpp>` pays for parsing the header and instantiating what it uses. This page lists the options to reduce
|
||||
that cost, ordered by how much they typically save.
|
||||
|
||||
!!! info "Measurements"
|
||||
|
||||
The numbers below are medians of nine runs compiling a single translation unit with `-std=c++17 -c` against the
|
||||
single-header version, with Apple clang and GCC 16 on macOS (Apple silicon). They show the order of magnitude to
|
||||
expect; measure your own code before and after a change.
|
||||
|
||||
## Include `json_fwd.hpp` in headers
|
||||
|
||||
Header files that only need to *name* the `json` type — for function declarations, members held by pointer or
|
||||
reference, or friend declarations — can include `<nlohmann/json_fwd.hpp>` instead of `<nlohmann/json.hpp>`. It only
|
||||
forward-declares `basic_json`, `json`, `ordered_json`, `json_pointer`, and `adl_serializer`. The translation units that
|
||||
actually use the values then include `<nlohmann/json.hpp>`.
|
||||
|
||||
```cpp title="person.hpp"
|
||||
#pragma once
|
||||
#include <nlohmann/json_fwd.hpp>
|
||||
|
||||
struct person;
|
||||
void to_json(nlohmann::json& j, const person& p);
|
||||
void from_json(const nlohmann::json& j, person& p);
|
||||
```
|
||||
|
||||
```cpp title="person.cpp"
|
||||
#include "person.hpp"
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
void to_json(nlohmann::json& j, const person& p) { /* ... */ }
|
||||
void from_json(const nlohmann::json& j, person& p) { /* ... */ }
|
||||
```
|
||||
|
||||
| Compiler | `json.hpp` (`-O0`) | `json_fwd.hpp` (`-O0`) | Change |
|
||||
|-------------|-------------------:|-----------------------:|-------:|
|
||||
| Apple clang | 704 ms | 329 ms | −53% |
|
||||
| GCC 16 | 779 ms | 242 ms | −69% |
|
||||
|
||||
This is the most effective option, because it avoids the full header in every translation unit that includes
|
||||
*your* headers.
|
||||
|
||||
## Opt out of the automatic user-defined string literals
|
||||
|
||||
The user-defined string literals [`operator""_json`](../api/operator_literal_json.md) and
|
||||
[`operator""_json_pointer`](../api/operator_literal_json_pointer.md) are ordinary inline functions whose bodies call the
|
||||
parser. As `<nlohmann/json.hpp>` includes them by default, every translation unit instantiates the parser, even if it
|
||||
never parses anything itself.
|
||||
|
||||
Define [`JSON_NO_AUTOMATIC_UDLS`](../api/macros/json_no_automatic_udls.md) for the whole project and include
|
||||
`<nlohmann/json_literals.hpp>` only in the files that use the literals:
|
||||
|
||||
```cmake
|
||||
target_compile_definitions(my_target PRIVATE JSON_NO_AUTOMATIC_UDLS)
|
||||
```
|
||||
|
||||
```cpp
|
||||
#include <nlohmann/json.hpp>
|
||||
#include <nlohmann/json_literals.hpp> // only where "..."_json is used
|
||||
```
|
||||
|
||||
The saving applies to translation units that do not parse JSON, for example ones that define types and their
|
||||
conversions or only pass `json` values around:
|
||||
|
||||
| Compiler | Translation unit | Default (`-O0` / `-O2`) | `JSON_NO_AUTOMATIC_UDLS` (`-O0` / `-O2`) | Change |
|
||||
|-------------|------------------|------------------------:|-----------------------------------------:|------------:|
|
||||
| Apple clang | model | 776 ms / 846 ms | 629 ms / 692 ms | −19% / −18% |
|
||||
| GCC 16 | model | 1022 ms / 1120 ms | 882 ms / 965 ms | −14% / −14% |
|
||||
| Apple clang | parsing | 992 ms / 1815 ms | 1006 ms / 1823 ms | +1% / 0% |
|
||||
| GCC 16 | parsing | 2018 ms / 3420 ms | 1990 ms / 3454 ms | −1% / +1% |
|
||||
|
||||
Translation units that include only the header save up to a third. Translation units that parse anyway instantiate
|
||||
the parser regardless and see no difference.
|
||||
|
||||
## Instantiate `basic_json` once
|
||||
|
||||
Each translation unit instantiates the member functions of `nlohmann::json` it uses. An explicit instantiation
|
||||
declaration tells the compiler that the non-template members are instantiated elsewhere, so it can skip them:
|
||||
|
||||
```cpp title="json_instance.hpp"
|
||||
#pragma once
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
extern template class nlohmann::basic_json<>;
|
||||
```
|
||||
|
||||
```cpp title="json_instance.cpp"
|
||||
#include "json_instance.hpp"
|
||||
|
||||
template class nlohmann::basic_json<>;
|
||||
```
|
||||
|
||||
Include `json_instance.hpp` instead of `<nlohmann/json.hpp>` and compile and link `json_instance.cpp` once.
|
||||
|
||||
| Compiler | Translation unit | Default (`-O0` / `-O2`) | `extern template` (`-O0` / `-O2`) | Change |
|
||||
|-------------|---------------------|------------------------:|----------------------------------:|------------:|
|
||||
| Apple clang | parsing | 992 ms / 1815 ms | 953 ms / 1625 ms | −4% / −10% |
|
||||
| GCC 16 | parsing | 2018 ms / 3420 ms | 1522 ms / 2728 ms | −25% / −20% |
|
||||
| Apple clang | `json_instance.cpp` | — | 2166 ms / 4660 ms | — |
|
||||
| GCC 16 | `json_instance.cpp` | — | 5085 ms / 10616 ms | — |
|
||||
|
||||
Notes:
|
||||
|
||||
- The saving grows with the number of translation units that use `json`, while the instantiation translation unit is
|
||||
compiled only once (and is rarely recompiled, as it does not depend on your code).
|
||||
- Member function templates (such as `get<T>()`, `parse(InputType&&)`, or `value(key, default)`) are not covered by
|
||||
the explicit instantiation and are still instantiated where they are used.
|
||||
- The declaration covers exactly `nlohmann::json`. Add the same lines for `nlohmann::ordered_json`
|
||||
(`nlohmann::basic_json<nlohmann::ordered_map>`) or your own `basic_json` specializations if you use them.
|
||||
|
||||
## Use C++20 modules
|
||||
|
||||
With a toolchain that supports named modules, `import nlohmann.json;` compiles the library once into a module and
|
||||
avoids parsing the header in every translation unit. See [Modules](../features/modules.md) for requirements and known
|
||||
issues. Module support is experimental and currently depends heavily on the compiler version.
|
||||
|
||||
## Use precompiled headers
|
||||
|
||||
Build systems can precompile `<nlohmann/json.hpp>` together with other stable headers, for example with CMake's
|
||||
[`target_precompile_headers`](https://cmake.org/cmake/help/latest/command/target_precompile_headers.html):
|
||||
|
||||
```cmake
|
||||
target_precompile_headers(my_target PRIVATE <nlohmann/json.hpp>)
|
||||
```
|
||||
|
||||
This removes the cost of parsing the header, but not of instantiating templates in each translation unit, so it
|
||||
combines well with the options above.
|
||||
|
||||
## Options without effect on compile times
|
||||
|
||||
Some configuration macros change what the library declares, but do not measurably change compile times:
|
||||
|
||||
| Macro | Apple clang, model (`-O0` / `-O2`) | GCC 16, model (`-O0` / `-O2`) |
|
||||
|------------------------------------------------------------------------|-----------------------------------:|------------------------------:|
|
||||
| default | 776 ms / 846 ms | 1022 ms / 1120 ms |
|
||||
| [`JSON_NO_IO`](../api/macros/json_no_io.md) | 764 ms / 836 ms | 1022 ms / 1117 ms |
|
||||
| [`JSON_USE_GLOBAL_UDLS`](../api/macros/json_use_global_udls.md)`=0` | 763 ms / 852 ms | 1019 ms / 1106 ms |
|
||||
|
||||
`JSON_USE_GLOBAL_UDLS` only controls *where* the literals are declared; to avoid their cost, use
|
||||
`JSON_NO_AUTOMATIC_UDLS` instead.
|
||||
|
||||
## See also
|
||||
|
||||
- [`JSON_NO_AUTOMATIC_UDLS`](../api/macros/json_no_automatic_udls.md) - do not include the user-defined string
|
||||
literals automatically
|
||||
- [Modules](../features/modules.md) - C++20 module support
|
||||
- [Header only](index.md) - including the library
|
||||
@@ -15,7 +15,7 @@ Clang).
|
||||
|
||||
You can further use file
|
||||
[`single_include/nlohmann/json_fwd.hpp`](https://github.com/nlohmann/json/blob/develop/single_include/nlohmann/json_fwd.hpp)
|
||||
for forward declarations (see [Compile times](compile_times.md)), and file
|
||||
for forward declarations, and file
|
||||
[`single_include/nlohmann/json_literals.hpp`](https://github.com/nlohmann/json/blob/develop/single_include/nlohmann/json_literals.hpp)
|
||||
for the user-defined string literals if you define
|
||||
[`JSON_NO_AUTOMATIC_UDLS`](../api/macros/json_no_automatic_udls.md).
|
||||
|
||||
@@ -106,7 +106,6 @@ nav:
|
||||
- integration/cmake.md
|
||||
- integration/package_managers.md
|
||||
- integration/pkg-config.md
|
||||
- integration/compile_times.md
|
||||
- API Documentation:
|
||||
- basic_json:
|
||||
- 'Overview': api/basic_json/index.md
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include <nlohmann/detail/macro_scope.hpp>
|
||||
#include <nlohmann/detail/string_concat.hpp>
|
||||
#include <nlohmann/detail/string_escape.hpp>
|
||||
#include <nlohmann/detail/string_utils.hpp>
|
||||
#include <nlohmann/detail/value_t.hpp>
|
||||
|
||||
NLOHMANN_JSON_NAMESPACE_BEGIN
|
||||
@@ -116,7 +117,7 @@ class json_pointer
|
||||
/// @sa https://json.nlohmann.me/api/json_pointer/operator_slasheq/
|
||||
json_pointer& operator/=(std::size_t array_idx)
|
||||
{
|
||||
return *this /= std::to_string(array_idx);
|
||||
return *this /= detail::to_string<string_t>(array_idx);
|
||||
}
|
||||
|
||||
/// @brief create a new JSON pointer by appending the right JSON pointer at the end of the left JSON pointer
|
||||
@@ -752,7 +753,7 @@ class json_pointer
|
||||
// would throw out_of_range.404 -- contains() must not throw (see #5395)
|
||||
return false;
|
||||
}
|
||||
if (JSON_HEDLEY_UNLIKELY(reference_token.size() == 1 && !("0" <= reference_token && reference_token <= "9")))
|
||||
if (JSON_HEDLEY_UNLIKELY(reference_token.size() == 1 && !('0' <= reference_token[0] && reference_token[0] <= '9')))
|
||||
{
|
||||
// invalid char
|
||||
return false;
|
||||
@@ -780,7 +781,7 @@ class json_pointer
|
||||
// not throw (see #5395), so such a reference token is treated as "not found"
|
||||
errno = 0; // strtoull() does not reset errno on success
|
||||
char* p_end = nullptr; // NOLINT(misc-const-correctness)
|
||||
const unsigned long long magnitude = std::strtoull(reference_token.c_str(), &p_end, 10); // NOLINT(runtime/int)
|
||||
const unsigned long long magnitude = std::strtoull(reference_token.data(), &p_end, 10); // NOLINT(runtime/int)
|
||||
if (JSON_HEDLEY_UNLIKELY(errno == ERANGE // the value exceeds ULLONG_MAX
|
||||
|| magnitude >= static_cast<unsigned long long>((std::numeric_limits<typename BasicJsonType::size_type>::max)()))) // NOLINT(runtime/int)
|
||||
{
|
||||
|
||||
@@ -748,6 +748,30 @@ using is_usable_as_key_type = typename std::conditional <
|
||||
std::true_type,
|
||||
std::false_type >::type;
|
||||
|
||||
#ifdef JSON_HAS_CPP_17
|
||||
// type trait to check if KeyType can only be used as an object key after
|
||||
// converting it to std::string_view: it is convertible to std::string_view, the
|
||||
// object's comparator cannot compare it with object_t::key_type directly, but
|
||||
// can compare a std::string_view. JSON pointers and JSON iterators are ruled out
|
||||
// first, so that the conversion checks are never instantiated for them (a JSON
|
||||
// pointer's deprecated conversion to string_t would be named otherwise).
|
||||
template < typename BasicJsonType, typename KeyTypeCVRef, typename KeyType = uncvref_t<KeyTypeCVRef>,
|
||||
bool = is_json_pointer<KeyType>::value || is_json_iterator_of<BasicJsonType, KeyType>::value >
|
||||
struct is_string_view_convertible_key_type : std::false_type {};
|
||||
|
||||
template<typename BasicJsonType, typename KeyTypeCVRef, typename KeyType>
|
||||
struct is_string_view_convertible_key_type<BasicJsonType, KeyTypeCVRef, KeyType, false>
|
||||
: std::integral_constant < bool,
|
||||
std::is_convertible<KeyTypeCVRef, std::string_view>::value
|
||||
&& !is_usable_as_key_type<typename BasicJsonType::object_comparator_t,
|
||||
typename BasicJsonType::object_t::key_type, KeyTypeCVRef, true, false>::value
|
||||
&& is_usable_as_key_type<typename BasicJsonType::object_comparator_t,
|
||||
typename BasicJsonType::object_t::key_type, std::string_view, true, false>::value > {};
|
||||
#else
|
||||
template<typename BasicJsonType, typename KeyTypeCVRef>
|
||||
struct is_string_view_convertible_key_type : std::false_type {};
|
||||
#endif
|
||||
|
||||
// type trait to check if KeyType can be used as an object key
|
||||
// true if:
|
||||
// - KeyType is comparable with BasicJsonType::object_t::key_type
|
||||
@@ -761,9 +785,7 @@ using is_usable_as_basic_json_key_type = typename std::conditional <
|
||||
typename BasicJsonType::object_t::key_type, KeyTypeCVRef,
|
||||
RequireTransparentComparator, ExcludeObjectKeyType>::value
|
||||
&& !is_json_iterator_of<BasicJsonType, KeyType>::value)
|
||||
#ifdef JSON_HAS_CPP_17
|
||||
|| std::is_convertible<KeyType, std::string_view>::value
|
||||
#endif
|
||||
|| is_string_view_convertible_key_type<BasicJsonType, KeyTypeCVRef>::value
|
||||
, std::true_type,
|
||||
std::false_type >::type;
|
||||
|
||||
|
||||
+36
-13
@@ -807,6 +807,24 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
return it;
|
||||
}
|
||||
|
||||
/// @brief the key to look up an object member with: the key itself, or its
|
||||
/// std::string_view if the object can only be searched with that
|
||||
template < typename KeyType, detail::enable_if_t <
|
||||
!detail::is_string_view_convertible_key_type<basic_json_t, KeyType>::value, int > = 0 >
|
||||
static KeyType && lookup_key(KeyType && key) noexcept
|
||||
{
|
||||
return std::forward<KeyType>(key);
|
||||
}
|
||||
|
||||
#ifdef JSON_HAS_CPP_17
|
||||
template < typename KeyType, detail::enable_if_t <
|
||||
detail::is_string_view_convertible_key_type<basic_json_t, KeyType>::value, int > = 0 >
|
||||
static std::string_view lookup_key(KeyType && key)
|
||||
{
|
||||
return std::forward<KeyType>(key);
|
||||
}
|
||||
#endif
|
||||
|
||||
/// @brief erase an element from the object and return the following one
|
||||
/// Not every map returns an iterator from erase(iterator): some containers
|
||||
/// (e.g., Abseil's hash maps) return void to avoid computing a successor
|
||||
@@ -2767,7 +2785,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
JSON_THROW(type_error::create(304, detail::concat("cannot use at() with ", type_name()), this));
|
||||
}
|
||||
|
||||
auto it = m_data.m_value.object->find(std::forward<KeyType>(key));
|
||||
auto it = m_data.m_value.object->find(lookup_key(std::forward<KeyType>(key)));
|
||||
if (it == m_data.m_value.object->end())
|
||||
{
|
||||
JSON_THROW(out_of_range::create(403, detail::concat("key '", string_t(std::forward<KeyType>(key)), "' not found"), this));
|
||||
@@ -2805,7 +2823,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
JSON_THROW(type_error::create(304, detail::concat("cannot use at() with ", type_name()), this));
|
||||
}
|
||||
|
||||
auto it = m_data.m_value.object->find(std::forward<KeyType>(key));
|
||||
auto it = m_data.m_value.object->find(lookup_key(std::forward<KeyType>(key)));
|
||||
if (it == m_data.m_value.object->end())
|
||||
{
|
||||
JSON_THROW(out_of_range::create(403, detail::concat("key '", string_t(std::forward<KeyType>(key)), "' not found"), this));
|
||||
@@ -2948,7 +2966,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
// operator[] only works for objects
|
||||
if (JSON_HEDLEY_LIKELY(is_object()))
|
||||
{
|
||||
auto result = m_data.m_value.object->emplace(std::forward<KeyType>(key), nullptr);
|
||||
auto result = m_data.m_value.object->emplace(lookup_key(std::forward<KeyType>(key)), nullptr);
|
||||
return set_parent(result.first->second);
|
||||
}
|
||||
|
||||
@@ -2964,7 +2982,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
// const operator[] only works for objects
|
||||
if (JSON_HEDLEY_LIKELY(is_object()))
|
||||
{
|
||||
auto it = m_data.m_value.object->find(std::forward<KeyType>(key));
|
||||
auto it = m_data.m_value.object->find(lookup_key(std::forward<KeyType>(key)));
|
||||
JSON_ASSERT(it != m_data.m_value.object->end());
|
||||
return it->second;
|
||||
}
|
||||
@@ -2974,8 +2992,10 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
|
||||
private:
|
||||
template<typename KeyType>
|
||||
using is_comparable_with_object_key = detail::is_comparable <
|
||||
object_comparator_t, const typename object_t::key_type&, KeyType >;
|
||||
using is_comparable_with_object_key = std::integral_constant < bool,
|
||||
detail::is_comparable <
|
||||
object_comparator_t, const typename object_t::key_type&, KeyType >::value
|
||||
|| detail::is_string_view_convertible_key_type<basic_json_t, KeyType>::value >;
|
||||
|
||||
template<typename ValueType>
|
||||
using value_return_type = std::conditional <
|
||||
@@ -3362,7 +3382,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
JSON_THROW(type_error::create(307, detail::concat("cannot use erase() with ", type_name()), this));
|
||||
}
|
||||
|
||||
const auto it = m_data.m_value.object->find(std::forward<KeyType>(key));
|
||||
const auto it = m_data.m_value.object->find(lookup_key(std::forward<KeyType>(key)));
|
||||
if (it != m_data.m_value.object->end())
|
||||
{
|
||||
m_data.m_value.object->erase(it);
|
||||
@@ -3389,7 +3409,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
detail::is_usable_as_basic_json_key_type<basic_json_t, KeyType>::value, int> = 0>
|
||||
size_type erase(KeyType && key)
|
||||
{
|
||||
return erase_internal(std::forward<KeyType>(key));
|
||||
return erase_internal(lookup_key(std::forward<KeyType>(key)));
|
||||
}
|
||||
|
||||
/// @brief remove element from a JSON array given an index
|
||||
@@ -3469,7 +3489,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
|
||||
if (is_object())
|
||||
{
|
||||
result.m_it.object_iterator = m_data.m_value.object->find(std::forward<KeyType>(key));
|
||||
result.m_it.object_iterator = m_data.m_value.object->find(lookup_key(std::forward<KeyType>(key)));
|
||||
}
|
||||
|
||||
return result;
|
||||
@@ -3485,7 +3505,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
|
||||
if (is_object())
|
||||
{
|
||||
result.m_it.object_iterator = m_data.m_value.object->find(std::forward<KeyType>(key));
|
||||
result.m_it.object_iterator = m_data.m_value.object->find(lookup_key(std::forward<KeyType>(key)));
|
||||
}
|
||||
|
||||
return result;
|
||||
@@ -3508,7 +3528,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
size_type count(KeyType && key) const
|
||||
{
|
||||
// return 0 for all nonobject types
|
||||
return is_object() ? m_data.m_value.object->count(std::forward<KeyType>(key)) : 0;
|
||||
return is_object() ? m_data.m_value.object->count(lookup_key(std::forward<KeyType>(key))) : 0;
|
||||
}
|
||||
|
||||
/// @brief check the existence of an element in a JSON object
|
||||
@@ -3526,7 +3546,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
JSON_HEDLEY_WARN_UNUSED_RESULT
|
||||
bool contains(KeyType && key) const
|
||||
{
|
||||
return is_object() && m_data.m_value.object->find(std::forward<KeyType>(key)) != m_data.m_value.object->end();
|
||||
return is_object() && m_data.m_value.object->find(lookup_key(std::forward<KeyType>(key))) != m_data.m_value.object->end();
|
||||
}
|
||||
|
||||
/// @brief check the existence of an element in a JSON object given a JSON pointer
|
||||
@@ -5092,7 +5112,10 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
/// @sa https://json.nlohmann.me/api/basic_json/operator_gtgt/
|
||||
friend std::istream& operator>>(std::istream& i, basic_json& j)
|
||||
{
|
||||
parser(detail::input_adapter(i)).parse(false, j);
|
||||
// parse into a temporary so that j is left unchanged if parsing fails
|
||||
basic_json result;
|
||||
parser(detail::input_adapter(i)).parse(false, result);
|
||||
j = std::move(result);
|
||||
return i;
|
||||
}
|
||||
#endif // JSON_NO_IO
|
||||
|
||||
@@ -4756,6 +4756,30 @@ using is_usable_as_key_type = typename std::conditional <
|
||||
std::true_type,
|
||||
std::false_type >::type;
|
||||
|
||||
#ifdef JSON_HAS_CPP_17
|
||||
// type trait to check if KeyType can only be used as an object key after
|
||||
// converting it to std::string_view: it is convertible to std::string_view, the
|
||||
// object's comparator cannot compare it with object_t::key_type directly, but
|
||||
// can compare a std::string_view. JSON pointers and JSON iterators are ruled out
|
||||
// first, so that the conversion checks are never instantiated for them (a JSON
|
||||
// pointer's deprecated conversion to string_t would be named otherwise).
|
||||
template < typename BasicJsonType, typename KeyTypeCVRef, typename KeyType = uncvref_t<KeyTypeCVRef>,
|
||||
bool = is_json_pointer<KeyType>::value || is_json_iterator_of<BasicJsonType, KeyType>::value >
|
||||
struct is_string_view_convertible_key_type : std::false_type {};
|
||||
|
||||
template<typename BasicJsonType, typename KeyTypeCVRef, typename KeyType>
|
||||
struct is_string_view_convertible_key_type<BasicJsonType, KeyTypeCVRef, KeyType, false>
|
||||
: std::integral_constant < bool,
|
||||
std::is_convertible<KeyTypeCVRef, std::string_view>::value
|
||||
&& !is_usable_as_key_type<typename BasicJsonType::object_comparator_t,
|
||||
typename BasicJsonType::object_t::key_type, KeyTypeCVRef, true, false>::value
|
||||
&& is_usable_as_key_type<typename BasicJsonType::object_comparator_t,
|
||||
typename BasicJsonType::object_t::key_type, std::string_view, true, false>::value > {};
|
||||
#else
|
||||
template<typename BasicJsonType, typename KeyTypeCVRef>
|
||||
struct is_string_view_convertible_key_type : std::false_type {};
|
||||
#endif
|
||||
|
||||
// type trait to check if KeyType can be used as an object key
|
||||
// true if:
|
||||
// - KeyType is comparable with BasicJsonType::object_t::key_type
|
||||
@@ -4769,9 +4793,7 @@ using is_usable_as_basic_json_key_type = typename std::conditional <
|
||||
typename BasicJsonType::object_t::key_type, KeyTypeCVRef,
|
||||
RequireTransparentComparator, ExcludeObjectKeyType>::value
|
||||
&& !is_json_iterator_of<BasicJsonType, KeyType>::value)
|
||||
#ifdef JSON_HAS_CPP_17
|
||||
|| std::is_convertible<KeyType, std::string_view>::value
|
||||
#endif
|
||||
|| is_string_view_convertible_key_type<BasicJsonType, KeyTypeCVRef>::value
|
||||
, std::true_type,
|
||||
std::false_type >::type;
|
||||
|
||||
@@ -19636,6 +19658,8 @@ NLOHMANN_JSON_NAMESPACE_END
|
||||
|
||||
// #include <nlohmann/detail/string_escape.hpp>
|
||||
|
||||
// #include <nlohmann/detail/string_utils.hpp>
|
||||
|
||||
// #include <nlohmann/detail/value_t.hpp>
|
||||
|
||||
|
||||
@@ -19727,7 +19751,7 @@ class json_pointer
|
||||
/// @sa https://json.nlohmann.me/api/json_pointer/operator_slasheq/
|
||||
json_pointer& operator/=(std::size_t array_idx)
|
||||
{
|
||||
return *this /= std::to_string(array_idx);
|
||||
return *this /= detail::to_string<string_t>(array_idx);
|
||||
}
|
||||
|
||||
/// @brief create a new JSON pointer by appending the right JSON pointer at the end of the left JSON pointer
|
||||
@@ -20363,7 +20387,7 @@ class json_pointer
|
||||
// would throw out_of_range.404 -- contains() must not throw (see #5395)
|
||||
return false;
|
||||
}
|
||||
if (JSON_HEDLEY_UNLIKELY(reference_token.size() == 1 && !("0" <= reference_token && reference_token <= "9")))
|
||||
if (JSON_HEDLEY_UNLIKELY(reference_token.size() == 1 && !('0' <= reference_token[0] && reference_token[0] <= '9')))
|
||||
{
|
||||
// invalid char
|
||||
return false;
|
||||
@@ -20391,7 +20415,7 @@ class json_pointer
|
||||
// not throw (see #5395), so such a reference token is treated as "not found"
|
||||
errno = 0; // strtoull() does not reset errno on success
|
||||
char* p_end = nullptr; // NOLINT(misc-const-correctness)
|
||||
const unsigned long long magnitude = std::strtoull(reference_token.c_str(), &p_end, 10); // NOLINT(runtime/int)
|
||||
const unsigned long long magnitude = std::strtoull(reference_token.data(), &p_end, 10); // NOLINT(runtime/int)
|
||||
if (JSON_HEDLEY_UNLIKELY(errno == ERANGE // the value exceeds ULLONG_MAX
|
||||
|| magnitude >= static_cast<unsigned long long>((std::numeric_limits<typename BasicJsonType::size_type>::max)()))) // NOLINT(runtime/int)
|
||||
{
|
||||
@@ -27732,6 +27756,24 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
return it;
|
||||
}
|
||||
|
||||
/// @brief the key to look up an object member with: the key itself, or its
|
||||
/// std::string_view if the object can only be searched with that
|
||||
template < typename KeyType, detail::enable_if_t <
|
||||
!detail::is_string_view_convertible_key_type<basic_json_t, KeyType>::value, int > = 0 >
|
||||
static KeyType && lookup_key(KeyType && key) noexcept
|
||||
{
|
||||
return std::forward<KeyType>(key);
|
||||
}
|
||||
|
||||
#ifdef JSON_HAS_CPP_17
|
||||
template < typename KeyType, detail::enable_if_t <
|
||||
detail::is_string_view_convertible_key_type<basic_json_t, KeyType>::value, int > = 0 >
|
||||
static std::string_view lookup_key(KeyType && key)
|
||||
{
|
||||
return std::forward<KeyType>(key);
|
||||
}
|
||||
#endif
|
||||
|
||||
/// @brief erase an element from the object and return the following one
|
||||
/// Not every map returns an iterator from erase(iterator): some containers
|
||||
/// (e.g., Abseil's hash maps) return void to avoid computing a successor
|
||||
@@ -29692,7 +29734,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
JSON_THROW(type_error::create(304, detail::concat("cannot use at() with ", type_name()), this));
|
||||
}
|
||||
|
||||
auto it = m_data.m_value.object->find(std::forward<KeyType>(key));
|
||||
auto it = m_data.m_value.object->find(lookup_key(std::forward<KeyType>(key)));
|
||||
if (it == m_data.m_value.object->end())
|
||||
{
|
||||
JSON_THROW(out_of_range::create(403, detail::concat("key '", string_t(std::forward<KeyType>(key)), "' not found"), this));
|
||||
@@ -29730,7 +29772,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
JSON_THROW(type_error::create(304, detail::concat("cannot use at() with ", type_name()), this));
|
||||
}
|
||||
|
||||
auto it = m_data.m_value.object->find(std::forward<KeyType>(key));
|
||||
auto it = m_data.m_value.object->find(lookup_key(std::forward<KeyType>(key)));
|
||||
if (it == m_data.m_value.object->end())
|
||||
{
|
||||
JSON_THROW(out_of_range::create(403, detail::concat("key '", string_t(std::forward<KeyType>(key)), "' not found"), this));
|
||||
@@ -29873,7 +29915,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
// operator[] only works for objects
|
||||
if (JSON_HEDLEY_LIKELY(is_object()))
|
||||
{
|
||||
auto result = m_data.m_value.object->emplace(std::forward<KeyType>(key), nullptr);
|
||||
auto result = m_data.m_value.object->emplace(lookup_key(std::forward<KeyType>(key)), nullptr);
|
||||
return set_parent(result.first->second);
|
||||
}
|
||||
|
||||
@@ -29889,7 +29931,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
// const operator[] only works for objects
|
||||
if (JSON_HEDLEY_LIKELY(is_object()))
|
||||
{
|
||||
auto it = m_data.m_value.object->find(std::forward<KeyType>(key));
|
||||
auto it = m_data.m_value.object->find(lookup_key(std::forward<KeyType>(key)));
|
||||
JSON_ASSERT(it != m_data.m_value.object->end());
|
||||
return it->second;
|
||||
}
|
||||
@@ -29899,8 +29941,10 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
|
||||
private:
|
||||
template<typename KeyType>
|
||||
using is_comparable_with_object_key = detail::is_comparable <
|
||||
object_comparator_t, const typename object_t::key_type&, KeyType >;
|
||||
using is_comparable_with_object_key = std::integral_constant < bool,
|
||||
detail::is_comparable <
|
||||
object_comparator_t, const typename object_t::key_type&, KeyType >::value
|
||||
|| detail::is_string_view_convertible_key_type<basic_json_t, KeyType>::value >;
|
||||
|
||||
template<typename ValueType>
|
||||
using value_return_type = std::conditional <
|
||||
@@ -30287,7 +30331,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
JSON_THROW(type_error::create(307, detail::concat("cannot use erase() with ", type_name()), this));
|
||||
}
|
||||
|
||||
const auto it = m_data.m_value.object->find(std::forward<KeyType>(key));
|
||||
const auto it = m_data.m_value.object->find(lookup_key(std::forward<KeyType>(key)));
|
||||
if (it != m_data.m_value.object->end())
|
||||
{
|
||||
m_data.m_value.object->erase(it);
|
||||
@@ -30314,7 +30358,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
detail::is_usable_as_basic_json_key_type<basic_json_t, KeyType>::value, int> = 0>
|
||||
size_type erase(KeyType && key)
|
||||
{
|
||||
return erase_internal(std::forward<KeyType>(key));
|
||||
return erase_internal(lookup_key(std::forward<KeyType>(key)));
|
||||
}
|
||||
|
||||
/// @brief remove element from a JSON array given an index
|
||||
@@ -30394,7 +30438,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
|
||||
if (is_object())
|
||||
{
|
||||
result.m_it.object_iterator = m_data.m_value.object->find(std::forward<KeyType>(key));
|
||||
result.m_it.object_iterator = m_data.m_value.object->find(lookup_key(std::forward<KeyType>(key)));
|
||||
}
|
||||
|
||||
return result;
|
||||
@@ -30410,7 +30454,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
|
||||
if (is_object())
|
||||
{
|
||||
result.m_it.object_iterator = m_data.m_value.object->find(std::forward<KeyType>(key));
|
||||
result.m_it.object_iterator = m_data.m_value.object->find(lookup_key(std::forward<KeyType>(key)));
|
||||
}
|
||||
|
||||
return result;
|
||||
@@ -30433,7 +30477,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
size_type count(KeyType && key) const
|
||||
{
|
||||
// return 0 for all nonobject types
|
||||
return is_object() ? m_data.m_value.object->count(std::forward<KeyType>(key)) : 0;
|
||||
return is_object() ? m_data.m_value.object->count(lookup_key(std::forward<KeyType>(key))) : 0;
|
||||
}
|
||||
|
||||
/// @brief check the existence of an element in a JSON object
|
||||
@@ -30451,7 +30495,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
JSON_HEDLEY_WARN_UNUSED_RESULT
|
||||
bool contains(KeyType && key) const
|
||||
{
|
||||
return is_object() && m_data.m_value.object->find(std::forward<KeyType>(key)) != m_data.m_value.object->end();
|
||||
return is_object() && m_data.m_value.object->find(lookup_key(std::forward<KeyType>(key))) != m_data.m_value.object->end();
|
||||
}
|
||||
|
||||
/// @brief check the existence of an element in a JSON object given a JSON pointer
|
||||
@@ -32017,7 +32061,10 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
/// @sa https://json.nlohmann.me/api/basic_json/operator_gtgt/
|
||||
friend std::istream& operator>>(std::istream& i, basic_json& j)
|
||||
{
|
||||
parser(detail::input_adapter(i)).parse(false, j);
|
||||
// parse into a temporary so that j is left unchanged if parsing fails
|
||||
basic_json result;
|
||||
parser(detail::input_adapter(i)).parse(false, result);
|
||||
j = std::move(result);
|
||||
return i;
|
||||
}
|
||||
#endif // JSON_NO_IO
|
||||
|
||||
@@ -352,6 +352,41 @@ TEST_CASE("alternative string type")
|
||||
CHECK(j2.flatten().unflatten() == j2);
|
||||
}
|
||||
|
||||
SECTION("contains(json_pointer)")
|
||||
{
|
||||
// contains(json_pointer) must compile and work with a string_t that has
|
||||
// no c_str() and no comparison with const char* (see #5666)
|
||||
auto j = alt_json::parse(R"({"foo": ["bar", "baz"]})");
|
||||
|
||||
// present: object key and array indices
|
||||
CHECK(j.contains(alt_json::json_pointer("/foo")));
|
||||
CHECK(j.contains(alt_json::json_pointer("/foo/0")));
|
||||
CHECK(j.contains(alt_json::json_pointer("/foo/1")));
|
||||
|
||||
// missing: absent object key and out-of-range array index
|
||||
CHECK_FALSE(j.contains(alt_json::json_pointer("/bar")));
|
||||
CHECK_FALSE(j.contains(alt_json::json_pointer("/foo/2")));
|
||||
|
||||
// "-" always fails the range check
|
||||
CHECK_FALSE(j.contains(alt_json::json_pointer("/foo/-")));
|
||||
|
||||
// an array index must not have a leading zero
|
||||
CHECK_FALSE(j.contains(alt_json::json_pointer("/foo/01")));
|
||||
|
||||
// a reference token that is not a number
|
||||
CHECK_FALSE(j.contains(alt_json::json_pointer("/foo/bar")));
|
||||
}
|
||||
|
||||
SECTION("operator/(std::size_t)")
|
||||
{
|
||||
// json_pointer::operator/=(std::size_t) must compile without string_t
|
||||
// being constructible from std::string (see #5666)
|
||||
auto j = alt_json::parse(R"({"foo": ["bar", "baz"]})");
|
||||
|
||||
CHECK(j.at(alt_json::json_pointer("/foo") / std::size_t(0)) == j["foo"][0]);
|
||||
CHECK(j.at(alt_json::json_pointer("/foo") / std::size_t(1)) == j["foo"][1]);
|
||||
}
|
||||
|
||||
SECTION("patch")
|
||||
{
|
||||
alt_json const patch1 = alt_json::parse(R"([{ "op": "add", "path": "/a/b", "value": [ "foo", "bar" ] }])");
|
||||
|
||||
@@ -19,6 +19,7 @@ using nlohmann::json;
|
||||
|
||||
#include <map>
|
||||
#include <unordered_map>
|
||||
#include <sstream>
|
||||
|
||||
TEST_CASE("Better diagnostics")
|
||||
{
|
||||
@@ -492,6 +493,21 @@ TEST_CASE("Regression tests for extended diagnostics")
|
||||
CHECK(copy == j);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("Regression test for issue #5652 - operator>> leaves a partial value in its target on a parse error")
|
||||
{
|
||||
json j = "old value";
|
||||
std::istringstream is("[1, x");
|
||||
CHECK_THROWS_WITH_AS(is >> j, "[json.exception.parse_error.101] parse error at line 1, column 5: syntax error while parsing value - invalid literal; last read: '1, x'", json::parse_error);
|
||||
|
||||
// j must be left unchanged, as json::parse() guarantees for its result
|
||||
CHECK(j == "old value");
|
||||
|
||||
// copying j must not trigger assert_invariant(): a failed parse must
|
||||
// not leave array/object elements without a parent pointer
|
||||
json const copy = j; // NOLINT(performance-unnecessary-copy-initialization)
|
||||
CHECK(copy == j);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("Better diagnostics past the descent bound of update() and merge_patch()")
|
||||
|
||||
@@ -1973,4 +1973,115 @@ TEST_CASE("operator[] with user-defined std::string_view-convertible types")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("keys convertible to std::string_view work with all lookup functions (regression test for #5663)")
|
||||
{
|
||||
// a key type convertible only to std::string_view: the case #4958 added
|
||||
// support for, but only the non-const operator[] compiled with it
|
||||
struct ViewKey
|
||||
{
|
||||
operator std::string_view() const
|
||||
{
|
||||
return "a";
|
||||
}
|
||||
};
|
||||
|
||||
// a key type convertible to both std::string and std::string_view: with
|
||||
// 3.12.0, such a key worked with at, the const operator[], find, count and
|
||||
// contains via the conversion to std::string; #4958 made the KeyType&&
|
||||
// templates win overload resolution for it instead, and those then failed
|
||||
struct DualKey
|
||||
{
|
||||
operator std::string() const
|
||||
{
|
||||
return "a";
|
||||
}
|
||||
operator std::string_view() const
|
||||
{
|
||||
return "a";
|
||||
}
|
||||
};
|
||||
|
||||
SECTION("nlohmann::json")
|
||||
{
|
||||
using json = nlohmann::json;
|
||||
|
||||
SECTION("ViewKey")
|
||||
{
|
||||
json j = {{"a", 1}};
|
||||
const json& cj = j;
|
||||
|
||||
CHECK(j[ViewKey{}] == 1);
|
||||
CHECK(cj[ViewKey{}] == 1);
|
||||
CHECK(j.at(ViewKey{}) == 1);
|
||||
CHECK(cj.at(ViewKey{}) == 1);
|
||||
CHECK(j.find(ViewKey{}) != j.end());
|
||||
CHECK(cj.find(ViewKey{}) != cj.end());
|
||||
CHECK(j.count(ViewKey{}) == 1);
|
||||
CHECK(j.contains(ViewKey{}));
|
||||
CHECK(j.value(ViewKey{}, 0) == 1);
|
||||
CHECK(j.erase(ViewKey{}) == 1);
|
||||
CHECK(!j.contains("a"));
|
||||
}
|
||||
|
||||
SECTION("DualKey")
|
||||
{
|
||||
json j = {{"a", 1}};
|
||||
const json& cj = j;
|
||||
|
||||
CHECK(j[DualKey{}] == 1);
|
||||
CHECK(cj[DualKey{}] == 1);
|
||||
CHECK(j.at(DualKey{}) == 1);
|
||||
CHECK(cj.at(DualKey{}) == 1);
|
||||
CHECK(j.find(DualKey{}) != j.end());
|
||||
CHECK(cj.find(DualKey{}) != cj.end());
|
||||
CHECK(j.count(DualKey{}) == 1);
|
||||
CHECK(j.contains(DualKey{}));
|
||||
CHECK(j.value(DualKey{}, 0) == 1);
|
||||
CHECK(j.erase(DualKey{}) == 1);
|
||||
CHECK(!j.contains("a"));
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("nlohmann::ordered_json")
|
||||
{
|
||||
using ordered_json = nlohmann::ordered_json;
|
||||
|
||||
SECTION("ViewKey")
|
||||
{
|
||||
ordered_json j = {{"a", 1}};
|
||||
const ordered_json& cj = j;
|
||||
|
||||
CHECK(j[ViewKey{}] == 1);
|
||||
CHECK(cj[ViewKey{}] == 1);
|
||||
CHECK(j.at(ViewKey{}) == 1);
|
||||
CHECK(cj.at(ViewKey{}) == 1);
|
||||
CHECK(j.find(ViewKey{}) != j.end());
|
||||
CHECK(cj.find(ViewKey{}) != cj.end());
|
||||
CHECK(j.count(ViewKey{}) == 1);
|
||||
CHECK(j.contains(ViewKey{}));
|
||||
CHECK(j.value(ViewKey{}, 0) == 1);
|
||||
CHECK(j.erase(ViewKey{}) == 1);
|
||||
CHECK(!j.contains("a"));
|
||||
}
|
||||
|
||||
SECTION("DualKey")
|
||||
{
|
||||
ordered_json j = {{"a", 1}};
|
||||
const ordered_json& cj = j;
|
||||
|
||||
CHECK(j[DualKey{}] == 1);
|
||||
CHECK(cj[DualKey{}] == 1);
|
||||
CHECK(j.at(DualKey{}) == 1);
|
||||
CHECK(cj.at(DualKey{}) == 1);
|
||||
CHECK(j.find(DualKey{}) != j.end());
|
||||
CHECK(cj.find(DualKey{}) != cj.end());
|
||||
CHECK(j.count(DualKey{}) == 1);
|
||||
CHECK(j.contains(DualKey{}));
|
||||
CHECK(j.value(DualKey{}, 0) == 1);
|
||||
CHECK(j.erase(DualKey{}) == 1);
|
||||
CHECK(!j.contains("a"));
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user