🔀 merge develop branch

parent 4703dd57
...@@ -3775,6 +3775,33 @@ struct is_constructible_tuple : std::false_type {}; ...@@ -3775,6 +3775,33 @@ struct is_constructible_tuple : std::false_type {};
template<typename T1, typename... Args> template<typename T1, typename... Args>
struct is_constructible_tuple<T1, std::tuple<Args...>> : conjunction<is_constructible<T1, Args>...> {}; struct is_constructible_tuple<T1, std::tuple<Args...>> : conjunction<is_constructible<T1, Args>...> {};
/// type to check if KeyType can be used as object key
template<typename ComparatorType, typename KeyType, typename ObjectKeyType, typename = void>
struct is_key_type_comparable
{
static constexpr bool value = false;
};
template<typename ComparatorType, typename KeyType, typename ObjectKeyType>
struct is_key_type_comparable<ComparatorType, KeyType, ObjectKeyType, void_t<
decltype(ComparatorType()(std::declval<KeyType const&>(), std::declval<ObjectKeyType const&>())),
decltype(ComparatorType()(std::declval<ObjectKeyType const&>(), std::declval<KeyType const&>()))
>>
{
static constexpr bool value = true;
};
template<typename BasicJsonType, typename KeyType>
struct is_usable_as_key_type
{
static constexpr bool value =
is_key_type_comparable<typename BasicJsonType::object_comparator_t, typename BasicJsonType::object_t::key_type, KeyType>::value &&
!std::is_same<KeyType, typename BasicJsonType::iterator>::value &&
!std::is_same<KeyType, typename BasicJsonType::const_iterator>::value;
};
// a naive helper to check if a type is an ordered_map (exploits the fact that // a naive helper to check if a type is an ordered_map (exploits the fact that
// ordered_map inherits capacity() from std::vector) // ordered_map inherits capacity() from std::vector)
template <typename T> template <typename T>
...@@ -17680,10 +17707,12 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec ...@@ -17680,10 +17707,12 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
default: default:
{ {
object = nullptr; // silence warning, see #821 object = nullptr; // silence warning, see #821
// LCOV_EXCL_START
if (JSON_HEDLEY_UNLIKELY(t == value_t::null)) if (JSON_HEDLEY_UNLIKELY(t == value_t::null))
{ {
JSON_THROW(other_error::create(500, "961c151d2e87f2686a955a9be24d316f1362bf21 3.10.4", basic_json())); // LCOV_EXCL_LINE JSON_THROW(other_error::create(500, "961c151d2e87f2686a955a9be24d316f1362bf21 3.10.4", basic_json()));
} }
// LCOV_EXCL_STOP
break; break;
} }
} }
...@@ -19133,48 +19162,42 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec ...@@ -19133,48 +19162,42 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @brief access specified object element with bounds checking /// @brief access specified object element with bounds checking
/// @sa https://json.nlohmann.me/api/basic_json/at/ /// @sa https://json.nlohmann.me/api/basic_json/at/
reference at(const typename object_t::key_type& key) template < class KeyT, typename detail::enable_if_t <
detail::is_usable_as_key_type<basic_json_t, KeyT>::value&& !std::is_same<typename std::decay<KeyT>::type, json_pointer>::value, int > = 0 >
reference at(const KeyT& key)
{ {
// at only works for objects // at only works for objects
if (JSON_HEDLEY_LIKELY(is_object())) if (JSON_HEDLEY_UNLIKELY(!is_object()))
{
JSON_TRY
{
return set_parent(m_value.object->at(key));
}
JSON_CATCH (std::out_of_range&)
{ {
// create better exception explanation JSON_THROW(type_error::create(304, "cannot use at() with " + std::string(type_name()), *this));
JSON_THROW(out_of_range::create(403, "key '" + key + "' not found", *this));
}
} }
else
auto it = m_value.object->find(key);
if (it == m_value.object->end())
{ {
JSON_THROW(type_error::create(304, "cannot use at() with " + std::string(type_name()), *this)); JSON_THROW(out_of_range::create(403, "key '" + std::string(key) + "' not found", *this));
} }
return set_parent(it->second);
} }
/// @brief access specified object element with bounds checking /// @brief access specified object element with bounds checking
/// @sa https://json.nlohmann.me/api/basic_json/at/ /// @sa https://json.nlohmann.me/api/basic_json/at/
const_reference at(const typename object_t::key_type& key) const template < class KeyT, typename detail::enable_if_t <
detail::is_usable_as_key_type<basic_json_t, KeyT>::value&& !std::is_same<typename std::decay<KeyT>::type, json_pointer>::value, int > = 0 >
const_reference at(const KeyT& key) const
{ {
// at only works for objects // at only works for objects
if (JSON_HEDLEY_LIKELY(is_object())) if (JSON_HEDLEY_UNLIKELY(!is_object()))
{
JSON_TRY
{
return m_value.object->at(key);
}
JSON_CATCH (std::out_of_range&)
{ {
// create better exception explanation JSON_THROW(type_error::create(304, "cannot use at() with " + std::string(type_name()), *this));
JSON_THROW(out_of_range::create(403, "key '" + key + "' not found", *this));
}
} }
else
auto it = m_value.object->find(key);
if (it == m_value.object->end())
{ {
JSON_THROW(type_error::create(304, "cannot use at() with " + std::string(type_name()), *this)); JSON_THROW(out_of_range::create(403, "key '" + std::string(key) + "' not found", *this));
} }
return it->second;
} }
/// @brief access specified array element /// @brief access specified array element
...@@ -19238,7 +19261,9 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec ...@@ -19238,7 +19261,9 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @brief access specified object element /// @brief access specified object element
/// @sa https://json.nlohmann.me/api/basic_json/operator%5B%5D/ /// @sa https://json.nlohmann.me/api/basic_json/operator%5B%5D/
reference operator[](const typename object_t::key_type& key) template < class KeyT, typename detail::enable_if_t <
detail::is_usable_as_key_type<basic_json_t, KeyT>::value&& !std::is_same<typename std::decay<KeyT>::type, json_pointer>::value, int > = 0 >
reference operator[](KeyT && key)
{ {
// implicitly convert null value to an empty object // implicitly convert null value to an empty object
if (is_null()) if (is_null())
...@@ -19251,7 +19276,8 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec ...@@ -19251,7 +19276,8 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
// operator[] only works for objects // operator[] only works for objects
if (JSON_HEDLEY_LIKELY(is_object())) if (JSON_HEDLEY_LIKELY(is_object()))
{ {
return set_parent(m_value.object->operator[](key)); auto result = m_value.object->emplace(std::forward<KeyT>(key), nullptr);
return set_parent(result.first->second);
} }
JSON_THROW(type_error::create(305, "cannot use operator[] with a string argument with " + std::string(type_name()), *this)); JSON_THROW(type_error::create(305, "cannot use operator[] with a string argument with " + std::string(type_name()), *this));
...@@ -19259,13 +19285,16 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec ...@@ -19259,13 +19285,16 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @brief access specified object element /// @brief access specified object element
/// @sa https://json.nlohmann.me/api/basic_json/operator%5B%5D/ /// @sa https://json.nlohmann.me/api/basic_json/operator%5B%5D/
const_reference operator[](const typename object_t::key_type& key) const template < class KeyT, typename detail::enable_if_t <
detail::is_usable_as_key_type<basic_json_t, KeyT>::value&& !std::is_same<typename std::decay<KeyT>::type, json_pointer>::value, int > = 0 >
const_reference operator[](KeyT && key) const
{ {
// const operator[] only works for objects // operator[] only works for objects
if (JSON_HEDLEY_LIKELY(is_object())) if (JSON_HEDLEY_LIKELY(is_object()))
{ {
JSON_ASSERT(m_value.object->find(key) != m_value.object->end()); auto it = m_value.object->find(std::forward<KeyT>(key));
return m_value.object->find(key)->second; JSON_ASSERT(it != m_value.object->end());
return it->second;
} }
JSON_THROW(type_error::create(305, "cannot use operator[] with a string argument with " + std::string(type_name()), *this)); JSON_THROW(type_error::create(305, "cannot use operator[] with a string argument with " + std::string(type_name()), *this));
...@@ -19294,8 +19323,36 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec ...@@ -19294,8 +19323,36 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
JSON_THROW(type_error::create(305, "cannot use operator[] with a string argument with " + std::string(type_name()), *this)); JSON_THROW(type_error::create(305, "cannot use operator[] with a string argument with " + std::string(type_name()), *this));
} }
/// @brief access specified object element /*!
/// @sa https://json.nlohmann.me/api/basic_json/operator%5B%5D/ @brief read-only access specified object element
Returns a const reference to the element at with specified key @a key. No
bounds checking is performed.
@warning If the element with key @a key does not exist, the behavior is
undefined.
@param[in] key key of the element to access
@return const reference to the element at key @a key
@pre The element with key @a key must exist. **This precondition is
enforced with an assertion.**
@throw type_error.305 if the JSON value is not an object; in that case,
using the [] operator with a key makes no sense.
@complexity Logarithmic in the size of the container.
@liveexample{The example below shows how object elements can be read using
the `[]` operator.,operatorarray__key_type_const}
@sa see @ref at(const typename object_t::key_type&) for access by reference
with range checking
@sa see @ref value() for access by value with a default value
@since version 1.1.0
*/
template<typename T> template<typename T>
JSON_HEDLEY_NON_NULL(2) JSON_HEDLEY_NON_NULL(2)
const_reference operator[](T* key) const const_reference operator[](T* key) const
...@@ -19313,10 +19370,10 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec ...@@ -19313,10 +19370,10 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @brief access specified object element with default value /// @brief access specified object element with default value
/// @sa https://json.nlohmann.me/api/basic_json/value/ /// @sa https://json.nlohmann.me/api/basic_json/value/
/// using std::is_convertible in a std::enable_if will fail when using explicit conversions /// using std::is_convertible in a std::enable_if will fail when using explicit conversions
template < class ValueType, typename std::enable_if < template < class KeyType, class ValueType, typename detail::enable_if_t <
detail::is_getable<basic_json_t, ValueType>::value detail::is_getable<basic_json_t, ValueType>::value
&& !std::is_same<value_t, ValueType>::value, int >::type = 0 > && !std::is_same<value_t, ValueType>::value&& detail::is_usable_as_key_type<basic_json_t, KeyType>::value, int > = 0 >
ValueType value(const typename object_t::key_type& key, const ValueType& default_value) const typename std::decay<ValueType>::type value(const KeyType& key, ValueType && default_value) const
{ {
// at only works for objects // at only works for objects
if (JSON_HEDLEY_LIKELY(is_object())) if (JSON_HEDLEY_LIKELY(is_object()))
...@@ -19325,10 +19382,10 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec ...@@ -19325,10 +19382,10 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
const auto it = find(key); const auto it = find(key);
if (it != end()) if (it != end())
{ {
return it->template get<ValueType>(); return it->template get<typename std::decay<ValueType>::type>();
} }
return default_value; return std::forward<ValueType>(default_value);
} }
JSON_THROW(type_error::create(306, "cannot use value() with " + std::string(type_name()), *this)); JSON_THROW(type_error::create(306, "cannot use value() with " + std::string(type_name()), *this));
...@@ -19337,7 +19394,9 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec ...@@ -19337,7 +19394,9 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @brief access specified object element with default value /// @brief access specified object element with default value
/// @sa https://json.nlohmann.me/api/basic_json/value/ /// @sa https://json.nlohmann.me/api/basic_json/value/
/// overload for a default value of type const char* /// overload for a default value of type const char*
string_t value(const typename object_t::key_type& key, const char* default_value) const template < class KeyType, typename detail::enable_if_t <
detail::is_usable_as_key_type<basic_json_t, KeyType>::value, int> = 0>
string_t value(const KeyType& key, const char* default_value) const
{ {
return value(key, string_t(default_value)); return value(key, string_t(default_value));
} }
...@@ -19346,7 +19405,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec ...@@ -19346,7 +19405,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @sa https://json.nlohmann.me/api/basic_json/value/ /// @sa https://json.nlohmann.me/api/basic_json/value/
template<class ValueType, typename std::enable_if< template<class ValueType, typename std::enable_if<
detail::is_getable<basic_json_t, ValueType>::value, int>::type = 0> detail::is_getable<basic_json_t, ValueType>::value, int>::type = 0>
ValueType value(const json_pointer& ptr, const ValueType& default_value) const typename std::decay<ValueType>::type value(const json_pointer& ptr, ValueType && default_value) const
{ {
// at only works for objects // at only works for objects
if (JSON_HEDLEY_LIKELY(is_object())) if (JSON_HEDLEY_LIKELY(is_object()))
...@@ -19358,7 +19417,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec ...@@ -19358,7 +19417,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
} }
JSON_INTERNAL_CATCH (out_of_range&) JSON_INTERNAL_CATCH (out_of_range&)
{ {
return default_value; return std::forward<ValueType>(default_value);
} }
} }
...@@ -19553,15 +19612,24 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec ...@@ -19553,15 +19612,24 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @brief remove element from a JSON object given a key /// @brief remove element from a JSON object given a key
/// @sa https://json.nlohmann.me/api/basic_json/erase/ /// @sa https://json.nlohmann.me/api/basic_json/erase/
size_type erase(const typename object_t::key_type& key) template < class KeyT, typename detail::enable_if_t <
detail::is_usable_as_key_type<basic_json_t, KeyT>::value, int> = 0>
size_type erase(const KeyT& key)
{ {
// this erase only works for objects // this erase only works for objects
if (JSON_HEDLEY_LIKELY(is_object())) if (JSON_HEDLEY_UNLIKELY(!is_object()))
{ {
return m_value.object->erase(key); JSON_THROW(type_error::create(307, "cannot use erase() with " + std::string(type_name()), *this));
} }
JSON_THROW(type_error::create(307, "cannot use erase() with " + std::string(type_name()), *this)); const auto it = m_value.object->find(key);
if (it != m_value.object->end())
{
m_value.object->erase(it);
return 1;
}
return 0;
} }
/// @brief remove element from a JSON array given an index /// @brief remove element from a JSON array given an index
...@@ -19596,14 +19664,15 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec ...@@ -19596,14 +19664,15 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @brief find an element in a JSON object /// @brief find an element in a JSON object
/// @sa https://json.nlohmann.me/api/basic_json/find/ /// @sa https://json.nlohmann.me/api/basic_json/find/
template<typename KeyT> template < class KeyT, typename detail::enable_if_t <
iterator find(KeyT&& key) detail::is_usable_as_key_type<basic_json_t, KeyT>::value, int> = 0>
iterator find(const KeyT& key)
{ {
auto result = end(); auto result = end();
if (is_object()) if (is_object())
{ {
result.m_it.object_iterator = m_value.object->find(std::forward<KeyT>(key)); result.m_it.object_iterator = m_value.object->find(key);
} }
return result; return result;
...@@ -19611,14 +19680,15 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec ...@@ -19611,14 +19680,15 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @brief find an element in a JSON object /// @brief find an element in a JSON object
/// @sa https://json.nlohmann.me/api/basic_json/find/ /// @sa https://json.nlohmann.me/api/basic_json/find/
template<typename KeyT> template < class KeyT, typename detail::enable_if_t <
const_iterator find(KeyT&& key) const detail::is_usable_as_key_type<basic_json_t, KeyT>::value, int> = 0>
const_iterator find(const KeyT& key) const
{ {
auto result = cend(); auto result = cend();
if (is_object()) if (is_object())
{ {
result.m_it.object_iterator = m_value.object->find(std::forward<KeyT>(key)); result.m_it.object_iterator = m_value.object->find(key);
} }
return result; return result;
...@@ -19626,20 +19696,21 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec ...@@ -19626,20 +19696,21 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @brief returns the number of occurrences of a key in a JSON object /// @brief returns the number of occurrences of a key in a JSON object
/// @sa https://json.nlohmann.me/api/basic_json/count/ /// @sa https://json.nlohmann.me/api/basic_json/count/
template<typename KeyT> template < class KeyT, typename detail::enable_if_t <
size_type count(KeyT&& key) const detail::is_usable_as_key_type<basic_json_t, KeyT>::value, int> = 0>
size_type count(const KeyT& key) const
{ {
// return 0 for all nonobject types // return 0 for all nonobject types
return is_object() ? m_value.object->count(std::forward<KeyT>(key)) : 0; return is_object() ? m_value.object->count(key) : 0;
} }
/// @brief check the existence of an element in a JSON object /// @brief check the existence of an element in a JSON object
/// @sa https://json.nlohmann.me/api/basic_json/contains/ /// @sa https://json.nlohmann.me/api/basic_json/contains/
template < typename KeyT, typename std::enable_if < template < class KeyT, typename detail::enable_if_t <
!std::is_same<typename std::decay<KeyT>::type, json_pointer>::value, int >::type = 0 > !std::is_same<typename std::decay<KeyT>::type, json_pointer>::value&& detail::is_usable_as_key_type<basic_json_t, KeyT>::value, int > = 0 >
bool contains(KeyT && key) const bool contains(const KeyT& key) const
{ {
return is_object() && m_value.object->find(std::forward<KeyT>(key)) != m_value.object->end(); return is_object() && m_value.object->find(key) != m_value.object->end();
} }
/// @brief check the existence of an element in a JSON object given a JSON pointer /// @brief check the existence of an element in a JSON object given a JSON pointer
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment