1 //===----------------------------------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #ifndef _LIBCPP___COMPARE_COMMON_COMPARISON_CATEGORY_H
10 #define _LIBCPP___COMPARE_COMMON_COMPARISON_CATEGORY_H
11 
12 #include <__compare/ordering.h>
13 #include <__config>
14 #include <__type_traits/is_same.h>
15 #include <cstddef>
16 
17 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
18 #  pragma GCC system_header
19 #endif
20 
21 _LIBCPP_BEGIN_NAMESPACE_STD
22 
23 #if _LIBCPP_STD_VER >= 20
24 
25 namespace __comp_detail {
26 
27 enum _ClassifyCompCategory : unsigned { _None, _PartialOrd, _WeakOrd, _StrongOrd, _CCC_Size };
28 
29 template <class _Tp>
__type_to_enum()30 _LIBCPP_HIDE_FROM_ABI constexpr _ClassifyCompCategory __type_to_enum() noexcept {
31   if (is_same_v<_Tp, partial_ordering>)
32     return _PartialOrd;
33   if (is_same_v<_Tp, weak_ordering>)
34     return _WeakOrd;
35   if (is_same_v<_Tp, strong_ordering>)
36     return _StrongOrd;
37   return _None;
38 }
39 
40 template <size_t _Size>
41 _LIBCPP_HIDE_FROM_ABI constexpr _ClassifyCompCategory
__compute_comp_type(const _ClassifyCompCategory (& __types)[_Size])42 __compute_comp_type(const _ClassifyCompCategory (&__types)[_Size]) {
43   int __seen[_CCC_Size] = {};
44   for (auto __type : __types)
45     ++__seen[__type];
46   if (__seen[_None])
47     return _None;
48   if (__seen[_PartialOrd])
49     return _PartialOrd;
50   if (__seen[_WeakOrd])
51     return _WeakOrd;
52   return _StrongOrd;
53 }
54 
55 template <class... _Ts, bool _False = false>
__get_comp_type()56 _LIBCPP_HIDE_FROM_ABI constexpr auto __get_comp_type() {
57   using _CCC                    = _ClassifyCompCategory;
58   constexpr _CCC __type_kinds[] = {_StrongOrd, __type_to_enum<_Ts>()...};
59   constexpr _CCC __cat          = __comp_detail::__compute_comp_type(__type_kinds);
60   if constexpr (__cat == _None)
61     return void();
62   else if constexpr (__cat == _PartialOrd)
63     return partial_ordering::equivalent;
64   else if constexpr (__cat == _WeakOrd)
65     return weak_ordering::equivalent;
66   else if constexpr (__cat == _StrongOrd)
67     return strong_ordering::equivalent;
68   else
69     static_assert(_False, "unhandled case");
70 }
71 } // namespace __comp_detail
72 
73 // [cmp.common], common comparison category type
74 template <class... _Ts>
75 struct _LIBCPP_TEMPLATE_VIS common_comparison_category {
76   using type = decltype(__comp_detail::__get_comp_type<_Ts...>());
77 };
78 
79 template <class... _Ts>
80 using common_comparison_category_t = typename common_comparison_category<_Ts...>::type;
81 
82 #endif // _LIBCPP_STD_VER >= 20
83 
84 _LIBCPP_END_NAMESPACE_STD
85 
86 #endif // _LIBCPP___COMPARE_COMMON_COMPARISON_CATEGORY_H
87