libstdc++: define std::common_comparison_category for C++20
diff mbox series

Message ID 20191108003215.GA31051@redhat.com
State New
Headers show
Series
  • libstdc++: define std::common_comparison_category for C++20
Related show

Commit Message

Jonathan Wakely Nov. 8, 2019, 12:32 a.m. UTC
* libsupc++/compare (common_comparison_category)
	(common_comparison_category_t): Define for C++20.
	* testsuite/18_support/comparisons/common/1.cc: New test.

Tested powerpc64le-linux, committed to trunk.
commit cb48e7e6d0bbed9eadc34b4318511f3e05ec1b64
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Thu Nov 7 21:33:36 2019 +0000

    libstdc++: define std::common_comparison_category for C++20
    
            * libsupc++/compare (common_comparison_category)
            (common_comparison_category_t): Define for C++20.
            * testsuite/18_support/comparisons/common/1.cc: New test.

Patch
diff mbox series

diff --git a/libstdc++-v3/libsupc++/compare b/libstdc++-v3/libsupc++/compare
index 84cc3f5c85f..94728e29de8 100644
--- a/libstdc++-v3/libsupc++/compare
+++ b/libstdc++-v3/libsupc++/compare
@@ -385,18 +385,81 @@  namespace std
   is_gteq(partial_ordering __cmp) noexcept
   { return __cmp >= 0; }
 
+#if __cpp_lib_concepts
+  namespace __detail
+  {
+    template<typename _Tp>
+      inline constexpr unsigned __cmp_cat_id = 1;
+    template<>
+      inline constexpr unsigned __cmp_cat_id<strong_ordering> = 2;
+    template<>
+      inline constexpr unsigned __cmp_cat_id<weak_ordering> = 4;
+    template<>
+      inline constexpr unsigned __cmp_cat_id<partial_ordering> = 8;
+
+    template<typename... _Ts>
+      constexpr unsigned __cmp_cat_ids()
+      { return (__cmp_cat_id<_Ts> | ...); }
+
+    template<unsigned>
+      struct __common_cmp_cat;
+
+    // If any Ti is not a comparison category type, U is void.
+    template<unsigned _Bits>
+      requires ((_Bits & 1) == 1)
+      struct __common_cmp_cat<_Bits> { using type = void; };
+
+    // Otherwise, if at least one Ti is std::partial_ordering,
+    // U is std::partial_ordering.
+    template<unsigned _Bits>
+      requires ((_Bits & 0b1001) == 0b1000)
+      struct __common_cmp_cat<_Bits> { using type = partial_ordering; };
+
+    // Otherwise, if at least one Ti is std::weak_ordering,
+    // U is std::weak_ordering.
+    template<unsigned _Bits>
+      requires ((_Bits & 0b1101) == 0b0100)
+      struct __common_cmp_cat<_Bits> { using type = weak_ordering; };
+
+    // Otherwise, U is std::strong_ordering.
+    template<>
+      struct __common_cmp_cat<0b0010> { using type = strong_ordering; };
+  } // namespace __detail
+
   // [cmp.common], common comparison category type
   template<typename... _Ts>
     struct common_comparison_category
     {
-      // using type = TODO
+      using type
+	= __detail::__common_cmp_cat<__detail::__cmp_cat_ids<_Ts...>()>::type;
     };
 
+  // Partial specializations for one and zero argument cases.
+
+  template<typename _Tp>
+    struct common_comparison_category<_Tp>
+    { using type = void; };
+
+  template<>
+    struct common_comparison_category<partial_ordering>
+    { using type = partial_ordering; };
+
+  template<>
+    struct common_comparison_category<weak_ordering>
+    { using type = weak_ordering; };
+
+  template<>
+    struct common_comparison_category<strong_ordering>
+    { using type = strong_ordering; };
+
+  template<>
+    struct common_comparison_category<>
+    { using type = strong_ordering; };
+
   template<typename... _Ts>
     using common_comparison_category_t
       = typename common_comparison_category<_Ts...>::type;
 
-#if __cpp_lib_concepts
   namespace __detail
   {
     template<typename _Tp, typename _Cat>
@@ -493,22 +556,22 @@  namespace std
     template<typename _Tp, typename _Up>
       requires (three_way_comparable_with<_Tp, _Up>
 	  || __detail::__3way_builtin_ptr_cmp<_Tp, _Up>)
-    constexpr auto
-    operator()(_Tp&& __t, _Up&& __u) const noexcept
-    {
-      if constexpr (__detail::__3way_builtin_ptr_cmp<_Tp, _Up>)
-	{
-	  auto __pt = static_cast<const volatile void*>(__t);
-	  auto __pu = static_cast<const volatile void*>(__u);
-	  if (__builtin_is_constant_evaluated())
-	    return __pt <=> __pu;
-	  auto __it = reinterpret_cast<__UINTPTR_TYPE__>(__pt);
-	  auto __iu = reinterpret_cast<__UINTPTR_TYPE__>(__pu);
-	  return __it <=> __iu;
-	}
-      else
-	return static_cast<_Tp&&>(__t) <=> static_cast<_Up&&>(__u);
-    }
+      constexpr auto
+      operator()(_Tp&& __t, _Up&& __u) const noexcept
+      {
+	if constexpr (__detail::__3way_builtin_ptr_cmp<_Tp, _Up>)
+	  {
+	    auto __pt = static_cast<const volatile void*>(__t);
+	    auto __pu = static_cast<const volatile void*>(__u);
+	    if (__builtin_is_constant_evaluated())
+	      return __pt <=> __pu;
+	    auto __it = reinterpret_cast<__UINTPTR_TYPE__>(__pt);
+	    auto __iu = reinterpret_cast<__UINTPTR_TYPE__>(__pu);
+	    return __it <=> __iu;
+	  }
+	else
+	  return static_cast<_Tp&&>(__t) <=> static_cast<_Up&&>(__u);
+      }
 
     using is_transparent = void;
   };
diff --git a/libstdc++-v3/testsuite/18_support/comparisons/common/1.cc b/libstdc++-v3/testsuite/18_support/comparisons/common/1.cc
new file mode 100644
index 00000000000..015a8acae97
--- /dev/null
+++ b/libstdc++-v3/testsuite/18_support/comparisons/common/1.cc
@@ -0,0 +1,48 @@ 
+// Copyright (C) 2019 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do compile { target c++2a } }
+
+#include <compare>
+
+template<typename Cat, typename... T>
+constexpr bool check()
+{
+  return std::same_as<Cat, std::common_comparison_category_t<T...>>;
+}
+
+using std::partial_ordering;
+using std::weak_ordering;
+using std::strong_ordering;
+
+static_assert(check<strong_ordering>());
+static_assert(check<void, int>());
+static_assert(check<void, int, int>());
+static_assert(check<void, weak_ordering, int>());
+static_assert(check<void, int, partial_ordering>());
+static_assert(check<partial_ordering, partial_ordering>());
+static_assert(check<partial_ordering, weak_ordering, partial_ordering>());
+
+using PO = std::partial_ordering;
+using WO = std::weak_ordering;
+using SO = std::strong_ordering;
+
+static_assert(check<PO, SO, PO, SO, SO>());
+static_assert(check<PO, SO, PO, SO, WO>());
+static_assert(check<WO, SO, WO, SO, WO>());
+static_assert(check<SO, SO, SO, SO, SO>());