diff mbox series

Use if-constexpr instead of overloading for customization point

Message ID 20191030174223.GK4169@redhat.com
State New
Headers show
Series Use if-constexpr instead of overloading for customization point | expand

Commit Message

Jonathan Wakely Oct. 30, 2019, 5:42 p.m. UTC
This combines two of the std::ranges::swap.operator() overloads into a
single function template. Using if-constexpr to choose between
implementations should give the compiler less work to do than using
overloading.

	* include/std/concepts (std::ranges::swap): Use a single overload for
	the non-array cases, and switch using if-constexpr.

Tested powerpc64le-linux, committed to trunk.
commit 1a09c76c7256ef400ef8be96937b25ab3ed6d585
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Wed Oct 30 17:03:46 2019 +0000

    Use if-constexpr instead of overloading for customization point
    
    This combines two of the std::ranges::swap.operator() overloads into a
    single function template. Using if-constexpr to choose between
    implementations should give the compiler less work to do than using
    overloading.
    
            * include/std/concepts (std::ranges::swap): Use a single overload for
            the non-array cases, and switch using if-constexpr.

Comments

Jonathan Wakely Oct. 30, 2019, 5:43 p.m. UTC | #1
On 30/10/19 17:42 +0000, Jonathan Wakely wrote:
>This combines two of the std::ranges::swap.operator() overloads into a
>single function template. Using if-constexpr to choose between
>implementations should give the compiler less work to do than using
>overloading.

P.S. this is how all the other std::ranges::* customization points are
defined, but I only started doing that after adding std::ranges::swap.
Now they're all done this way.
diff mbox series

Patch

diff --git a/libstdc++-v3/include/std/concepts b/libstdc++-v3/include/std/concepts
index 68cbba9b8a7..c4acfd2e212 100644
--- a/libstdc++-v3/include/std/concepts
+++ b/libstdc++-v3/include/std/concepts
@@ -173,12 +173,37 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
       struct _Swap
       {
+      private:
+	template<typename _Tp, typename _Up>
+	  static constexpr bool
+	  _S_noexcept()
+	  {
+	    if constexpr (__adl_swap<_Tp, _Up>)
+	      return noexcept(swap(std::declval<_Tp>(), std::declval<_Up>()));
+	    else
+	      return is_nothrow_move_constructible_v<remove_reference_t<_Tp>>
+		   && is_nothrow_move_assignable_v<remove_reference_t<_Tp>>;
+	  }
+
+      public:
 	template<typename _Tp, typename _Up>
 	  requires __adl_swap<_Tp, _Up>
+	  || (same_as<_Tp, _Up> && is_lvalue_reference_v<_Tp>
+	      && move_constructible<remove_reference_t<_Tp>>
+	      && assignable_from<_Tp, remove_reference_t<_Tp>>)
 	  constexpr void
 	  operator()(_Tp&& __t, _Up&& __u) const
-	  noexcept(noexcept(swap(std::declval<_Tp>(), std::declval<_Up>())))
-	  { swap(static_cast<_Tp&&>(__t), static_cast<_Up&&>(__u)); }
+	  noexcept(_S_noexcept<_Tp, _Up>())
+	  {
+	    if constexpr (__adl_swap<_Tp, _Up>)
+	      swap(static_cast<_Tp&&>(__t), static_cast<_Up&&>(__u));
+	    else
+	      {
+		auto __tmp = static_cast<remove_reference_t<_Tp>&&>(__t);
+		__t = static_cast<remove_reference_t<_Tp>&&>(__u);
+		__u = static_cast<remove_reference_t<_Tp>&&>(__tmp);
+	      }
+	  }
 
 	template<typename _Tp, typename _Up, size_t _Num>
 	  requires requires(const _Swap& __swap, _Tp& __e1, _Up& __e2) {
@@ -191,19 +216,6 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	    for (size_t __n = 0; __n < _Num; ++__n)
 	      (*this)(__e1[__n], __e2[__n]);
 	  }
-
-	template<typename _Tp>
-	  requires (!__adl_swap<_Tp&, _Tp&>
-	    && move_constructible<_Tp> && assignable_from<_Tp&, _Tp>)
-	  constexpr void
-	  operator()(_Tp& __e1, _Tp& __e2) const
-	  noexcept(is_nothrow_move_constructible_v<_Tp>
-		   && is_nothrow_move_assignable_v<_Tp>)
-	  {
-	    _Tp __tmp = static_cast<_Tp&&>(__e1);
-	    __e1 = static_cast<_Tp&&>(__e2);
-	    __e2 = static_cast<_Tp&&>(__tmp);
-	  }
       };
     } // namespace __cust_swap