Re: [PATCH] Use if-constexpr instead of overloading for customization point

2019-10-30 Thread Jonathan Wakely

On 30/10/19 17:42 +, 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.



[PATCH] Use if-constexpr instead of overloading for customization point

2019-10-30 Thread Jonathan Wakely

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 
Date:   Wed Oct 30 17:03:46 2019 +

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.

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
+ 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>
+  && is_nothrow_move_assignable_v>;
+ }
+
+  public:
template
  requires __adl_swap<_Tp, _Up>
+ || (same_as<_Tp, _Up> && is_lvalue_reference_v<_Tp>
+ && move_constructible>
+ && 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&&>(__t);
+   __t = static_cast&&>(__u);
+   __u = static_cast&&>(__tmp);
+ }
+ }
 
template
  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
- 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