From 1a66679929176fc7041c8140aa582cd745359fce Mon Sep 17 00:00:00 2001 From: Jamie Seward Date: Sat, 21 Oct 2017 15:20:13 -0700 Subject: [PATCH 1/9] Add string_view support This avoids unnecessary string copies on often used find(). --- src/json.hpp | 44 +++++++++++++++++++++++++++++++++++--------- test/CMakeLists.txt | 5 +++++ 2 files changed, 40 insertions(+), 9 deletions(-) diff --git a/src/json.hpp b/src/json.hpp index 589f04470..ac93e725b 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -109,6 +109,16 @@ SOFTWARE. #define JSON_UNLIKELY(x) x #endif +// string_view support +#if defined(_MSC_VER) && defined(_HAS_CXX17) + #define JSON_USE_STRING_VIEW +#endif + +#if defined(JSON_USE_STRING_VIEW) + #include +#endif + + /*! @brief namespace for Niels Lohmann @see https://github.com/nlohmann @@ -7589,11 +7599,27 @@ class basic_json 7159](http://rfc7159.net/rfc7159), because any order implements the specified "unordered" nature of JSON objects. */ - using object_t = ObjectType, - AllocatorType>>; + +#if defined(JSON_USE_STRING_VIEW) + // if std::string_view is to be used the object_t must + // be declared with a transparent comparator + // https://stackoverflow.com/questions/35525777/use-of-string-view-for-map-lookup + using object_t = ObjectType, + AllocatorType>>; + + using object_comparator_key_t = std::string_view; +#else + using object_t = ObjectType, + AllocatorType>>; + + using object_comparator_key_t = typename object_t::key_type; +#endif /*! @brief a type for an array @@ -10880,7 +10906,7 @@ class basic_json @since version 1.0.0 */ - iterator find(typename object_t::key_type key) + iterator find(object_comparator_key_t key) { auto result = end(); @@ -10894,9 +10920,9 @@ class basic_json /*! @brief find an element in a JSON object - @copydoc find(typename object_t::key_type) + @copydoc find(object_transparent_comparator_key_t) */ - const_iterator find(typename object_t::key_type key) const + const_iterator find(object_comparator_key_t key) const { auto result = cend(); @@ -10929,7 +10955,7 @@ class basic_json @since version 1.0.0 */ - size_type count(typename object_t::key_type key) const + size_type count(object_comparator_key_t key) const { // return 0 for all nonobject types return is_object() ? m_value.object->count(key) : 0; diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index c72867839..1c1455a23 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -80,6 +80,11 @@ if(MSVC) # Disable warning C4566: character represented by universal-character-name '\uFF01' cannot be represented in the current code page (1252) # Disable warning C4996: 'nlohmann::basic_json::operator <<': was declared deprecated set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4389 /wd4309 /wd4566 /wd4996") + + if(MSVC_VERSION GREATER_EQUAL 1910) + # Enable c++17 support in Visual Studio 2017 (for testing string_view support) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /std:c++17") + endif() endif() ############################################################################# From 59cde1ad6ef0bcfbdc86bb1527342f1065dc0ab5 Mon Sep 17 00:00:00 2001 From: Jamie Seward Date: Sat, 21 Oct 2017 16:29:37 -0700 Subject: [PATCH 2/9] Fix for _HAS_CXX17 == 0 Copied from solution to https://github.com/nlohmann/json/issues/464 --- src/json.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/json.hpp b/src/json.hpp index ac93e725b..4a5e14d42 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -110,7 +110,7 @@ SOFTWARE. #endif // string_view support -#if defined(_MSC_VER) && defined(_HAS_CXX17) +#if defined(_MSC_VER) && defined(_HAS_CXX17) && _HAS_CXX17 == 1 #define JSON_USE_STRING_VIEW #endif From d468f8c4e65087aa9df2899c2c37e46a4c423f98 Mon Sep 17 00:00:00 2001 From: Jamie Seward Date: Sat, 21 Oct 2017 16:36:05 -0700 Subject: [PATCH 3/9] Use consistent logic to determine if string_view exists --- src/json.hpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/json.hpp b/src/json.hpp index 4a5e14d42..2e619c858 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -110,11 +110,11 @@ SOFTWARE. #endif // string_view support -#if defined(_MSC_VER) && defined(_HAS_CXX17) && _HAS_CXX17 == 1 - #define JSON_USE_STRING_VIEW +#if (defined(__cplusplus) && __cplusplus >= 201703L) || (defined(_MSC_VER) && _MSC_VER > 1900 && defined(_HAS_CXX17) && _HAS_CXX17 == 1) // fix for issue #464 + #define JSON_HAS_STRING_VIEW #endif -#if defined(JSON_USE_STRING_VIEW) +#if defined(JSON_HAS_STRING_VIEW) #include #endif @@ -7600,7 +7600,7 @@ class basic_json specified "unordered" nature of JSON objects. */ -#if defined(JSON_USE_STRING_VIEW) +#if defined(JSON_HAS_STRING_VIEW) // if std::string_view is to be used the object_t must // be declared with a transparent comparator // https://stackoverflow.com/questions/35525777/use-of-string-view-for-map-lookup @@ -9868,7 +9868,7 @@ class basic_json #ifndef _MSC_VER // fix for issue #167 operator<< ambiguity under VS2015 and not std::is_same>::value #endif -#if (defined(__cplusplus) && __cplusplus >= 201703L) || (defined(_MSC_VER) && _MSC_VER >1900 && defined(_HAS_CXX17) && _HAS_CXX17 == 1) // fix for issue #464 +#if defined(JSON_HAS_STRING_VIEW) and not std::is_same::value #endif , int >::type = 0 > From 33c6511dd0b04337ba4d0abe151ce826372ba551 Mon Sep 17 00:00:00 2001 From: Jamie Seward Date: Mon, 23 Oct 2017 00:43:26 -0700 Subject: [PATCH 4/9] Remove JSON_HAS_STRING_VIEW Instead implement @gregmarr's PR comments that perfect forwarding should be used. Also cleaned up cpp language standard detection. --- src/json.hpp | 100 ++++++++++++++++++++++++++++++-------------- test/CMakeLists.txt | 2 +- 2 files changed, 70 insertions(+), 32 deletions(-) diff --git a/src/json.hpp b/src/json.hpp index 2e619c858..16b0b1fd8 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -109,16 +109,14 @@ SOFTWARE. #define JSON_UNLIKELY(x) x #endif -// string_view support -#if (defined(__cplusplus) && __cplusplus >= 201703L) || (defined(_MSC_VER) && _MSC_VER > 1900 && defined(_HAS_CXX17) && _HAS_CXX17 == 1) // fix for issue #464 - #define JSON_HAS_STRING_VIEW +// cpp language standard detection +#if (defined(__cplusplus) && __cplusplus >= 201703L) || (defined(_HAS_CXX17) && _HAS_CXX17 == 1) // fix for issue #464 + #define JSON_HAS_CPP_17 + #define JSON_HAS_CPP_14 +#elif (defined(__cplusplus) && __cplusplus >= 201402L) || (defined(_HAS_CXX14) && _HAS_CXX14 == 1) + #define JSON_HAS_CPP_14 #endif -#if defined(JSON_HAS_STRING_VIEW) - #include -#endif - - /*! @brief namespace for Niels Lohmann @see https://github.com/nlohmann @@ -7600,26 +7598,18 @@ class basic_json specified "unordered" nature of JSON objects. */ -#if defined(JSON_HAS_STRING_VIEW) - // if std::string_view is to be used the object_t must - // be declared with a transparent comparator - // https://stackoverflow.com/questions/35525777/use-of-string-view-for-map-lookup - using object_t = ObjectType, - AllocatorType>>; - - using object_comparator_key_t = std::string_view; +#if defined(JSON_HAS_CPP_14) + // Use transparent comparator if possible, combined with perfect forwarding + // on find() and count() calls prevents unnecessary string construction. + using object_comparator_t = std::less<>; #else - using object_t = ObjectType, - AllocatorType>>; - - using object_comparator_key_t = typename object_t::key_type; + using object_comparator_t = std::less; #endif + using object_t = ObjectType>>; /*! @brief a type for an array @@ -9868,7 +9858,7 @@ class basic_json #ifndef _MSC_VER // fix for issue #167 operator<< ambiguity under VS2015 and not std::is_same>::value #endif -#if defined(JSON_HAS_STRING_VIEW) +#if defined(JSON_HAS_CPP_17) and not std::is_same::value #endif , int >::type = 0 > @@ -10906,7 +10896,7 @@ class basic_json @since version 1.0.0 */ - iterator find(object_comparator_key_t key) + iterator find(typename object_t::key_type key) { auto result = end(); @@ -10920,9 +10910,9 @@ class basic_json /*! @brief find an element in a JSON object - @copydoc find(object_transparent_comparator_key_t) + @copydoc find(typename object_t::key_type) */ - const_iterator find(object_comparator_key_t key) const + const_iterator find(typename object_t::key_type key) const { auto result = cend(); @@ -10934,6 +10924,42 @@ class basic_json return result; } +#ifdef JSON_HAS_CPP_14 + /*! + @brief find an element in a JSON object + @copydoc find(typename object_t::key_type) + */ + template + iterator find(KeyT&& key) + { + auto result = end(); + + if (is_object()) + { + result.m_it.object_iterator = m_value.object->find(std::forward(key)); + } + + return result; + } + + /*! + @brief find an element in a JSON object + @copydoc find(typename object_t::key_type) + */ + template + const_iterator find(KeyT&& key) const + { + auto result = cend(); + + if (is_object()) + { + result.m_it.object_iterator = m_value.object->find(std::forward(key)); + } + + return result; + } +#endif + /*! @brief returns the number of occurrences of a key in a JSON object @@ -10955,12 +10981,24 @@ class basic_json @since version 1.0.0 */ - size_type count(object_comparator_key_t key) const + size_type count(typename object_t::key_type key) const { // return 0 for all nonobject types return is_object() ? m_value.object->count(key) : 0; } +#ifdef JSON_HAS_CPP_14 + /*! + @brief returns the number of occurrences of a key in a JSON object + @copydoc count(typename object_t::key_type) + */ + template + size_type count(KeyT&& key) const + { + // return 0 for all nonobject types + return is_object() ? m_value.object->count(std::forward(key)) : 0; + } +#endif /// @} diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 1c1455a23..2c2c74791 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -82,7 +82,7 @@ if(MSVC) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4389 /wd4309 /wd4566 /wd4996") if(MSVC_VERSION GREATER_EQUAL 1910) - # Enable c++17 support in Visual Studio 2017 (for testing string_view support) + # Enable c++17 support in Visual Studio 2017 (for testing perfect forwarding and transparent comparator in find() / count()) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /std:c++17") endif() endif() From 73b1629a15a66a3e15d456f400ea9ceca4d2e317 Mon Sep 17 00:00:00 2001 From: Jamie Seward Date: Mon, 23 Oct 2017 23:45:39 -0700 Subject: [PATCH 5/9] Remove tabs for spaces --- src/json.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/json.hpp b/src/json.hpp index 16b0b1fd8..af0870981 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -111,10 +111,10 @@ SOFTWARE. // cpp language standard detection #if (defined(__cplusplus) && __cplusplus >= 201703L) || (defined(_HAS_CXX17) && _HAS_CXX17 == 1) // fix for issue #464 - #define JSON_HAS_CPP_17 - #define JSON_HAS_CPP_14 + #define JSON_HAS_CPP_17 + #define JSON_HAS_CPP_14 #elif (defined(__cplusplus) && __cplusplus >= 201402L) || (defined(_HAS_CXX14) && _HAS_CXX14 == 1) - #define JSON_HAS_CPP_14 + #define JSON_HAS_CPP_14 #endif /*! From 16ffdbcb209ec43fdff246f6d73caf18fae940a2 Mon Sep 17 00:00:00 2001 From: Jamie Seward Date: Mon, 23 Oct 2017 23:50:06 -0700 Subject: [PATCH 6/9] Remove c++17 support flag in cmake Already covered by AppVeyor --- test/CMakeLists.txt | 5 ----- 1 file changed, 5 deletions(-) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 2c2c74791..c72867839 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -80,11 +80,6 @@ if(MSVC) # Disable warning C4566: character represented by universal-character-name '\uFF01' cannot be represented in the current code page (1252) # Disable warning C4996: 'nlohmann::basic_json::operator <<': was declared deprecated set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4389 /wd4309 /wd4566 /wd4996") - - if(MSVC_VERSION GREATER_EQUAL 1910) - # Enable c++17 support in Visual Studio 2017 (for testing perfect forwarding and transparent comparator in find() / count()) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /std:c++17") - endif() endif() ############################################################################# From 6c9a401ebc680199cdcacfbe60d5dd8f51724a48 Mon Sep 17 00:00:00 2001 From: Jamie Seward Date: Tue, 24 Oct 2017 00:01:56 -0700 Subject: [PATCH 7/9] Remove old non-perfect forwarding find and count --- src/json.hpp | 51 +++------------------------------------------------ 1 file changed, 3 insertions(+), 48 deletions(-) diff --git a/src/json.hpp b/src/json.hpp index af0870981..93a842bf7 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -10884,7 +10884,7 @@ class basic_json @note This method always returns @ref end() when executed on a JSON type that is not an object. - @param[in] key key value of the element to search for + @param[in] key key value of the element to search for. @return Iterator to an element with key equivalent to @a key. If no such element is found or the JSON value is not an object, past-the-end (see @@ -10896,39 +10896,6 @@ class basic_json @since version 1.0.0 */ - iterator find(typename object_t::key_type key) - { - auto result = end(); - - if (is_object()) - { - result.m_it.object_iterator = m_value.object->find(key); - } - - return result; - } - - /*! - @brief find an element in a JSON object - @copydoc find(typename object_t::key_type) - */ - const_iterator find(typename object_t::key_type key) const - { - auto result = cend(); - - if (is_object()) - { - result.m_it.object_iterator = m_value.object->find(key); - } - - return result; - } - -#ifdef JSON_HAS_CPP_14 - /*! - @brief find an element in a JSON object - @copydoc find(typename object_t::key_type) - */ template iterator find(KeyT&& key) { @@ -10944,7 +10911,7 @@ class basic_json /*! @brief find an element in a JSON object - @copydoc find(typename object_t::key_type) + @copydoc find(KeyT&&) */ template const_iterator find(KeyT&& key) const @@ -10958,7 +10925,6 @@ class basic_json return result; } -#endif /*! @brief returns the number of occurrences of a key in a JSON object @@ -10981,24 +10947,13 @@ class basic_json @since version 1.0.0 */ - size_type count(typename object_t::key_type key) const - { - // return 0 for all nonobject types - return is_object() ? m_value.object->count(key) : 0; - } - -#ifdef JSON_HAS_CPP_14 - /*! - @brief returns the number of occurrences of a key in a JSON object - @copydoc count(typename object_t::key_type) - */ template size_type count(KeyT&& key) const { // return 0 for all nonobject types return is_object() ? m_value.object->count(std::forward(key)) : 0; } -#endif + /// @} From 715c98b404259f41765fa0c77f69d189a0754c68 Mon Sep 17 00:00:00 2001 From: Jamie Seward Date: Tue, 24 Oct 2017 00:06:22 -0700 Subject: [PATCH 8/9] Remove extra spaces --- src/json.hpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/json.hpp b/src/json.hpp index 93a842bf7..055d1b9ec 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -7606,10 +7606,10 @@ class basic_json using object_comparator_t = std::less; #endif using object_t = ObjectType>>; + basic_json, + object_comparator_t, + AllocatorType>>; /*! @brief a type for an array From 992c836b308e313518a55ca0f2f47876fdf0ce17 Mon Sep 17 00:00:00 2001 From: Jamie Seward Date: Tue, 24 Oct 2017 00:14:25 -0700 Subject: [PATCH 9/9] Add missing spaces --- src/json.hpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/json.hpp b/src/json.hpp index 055d1b9ec..8fee398e7 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -7606,10 +7606,10 @@ class basic_json using object_comparator_t = std::less; #endif using object_t = ObjectType>>; + basic_json, + object_comparator_t, + AllocatorType>>; /*! @brief a type for an array