mirror of
https://github.com/nlohmann/json.git
synced 2026-10-01 12:10:32 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
954bdad63b | ||
|
|
2dc43e8bf8 | ||
|
|
e0eb3e7490 | ||
|
|
3ae4d7c45e |
@@ -224,7 +224,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 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.
|
||||
3. Added in version 3.11.0.
|
||||
4. Added in version 2.0.0.
|
||||
|
||||
@@ -272,6 +272,15 @@ basic_json(basic_json&& other) noexcept;
|
||||
When used without parentheses around an empty initializer list, `basic_json()` is called instead of this
|
||||
function, yielding the JSON `#!json null` value.
|
||||
|
||||
- Overload 4:
|
||||
|
||||
!!! info "Implicit conversion"
|
||||
|
||||
The conversion is implicit unless [`JSON_USE_IMPLICIT_CONVERSIONS`](../macros/json_use_implicit_conversions.md)
|
||||
is defined to `0` and `BasicJsonType::string_t` differs from `string_t`. In that case, the constructor is
|
||||
`explicit`, so a JSON value with a different string type is no longer silently converted, for example when it is
|
||||
passed to a function taking `#!cpp const json&`. Write `#!cpp json(other)` or `#!cpp other.get<json>()` instead.
|
||||
|
||||
- Overload 7:
|
||||
|
||||
!!! info "Preconditions"
|
||||
@@ -420,7 +429,8 @@ basic_json(basic_json&& other) noexcept;
|
||||
1. Since version 1.0.0.
|
||||
2. Since version 1.0.0.
|
||||
3. Since version 2.1.0.
|
||||
4. Since version 3.2.0.
|
||||
4. Since version 3.2.0. Explicit for different string types if `JSON_USE_IMPLICIT_CONVERSIONS` is `0` since
|
||||
version 3.13.0.
|
||||
5. Since version 1.0.0.
|
||||
6. Since version 1.0.0.
|
||||
7. Since version 1.0.0. Fixed in version 3.13.0 to also check the iterator range for binary values; before, a range
|
||||
|
||||
@@ -119,9 +119,7 @@ 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. 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.
|
||||
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.
|
||||
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,8 +84,6 @@ 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. 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.
|
||||
2. Added in version 1.0.0. Changed parameter `key` type to `KeyType&&` in version 3.11.0.
|
||||
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,7 +213,5 @@ 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. 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.
|
||||
4. Added in version 3.11.0.
|
||||
5. Added in version 1.0.0.
|
||||
|
||||
@@ -88,8 +88,6 @@ 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. 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.
|
||||
2. Added in version 1.0.0. Changed to support comparable types in version 3.11.0.
|
||||
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,9 +195,7 @@ 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. 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.
|
||||
2. Added in version 3.11.0. Made `ValueType` the first template parameter in version 3.11.2.
|
||||
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).
|
||||
|
||||
@@ -5,7 +5,9 @@
|
||||
```
|
||||
|
||||
When defined to `0`, implicit conversions are switched off. By default, implicit conversions are switched on. The
|
||||
value directly affects [`operator ValueType`](../basic_json/operator_ValueType.md).
|
||||
value directly affects [`operator ValueType`](../basic_json/operator_ValueType.md) and the
|
||||
[converting constructor](../basic_json/basic_json.md) from a `basic_json` specialization with a different string
|
||||
type (overload 4).
|
||||
|
||||
## Default definition
|
||||
|
||||
@@ -57,6 +59,25 @@ By default, implicit conversions are enabled.
|
||||
auto s = j.get<std::string>();
|
||||
```
|
||||
|
||||
??? example "Conversion between `basic_json` specializations"
|
||||
|
||||
A `basic_json` specialization with a different string type is also no longer converted implicitly when
|
||||
`JSON_USE_IMPLICIT_CONVERSIONS` is defined to `0`:
|
||||
|
||||
```cpp
|
||||
using wjson = nlohmann::basic_json<std::map, std::vector, std::wstring>;
|
||||
|
||||
void load(const nlohmann::json& j);
|
||||
|
||||
wjson wj = /* ... */;
|
||||
load(wj); // error: no implicit conversion
|
||||
load(nlohmann::json(wj)); // OK: explicit conversion
|
||||
load(wj.get<nlohmann::json>()); // OK: explicit conversion
|
||||
```
|
||||
|
||||
Specializations that share the same string type, such as `json` and `ordered_json`, remain implicitly
|
||||
convertible.
|
||||
|
||||
## See also
|
||||
|
||||
- [**operator ValueType**](../basic_json/operator_ValueType.md) - get a value (implicit)
|
||||
@@ -66,3 +87,4 @@ By default, implicit conversions are enabled.
|
||||
## Version history
|
||||
|
||||
- Added in version 3.9.0.
|
||||
- Also affects the conversion between `basic_json` specializations with different string types since version 3.13.0.
|
||||
|
||||
@@ -291,7 +291,9 @@ void to_json(BasicJsonType& j, const std::optional<T>& opt) noexcept(std::is_not
|
||||
{
|
||||
if (opt.has_value())
|
||||
{
|
||||
j = *opt;
|
||||
// explicit construction, as the conversion from a basic_json with a different
|
||||
// string type is explicit if JSON_USE_IMPLICIT_CONVERSIONS is 0 (#2649)
|
||||
j = BasicJsonType(*opt);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -748,30 +748,6 @@ 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
|
||||
@@ -785,7 +761,9 @@ 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)
|
||||
|| is_string_view_convertible_key_type<BasicJsonType, KeyTypeCVRef>::value
|
||||
#ifdef JSON_HAS_CPP_17
|
||||
|| std::is_convertible<KeyType, std::string_view>::value
|
||||
#endif
|
||||
, std::true_type,
|
||||
std::false_type >::type;
|
||||
|
||||
|
||||
+46
-35
@@ -807,24 +807,6 @@ 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
|
||||
@@ -1624,12 +1606,42 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
assert_invariant();
|
||||
}
|
||||
|
||||
private:
|
||||
/// whether a basic_json specialization can be converted implicitly into this one;
|
||||
/// with JSON_USE_IMPLICIT_CONVERSIONS set to 0, this is only the case if both share
|
||||
/// the same string type (see https://github.com/nlohmann/json/issues/2649)
|
||||
template<typename BasicJsonType>
|
||||
using is_implicitly_convertible_basic_json = std::integral_constant < bool,
|
||||
(JSON_USE_IMPLICIT_CONVERSIONS != 0)
|
||||
|| std::is_same<typename BasicJsonType::string_t, string_t>::value >;
|
||||
|
||||
/// tag to select the constructor that performs the conversion from another basic_json specialization
|
||||
struct convert_basic_json_tag {};
|
||||
|
||||
public:
|
||||
/// @brief create a JSON value from an existing one
|
||||
/// @sa https://json.nlohmann.me/api/basic_json/basic_json/
|
||||
template < typename BasicJsonType,
|
||||
detail::enable_if_t <
|
||||
detail::is_basic_json<BasicJsonType>::value&& !std::is_same<basic_json, BasicJsonType>::value, int > = 0 >
|
||||
detail::is_basic_json<BasicJsonType>::value&& !std::is_same<basic_json, BasicJsonType>::value
|
||||
&& is_implicitly_convertible_basic_json<BasicJsonType>::value, int > = 0 >
|
||||
basic_json(const BasicJsonType& val)
|
||||
: basic_json(val, convert_basic_json_tag{})
|
||||
{}
|
||||
|
||||
/// @brief create a JSON value from an existing one
|
||||
/// @sa https://json.nlohmann.me/api/basic_json/basic_json/
|
||||
template < typename BasicJsonType,
|
||||
detail::enable_if_t <
|
||||
detail::is_basic_json<BasicJsonType>::value&& !std::is_same<basic_json, BasicJsonType>::value
|
||||
&& !is_implicitly_convertible_basic_json<BasicJsonType>::value, int > = 0 >
|
||||
explicit basic_json(const BasicJsonType& val)
|
||||
: basic_json(val, convert_basic_json_tag{})
|
||||
{}
|
||||
|
||||
private:
|
||||
template<typename BasicJsonType>
|
||||
basic_json(const BasicJsonType& val, convert_basic_json_tag /*unused*/)
|
||||
#if JSON_DIAGNOSTIC_POSITIONS
|
||||
: start_position(val.start_pos()),
|
||||
end_position(val.end_pos())
|
||||
@@ -1685,6 +1697,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
assert_invariant();
|
||||
}
|
||||
|
||||
public:
|
||||
/// @brief create a container (array or object) from an initializer list
|
||||
/// @sa https://json.nlohmann.me/api/basic_json/basic_json/
|
||||
basic_json(initializer_list_t init,
|
||||
@@ -2451,7 +2464,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
int > = 0 >
|
||||
BasicJsonType get_impl(detail::priority_tag<2> /*unused*/) const
|
||||
{
|
||||
return *this;
|
||||
return BasicJsonType(*this);
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -2590,7 +2603,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
int> = 0>
|
||||
ValueType & get_to(ValueType& v) const
|
||||
{
|
||||
v = *this;
|
||||
v = ValueType(*this);
|
||||
return v;
|
||||
}
|
||||
|
||||
@@ -2785,7 +2798,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(lookup_key(std::forward<KeyType>(key)));
|
||||
auto it = m_data.m_value.object->find(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));
|
||||
@@ -2823,7 +2836,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(lookup_key(std::forward<KeyType>(key)));
|
||||
auto it = m_data.m_value.object->find(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));
|
||||
@@ -2966,7 +2979,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(lookup_key(std::forward<KeyType>(key)), nullptr);
|
||||
auto result = m_data.m_value.object->emplace(std::forward<KeyType>(key), nullptr);
|
||||
return set_parent(result.first->second);
|
||||
}
|
||||
|
||||
@@ -2982,7 +2995,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(lookup_key(std::forward<KeyType>(key)));
|
||||
auto it = m_data.m_value.object->find(std::forward<KeyType>(key));
|
||||
JSON_ASSERT(it != m_data.m_value.object->end());
|
||||
return it->second;
|
||||
}
|
||||
@@ -2992,10 +3005,8 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
|
||||
private:
|
||||
template<typename 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 >;
|
||||
using is_comparable_with_object_key = detail::is_comparable <
|
||||
object_comparator_t, const typename object_t::key_type&, KeyType >;
|
||||
|
||||
template<typename ValueType>
|
||||
using value_return_type = std::conditional <
|
||||
@@ -3382,7 +3393,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(lookup_key(std::forward<KeyType>(key)));
|
||||
const auto it = m_data.m_value.object->find(std::forward<KeyType>(key));
|
||||
if (it != m_data.m_value.object->end())
|
||||
{
|
||||
m_data.m_value.object->erase(it);
|
||||
@@ -3409,7 +3420,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(lookup_key(std::forward<KeyType>(key)));
|
||||
return erase_internal(std::forward<KeyType>(key));
|
||||
}
|
||||
|
||||
/// @brief remove element from a JSON array given an index
|
||||
@@ -3489,7 +3500,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(lookup_key(std::forward<KeyType>(key)));
|
||||
result.m_it.object_iterator = m_data.m_value.object->find(std::forward<KeyType>(key));
|
||||
}
|
||||
|
||||
return result;
|
||||
@@ -3505,7 +3516,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(lookup_key(std::forward<KeyType>(key)));
|
||||
result.m_it.object_iterator = m_data.m_value.object->find(std::forward<KeyType>(key));
|
||||
}
|
||||
|
||||
return result;
|
||||
@@ -3528,7 +3539,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(lookup_key(std::forward<KeyType>(key))) : 0;
|
||||
return is_object() ? m_data.m_value.object->count(std::forward<KeyType>(key)) : 0;
|
||||
}
|
||||
|
||||
/// @brief check the existence of an element in a JSON object
|
||||
@@ -3546,7 +3557,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(lookup_key(std::forward<KeyType>(key))) != m_data.m_value.object->end();
|
||||
return is_object() && m_data.m_value.object->find(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
|
||||
|
||||
@@ -4756,30 +4756,6 @@ 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
|
||||
@@ -4793,7 +4769,9 @@ 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)
|
||||
|| is_string_view_convertible_key_type<BasicJsonType, KeyTypeCVRef>::value
|
||||
#ifdef JSON_HAS_CPP_17
|
||||
|| std::is_convertible<KeyType, std::string_view>::value
|
||||
#endif
|
||||
, std::true_type,
|
||||
std::false_type >::type;
|
||||
|
||||
@@ -6844,7 +6822,9 @@ void to_json(BasicJsonType& j, const std::optional<T>& opt) noexcept(std::is_not
|
||||
{
|
||||
if (opt.has_value())
|
||||
{
|
||||
j = *opt;
|
||||
// explicit construction, as the conversion from a basic_json with a different
|
||||
// string type is explicit if JSON_USE_IMPLICIT_CONVERSIONS is 0 (#2649)
|
||||
j = BasicJsonType(*opt);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -27756,24 +27736,6 @@ 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
|
||||
@@ -28573,12 +28535,42 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
assert_invariant();
|
||||
}
|
||||
|
||||
private:
|
||||
/// whether a basic_json specialization can be converted implicitly into this one;
|
||||
/// with JSON_USE_IMPLICIT_CONVERSIONS set to 0, this is only the case if both share
|
||||
/// the same string type (see https://github.com/nlohmann/json/issues/2649)
|
||||
template<typename BasicJsonType>
|
||||
using is_implicitly_convertible_basic_json = std::integral_constant < bool,
|
||||
(JSON_USE_IMPLICIT_CONVERSIONS != 0)
|
||||
|| std::is_same<typename BasicJsonType::string_t, string_t>::value >;
|
||||
|
||||
/// tag to select the constructor that performs the conversion from another basic_json specialization
|
||||
struct convert_basic_json_tag {};
|
||||
|
||||
public:
|
||||
/// @brief create a JSON value from an existing one
|
||||
/// @sa https://json.nlohmann.me/api/basic_json/basic_json/
|
||||
template < typename BasicJsonType,
|
||||
detail::enable_if_t <
|
||||
detail::is_basic_json<BasicJsonType>::value&& !std::is_same<basic_json, BasicJsonType>::value, int > = 0 >
|
||||
detail::is_basic_json<BasicJsonType>::value&& !std::is_same<basic_json, BasicJsonType>::value
|
||||
&& is_implicitly_convertible_basic_json<BasicJsonType>::value, int > = 0 >
|
||||
basic_json(const BasicJsonType& val)
|
||||
: basic_json(val, convert_basic_json_tag{})
|
||||
{}
|
||||
|
||||
/// @brief create a JSON value from an existing one
|
||||
/// @sa https://json.nlohmann.me/api/basic_json/basic_json/
|
||||
template < typename BasicJsonType,
|
||||
detail::enable_if_t <
|
||||
detail::is_basic_json<BasicJsonType>::value&& !std::is_same<basic_json, BasicJsonType>::value
|
||||
&& !is_implicitly_convertible_basic_json<BasicJsonType>::value, int > = 0 >
|
||||
explicit basic_json(const BasicJsonType& val)
|
||||
: basic_json(val, convert_basic_json_tag{})
|
||||
{}
|
||||
|
||||
private:
|
||||
template<typename BasicJsonType>
|
||||
basic_json(const BasicJsonType& val, convert_basic_json_tag /*unused*/)
|
||||
#if JSON_DIAGNOSTIC_POSITIONS
|
||||
: start_position(val.start_pos()),
|
||||
end_position(val.end_pos())
|
||||
@@ -28634,6 +28626,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
assert_invariant();
|
||||
}
|
||||
|
||||
public:
|
||||
/// @brief create a container (array or object) from an initializer list
|
||||
/// @sa https://json.nlohmann.me/api/basic_json/basic_json/
|
||||
basic_json(initializer_list_t init,
|
||||
@@ -29400,7 +29393,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
int > = 0 >
|
||||
BasicJsonType get_impl(detail::priority_tag<2> /*unused*/) const
|
||||
{
|
||||
return *this;
|
||||
return BasicJsonType(*this);
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -29539,7 +29532,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
int> = 0>
|
||||
ValueType & get_to(ValueType& v) const
|
||||
{
|
||||
v = *this;
|
||||
v = ValueType(*this);
|
||||
return v;
|
||||
}
|
||||
|
||||
@@ -29734,7 +29727,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(lookup_key(std::forward<KeyType>(key)));
|
||||
auto it = m_data.m_value.object->find(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));
|
||||
@@ -29772,7 +29765,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(lookup_key(std::forward<KeyType>(key)));
|
||||
auto it = m_data.m_value.object->find(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));
|
||||
@@ -29915,7 +29908,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(lookup_key(std::forward<KeyType>(key)), nullptr);
|
||||
auto result = m_data.m_value.object->emplace(std::forward<KeyType>(key), nullptr);
|
||||
return set_parent(result.first->second);
|
||||
}
|
||||
|
||||
@@ -29931,7 +29924,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(lookup_key(std::forward<KeyType>(key)));
|
||||
auto it = m_data.m_value.object->find(std::forward<KeyType>(key));
|
||||
JSON_ASSERT(it != m_data.m_value.object->end());
|
||||
return it->second;
|
||||
}
|
||||
@@ -29941,10 +29934,8 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
|
||||
private:
|
||||
template<typename 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 >;
|
||||
using is_comparable_with_object_key = detail::is_comparable <
|
||||
object_comparator_t, const typename object_t::key_type&, KeyType >;
|
||||
|
||||
template<typename ValueType>
|
||||
using value_return_type = std::conditional <
|
||||
@@ -30331,7 +30322,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(lookup_key(std::forward<KeyType>(key)));
|
||||
const auto it = m_data.m_value.object->find(std::forward<KeyType>(key));
|
||||
if (it != m_data.m_value.object->end())
|
||||
{
|
||||
m_data.m_value.object->erase(it);
|
||||
@@ -30358,7 +30349,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(lookup_key(std::forward<KeyType>(key)));
|
||||
return erase_internal(std::forward<KeyType>(key));
|
||||
}
|
||||
|
||||
/// @brief remove element from a JSON array given an index
|
||||
@@ -30438,7 +30429,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(lookup_key(std::forward<KeyType>(key)));
|
||||
result.m_it.object_iterator = m_data.m_value.object->find(std::forward<KeyType>(key));
|
||||
}
|
||||
|
||||
return result;
|
||||
@@ -30454,7 +30445,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(lookup_key(std::forward<KeyType>(key)));
|
||||
result.m_it.object_iterator = m_data.m_value.object->find(std::forward<KeyType>(key));
|
||||
}
|
||||
|
||||
return result;
|
||||
@@ -30477,7 +30468,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(lookup_key(std::forward<KeyType>(key))) : 0;
|
||||
return is_object() ? m_data.m_value.object->count(std::forward<KeyType>(key)) : 0;
|
||||
}
|
||||
|
||||
/// @brief check the existence of an element in a JSON object
|
||||
@@ -30495,7 +30486,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(lookup_key(std::forward<KeyType>(key))) != m_data.m_value.object->end();
|
||||
return is_object() && m_data.m_value.object->find(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
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
@@ -419,6 +420,41 @@ TEST_CASE("alternative string type")
|
||||
CHECK(j2.dump() == R"({"/foo/0":"bar","/foo/1":"baz"})");
|
||||
}
|
||||
|
||||
SECTION("conversion between basic_json specializations (#2649)")
|
||||
{
|
||||
// explicit conversions are always possible
|
||||
CHECK(std::is_constructible<nlohmann::json, alt_json>::value);
|
||||
CHECK(std::is_constructible<alt_json, nlohmann::json>::value);
|
||||
CHECK(std::is_constructible<nlohmann::json, nlohmann::ordered_json>::value);
|
||||
CHECK(std::is_constructible<nlohmann::ordered_json, nlohmann::json>::value);
|
||||
|
||||
// specializations with the same string type are implicitly convertible
|
||||
CHECK(std::is_convertible<nlohmann::ordered_json, nlohmann::json>::value);
|
||||
CHECK(std::is_convertible<nlohmann::json, nlohmann::ordered_json>::value);
|
||||
|
||||
// specializations with different string types are only implicitly convertible
|
||||
// if implicit conversions are enabled
|
||||
#if JSON_USE_IMPLICIT_CONVERSIONS
|
||||
CHECK(std::is_convertible<alt_json, nlohmann::json>::value);
|
||||
CHECK(std::is_convertible<nlohmann::json, alt_json>::value);
|
||||
#else
|
||||
CHECK_FALSE(std::is_convertible<alt_json, nlohmann::json>::value);
|
||||
CHECK_FALSE(std::is_convertible<nlohmann::json, alt_json>::value);
|
||||
#endif
|
||||
|
||||
// get<BasicJsonType>() works in either case
|
||||
const nlohmann::json j = {{"foo", 1}, {"bar", true}};
|
||||
CHECK(j.get<nlohmann::ordered_json>() == nlohmann::ordered_json(j));
|
||||
// (only a number is converted here, as objects and strings are affected by #3425)
|
||||
CHECK(nlohmann::json(42).get<alt_json>() == 42);
|
||||
CHECK(alt_json(nlohmann::json(42)) == 42);
|
||||
|
||||
// get_to() also works in either case
|
||||
alt_json a;
|
||||
nlohmann::json(42).get_to(a);
|
||||
CHECK(a == 42);
|
||||
}
|
||||
|
||||
SECTION("strict enum")
|
||||
{
|
||||
// regression test for #5667: NLOHMANN_JSON_SERIALIZE_ENUM_STRICT's from_json
|
||||
|
||||
@@ -1973,115 +1973,4 @@ 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