libstdc++: define std::common_comparison_category for C++20
authorJonathan Wakely <jwakely@redhat.com>
Fri, 8 Nov 2019 00:37:08 +0000 (00:37 +0000)
committerJonathan Wakely <redi@gcc.gnu.org>
Fri, 8 Nov 2019 00:37:08 +0000 (00:37 +0000)
* libsupc++/compare (common_comparison_category)
(common_comparison_category_t): Define for C++20.
* testsuite/18_support/comparisons/common/1.cc: New test.

From-SVN: r277943

libstdc++-v3/ChangeLog
libstdc++-v3/libsupc++/compare
libstdc++-v3/testsuite/18_support/comparisons/common/1.cc [new file with mode: 0644]

index 31399142ab8df7e747bf0c884abf9671c20af61b..65e55d097a64dbb24c6b7c0265de8a2e251dc229 100644 (file)
@@ -1,5 +1,9 @@
 2019-11-07  Jonathan Wakely  <jwakely@redhat.com>
 
+       * libsupc++/compare (common_comparison_category)
+       (common_comparison_category_t): Define for C++20.
+       * testsuite/18_support/comparisons/common/1.cc: New test.
+
        * include/bits/stl_algo.h (for_each_n): Handle negative count.
        * testsuite/25_algorithms/for_each/for_each_n_debug.cc: New test.
 
index 84cc3f5c85fe0aa37cc776ef73759e42a250ded7..94728e29de80a1c51e2dbd9aa93aa15bdf464b0e 100644 (file)
@@ -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 (file)
index 0000000..015a8ac
--- /dev/null
@@ -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>());