From 225c8f150ad6b098de6a650fc0cce613d5d66802 Mon Sep 17 00:00:00 2001 From: Guillaume Racicot Date: Sat, 6 Jun 2020 11:36:39 -0400 Subject: [PATCH 1/2] Disable std::swap specialization in C++20 and added a friend swap function --- include/nlohmann/detail/macro_scope.hpp | 6 +++- include/nlohmann/json.hpp | 33 +++++++++++++++++++++ single_include/nlohmann/json.hpp | 39 ++++++++++++++++++++++++- 3 files changed, 76 insertions(+), 2 deletions(-) diff --git a/include/nlohmann/detail/macro_scope.hpp b/include/nlohmann/detail/macro_scope.hpp index 25e6b76e..a48d18e8 100644 --- a/include/nlohmann/detail/macro_scope.hpp +++ b/include/nlohmann/detail/macro_scope.hpp @@ -20,7 +20,11 @@ #endif // C++ language standard detection -#if (defined(__cplusplus) && __cplusplus >= 201703L) || (defined(_HAS_CXX17) && _HAS_CXX17 == 1) // fix for issue #464 +#if (defined(__cplusplus) && __cplusplus >= 202002L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 202002L) + #define JSON_HAS_CPP_20 + #define JSON_HAS_CPP_17 + #define JSON_HAS_CPP_14 +#elif (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) diff --git a/include/nlohmann/json.hpp b/include/nlohmann/json.hpp index 592d1966..abc53056 100644 --- a/include/nlohmann/json.hpp +++ b/include/nlohmann/json.hpp @@ -5865,6 +5865,34 @@ class basic_json /*! @brief exchanges the values + Exchanges the contents of the JSON value from @a left with those of @a right. Does not + invoke any move, copy, or swap operations on individual elements. All + iterators and references remain valid. The past-the-end iterator is + invalidated. implemented as a friend function callable via ADL. + + @param[in,out] left JSON value to exchange the contents with + @param[in,out] right JSON value to exchange the contents with + + @complexity Constant. + + @liveexample{The example below shows how JSON values can be swapped with + `swap()`.,swap__reference} + + @since version 1.0.0 + */ + friend void swap(reference left, reference right) noexcept ( + std::is_nothrow_move_constructible::value and + std::is_nothrow_move_assignable::value and + std::is_nothrow_move_constructible::value and + std::is_nothrow_move_assignable::value + ) + { + left.swap(right); + } + + /*! + @brief exchanges the values + Exchanges the contents of a JSON array with those of @a other. Does not invoke any move, copy, or swap operations on individual elements. All iterators and references remain valid. The past-the-end iterator is @@ -8635,6 +8663,9 @@ struct less<::nlohmann::detail::value_t> } }; +// C++20 prohibit function specialization in the std namespace. +#ifndef JSON_HAS_CPP_20 + /*! @brief exchanges the values of two JSON objects @@ -8649,6 +8680,8 @@ inline void swap(nlohmann::json& j1, nlohmann::json& j2) noexcep j1.swap(j2); } +#endif + } // namespace std /*! diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index a24a08b5..53a9380c 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -2048,7 +2048,11 @@ JSON_HEDLEY_DIAGNOSTIC_POP #endif // C++ language standard detection -#if (defined(__cplusplus) && __cplusplus >= 201703L) || (defined(_HAS_CXX17) && _HAS_CXX17 == 1) // fix for issue #464 +#if (defined(__cplusplus) && __cplusplus >= 202002L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 202002L) + #define JSON_HAS_CPP_20 + #define JSON_HAS_CPP_17 + #define JSON_HAS_CPP_14 +#elif (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) @@ -21628,6 +21632,34 @@ class basic_json /*! @brief exchanges the values + Exchanges the contents of the JSON value from @a left with those of @a right. Does not + invoke any move, copy, or swap operations on individual elements. All + iterators and references remain valid. The past-the-end iterator is + invalidated. implemented as a friend function callable via ADL. + + @param[in,out] left JSON value to exchange the contents with + @param[in,out] right JSON value to exchange the contents with + + @complexity Constant. + + @liveexample{The example below shows how JSON values can be swapped with + `swap()`.,swap__reference} + + @since version 1.0.0 + */ + friend void swap(reference left, reference right) noexcept ( + std::is_nothrow_move_constructible::value and + std::is_nothrow_move_assignable::value and + std::is_nothrow_move_constructible::value and + std::is_nothrow_move_assignable::value + ) + { + left.swap(right); + } + + /*! + @brief exchanges the values + Exchanges the contents of a JSON array with those of @a other. Does not invoke any move, copy, or swap operations on individual elements. All iterators and references remain valid. The past-the-end iterator is @@ -24398,6 +24430,9 @@ struct less<::nlohmann::detail::value_t> } }; +// C++20 prohibit function specialization in the std namespace. +#ifndef JSON_HAS_CPP_20 + /*! @brief exchanges the values of two JSON objects @@ -24412,6 +24447,8 @@ inline void swap(nlohmann::json& j1, nlohmann::json& j2) noexcep j1.swap(j2); } +#endif + } // namespace std /*! From 82fbbeeac5c4a75fa4af95f10c97c56ef95ddbed Mon Sep 17 00:00:00 2001 From: Guillaume Racicot Date: Sat, 6 Jun 2020 12:28:52 -0400 Subject: [PATCH 2/2] Adapted unit tests to use ADL calls for swap like the new swappable concept --- test/src/unit-concepts.cpp | 4 ++-- test/src/unit-modifiers.cpp | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/test/src/unit-concepts.cpp b/test/src/unit-concepts.cpp index 899d1eaf..1f3afc0c 100644 --- a/test/src/unit-concepts.cpp +++ b/test/src/unit-concepts.cpp @@ -154,7 +154,7 @@ TEST_CASE("concepts") json j {1, 2, 3}; json::iterator it1 = j.begin(); json::iterator it2 = j.end(); - std::swap(it1, it2); + swap(it1, it2); CHECK(it1 == j.end()); CHECK(it2 == j.begin()); } @@ -162,7 +162,7 @@ TEST_CASE("concepts") json j {1, 2, 3}; json::const_iterator it1 = j.cbegin(); json::const_iterator it2 = j.cend(); - std::swap(it1, it2); + swap(it1, it2); CHECK(it1 == j.end()); CHECK(it2 == j.begin()); } diff --git a/test/src/unit-modifiers.cpp b/test/src/unit-modifiers.cpp index 9214c608..4b8d0762 100644 --- a/test/src/unit-modifiers.cpp +++ b/test/src/unit-modifiers.cpp @@ -878,7 +878,8 @@ TEST_CASE("modifiers") json j("hello world"); json k(42.23); - std::swap(j, k); + using std::swap; + swap(j, k); CHECK(j == json(42.23)); CHECK(k == json("hello world"));