From 9b838a0ecbd37df65afaeb68488450feff815670 Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Sun, 17 Oct 2021 15:27:21 +0200 Subject: [PATCH] :twisted_rightwards_arrows: update from develop --- single_include/nlohmann/json.hpp | 278 +++++++++++++------------------ 1 file changed, 118 insertions(+), 160 deletions(-) diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index 87475ab31..19e92f120 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -3913,6 +3913,33 @@ struct is_constructible_tuple : std::false_type {}; template struct is_constructible_tuple> : conjunction...> {}; +/// type to check if KeyType can be used as object key + +template +struct is_key_type_comparable +{ + static constexpr bool value = false; +}; + +template +struct is_key_type_comparable(), std::declval())), +decltype(ComparatorType()(std::declval(), std::declval())) + >> +{ + static constexpr bool value = true; +}; + +template +struct is_usable_as_key_type +{ + static constexpr bool value = + is_key_type_comparable::value && + !std::is_same::value && + !std::is_same::value; +}; + + // a naive helper to check if a type is an ordered_map (exploits the fact that // ordered_map inherits capacity() from std::vector) template @@ -18564,10 +18591,12 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec default: { object = nullptr; // silence warning, see #821 + // LCOV_EXCL_START 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; } } @@ -21058,6 +21087,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec Returns a reference to the element at with specified key @a key, with bounds checking. + @tparam KeyT a type convertible to an object key or a `std::string_view` @param[in] key key of the element to access @return reference to the element at key @a key @@ -21076,31 +21106,28 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec access by reference @sa see @ref value() for access by value with a default value - @since version 1.0.0 + @since version 1.0.0; template added in version 3.10.0 @liveexample{The example below shows how object elements can be read and written using `at()`. It also demonstrates the different exceptions that can be thrown.,at__object_t_key_type} */ - reference at(const typename object_t::key_type& key) + template < class KeyT, typename detail::enable_if_t < + detail::is_usable_as_key_type::value&& !std::is_same::type, json_pointer>::value > ... > + reference at(const KeyT& key) { // at only works for objects - if (JSON_HEDLEY_LIKELY(is_object())) - { - JSON_TRY - { - return set_parent(m_value.object->at(key)); - } - JSON_CATCH (std::out_of_range&) - { - // create better exception explanation - JSON_THROW(out_of_range::create(403, "key '" + key + "' not found", *this)); - } - } - else + if (JSON_HEDLEY_UNLIKELY(!is_object())) { JSON_THROW(type_error::create(304, "cannot use at() with " + std::string(type_name()), *this)); } + + auto it = m_value.object->find(key); + if (it == m_value.object->end()) + { + JSON_THROW(out_of_range::create(403, "key '" + std::string(key) + "' not found", *this)); + } + return set_parent(it->second); } /*! @@ -21110,6 +21137,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec with bounds checking. @param[in] key key of the element to access + @tparam KeyT a type convertible to an object key or a `std::string_view` @return const reference to the element at key @a key @@ -21127,31 +21155,28 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec access by reference @sa see @ref value() for access by value with a default value - @since version 1.0.0 + @since version 1.0.0; template added in version 3.10.0 @liveexample{The example below shows how object elements can be read using `at()`. It also demonstrates the different exceptions that can be thrown., at__object_t_key_type_const} */ - 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::value&& !std::is_same::type, json_pointer>::value > ... > + const_reference at(const KeyT& key) const { // at only works for objects - if (JSON_HEDLEY_LIKELY(is_object())) - { - JSON_TRY - { - return m_value.object->at(key); - } - JSON_CATCH (std::out_of_range&) - { - // create better exception explanation - JSON_THROW(out_of_range::create(403, "key '" + key + "' not found", *this)); - } - } - else + if (JSON_HEDLEY_UNLIKELY(!is_object())) { JSON_THROW(type_error::create(304, "cannot use at() with " + std::string(type_name()), *this)); } + + auto it = m_value.object->find(key); + if (it == m_value.object->end()) + { + JSON_THROW(out_of_range::create(403, "key '" + std::string(key) + "' not found", *this)); + } + return it->second; } /*! @@ -21263,6 +21288,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec In case the value was `null` before, it is converted to an object. @param[in] key key of the element to access + @tparam KeyT a type convertible to an object key or a std::string_view @return reference to the element at key @a key @@ -21278,9 +21304,11 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec with range checking @sa see @ref value() for access by value with a default value - @since version 1.0.0 + @since version 1.0.0; template KeyT added in version 3.10.0 */ - reference operator[](const typename object_t::key_type& key) + template < class KeyT, typename detail::enable_if_t < + detail::is_usable_as_key_type::value&& !std::is_same::type, json_pointer>::value > ... > + reference operator[](KeyT&& key) { // implicitly convert null value to an empty object if (is_null()) @@ -21293,7 +21321,8 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec // operator[] only works for objects if (JSON_HEDLEY_LIKELY(is_object())) { - return set_parent(m_value.object->operator[](key)); + auto result = m_value.object->emplace(std::forward(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)); @@ -21309,6 +21338,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec undefined. @param[in] key key of the element to access + @tparam KeyT a type convertible to an object key or a std::string_view @return const reference to the element at key @a key @@ -21327,107 +21357,18 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec with range checking @sa see @ref value() for access by value with a default value - @since version 1.0.0 + @since version 1.0.0; template KeyT added in version 3.10.0 */ - 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::value&& !std::is_same::type, json_pointer>::value > ... > + const_reference operator[](KeyT&& key) const { - // const operator[] only works for objects + // operator[] only works for objects if (JSON_HEDLEY_LIKELY(is_object())) { - JSON_ASSERT(m_value.object->find(key) != m_value.object->end()); - return m_value.object->find(key)->second; - } - - JSON_THROW(type_error::create(305, "cannot use operator[] with a string argument with " + std::string(type_name()), *this)); - } - - /*! - @brief access specified object element - - Returns a reference to the element at with specified key @a key. - - @note If @a key is not found in the object, then it is silently added to - the object and filled with a `null` value to make `key` a valid reference. - In case the value was `null` before, it is converted to an object. - - @param[in] key key of the element to access - - @return reference to the element at key @a key - - @throw type_error.305 if the JSON value is not an object or null; in that - cases, 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 and - written using the `[]` operator.,operatorarray__key_type} - - @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 - JSON_HEDLEY_NON_NULL(2) - reference operator[](T* key) - { - // implicitly convert null to object - if (is_null()) - { - m_type = value_t::object; - m_value = value_t::object; - assert_invariant(); - } - - // at only works for objects - if (JSON_HEDLEY_LIKELY(is_object())) - { - return set_parent(m_value.object->operator[](key)); - } - - JSON_THROW(type_error::create(305, "cannot use operator[] with a string argument with " + std::string(type_name()), *this)); - } - - /*! - @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 - JSON_HEDLEY_NON_NULL(2) - const_reference operator[](T* key) const - { - // at only works for objects - if (JSON_HEDLEY_LIKELY(is_object())) - { - JSON_ASSERT(m_value.object->find(key) != m_value.object->end()); - return m_value.object->find(key)->second; + auto it = m_value.object->find(std::forward(key)); + 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)); @@ -21458,6 +21399,8 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec @param[in] key key of the element to access @param[in] default_value the value to return if @a key is not found + @tparam KeyType A type for an object key. This can also be a string + literal or a string view (C++17). @tparam ValueType type compatible to JSON values, for instance `int` for JSON integer numbers, `bool` for JSON booleans, or `std::vector` types for JSON arrays. Note the type of the expected value at @a key and the default @@ -21481,13 +21424,13 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec @sa see @ref operator[](const typename object_t::key_type&) for unchecked access by reference - @since version 1.0.0 + @since version 1.0.0, KeyType template added in 3.10.0 */ // 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::value - && !std::is_same::value, int >::type = 0 > - ValueType value(const typename object_t::key_type& key, const ValueType& default_value) const + && !std::is_same::value&& detail::is_usable_as_key_type::value > ... > + typename std::decay::type value(const KeyType& key, ValueType&& default_value) const { // at only works for objects if (JSON_HEDLEY_LIKELY(is_object())) @@ -21496,10 +21439,10 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec const auto it = find(key); if (it != end()) { - return it->template get(); + return it->template get::type>(); } - return default_value; + return std::forward(default_value); } JSON_THROW(type_error::create(306, "cannot use value() with " + std::string(type_name()), *this)); @@ -21509,7 +21452,9 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec @brief overload for a default value of type const char* @copydoc basic_json::value(const typename object_t::key_type&, const ValueType&) const */ - 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::value > ... > + string_t value(const KeyType& key, const char* default_value) const { return value(key, string_t(default_value)); } @@ -21559,7 +21504,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec */ template::value, int>::type = 0> - ValueType value(const json_pointer& ptr, const ValueType& default_value) const + typename std::decay::type value(const json_pointer& ptr, ValueType && default_value) const { // at only works for objects if (JSON_HEDLEY_LIKELY(is_object())) @@ -21571,7 +21516,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec } JSON_INTERNAL_CATCH (out_of_range&) { - return default_value; + return std::forward(default_value); } } @@ -21913,6 +21858,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec Removes elements from a JSON object with the key value @a key. @param[in] key value of the elements to remove + @tparam KeyT a type convertible to an object key or a std::string_view @return Number of elements removed. If @a ObjectType is the default `std::map` type, the return value will always be `0` (@a key was not @@ -21934,17 +21880,26 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec @sa see @ref erase(const size_type) -- removes the element from an array at the given index - @since version 1.0.0 + @since version 1.0.0; template added in version 3.10.0 */ - size_type erase(const typename object_t::key_type& key) + template < class KeyT, typename detail::enable_if_t < + detail::is_usable_as_key_type::value > ... > + size_type erase(const KeyT& key) { // 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; } /*! @@ -22023,14 +21978,15 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec @since version 1.0.0 */ - template - iterator find(KeyT&& key) + template < class KeyT, typename detail::enable_if_t < + detail::is_usable_as_key_type::value > ... > + iterator find(const KeyT& key) { auto result = end(); if (is_object()) { - result.m_it.object_iterator = m_value.object->find(std::forward(key)); + result.m_it.object_iterator = m_value.object->find(key); } return result; @@ -22038,16 +21994,17 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /*! @brief find an element in a JSON object - @copydoc find(KeyT&&) + @copydoc find(const KeyT&) */ - template - const_iterator find(KeyT&& key) const + template < class KeyT, typename detail::enable_if_t < + detail::is_usable_as_key_type::value > ... > + const_iterator find(const KeyT& key) const { auto result = cend(); if (is_object()) { - result.m_it.object_iterator = m_value.object->find(std::forward(key)); + result.m_it.object_iterator = m_value.object->find(key); } return result; @@ -22074,11 +22031,12 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec @since version 1.0.0 */ - template - size_type count(KeyT&& key) const + template < class KeyT, typename detail::enable_if_t < + detail::is_usable_as_key_type::value > ... > + size_type count(const KeyT& key) const { // return 0 for all nonobject types - return is_object() ? m_value.object->count(std::forward(key)) : 0; + return is_object() ? m_value.object->count(key) : 0; } /*! @@ -22101,16 +22059,16 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec @liveexample{The following code shows an example for `contains()`.,contains} - @sa see @ref find(KeyT&&) -- returns an iterator to an object element + @sa see @ref find(const KeyT&) -- returns an iterator to an object element @sa see @ref contains(const json_pointer&) const -- checks the existence for a JSON pointer @since version 3.6.0 */ - template < typename KeyT, typename std::enable_if < - !std::is_same::type, json_pointer>::value, int >::type = 0 > - bool contains(KeyT && key) const + template < class KeyT, typename detail::enable_if_t < + !std::is_same::type, json_pointer>::value&& detail::is_usable_as_key_type::value > ... > + bool contains(const KeyT& key) const { - return is_object() && m_value.object->find(std::forward(key)) != m_value.object->end(); + return is_object() && m_value.object->find(key) != m_value.object->end(); } /*!