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// <utility>
10
11// template <class T1, class T2> struct pair
12
13// template <class T1, class T2, class U1, class U2>
14// constexpr common_comparison_category_t<synth-three-way-result<T1, U1>,synth-three-way-result<T2, U2>>
15// operator<=>(const pair<T1,T2>&, const pair<U1,U2>&);
16
17// UNSUPPORTED: c++03, c++11, c++14, c++17
18
19#include <cassert>
20#include <compare>
21#include <limits>
22#include <type_traits> // std::is_constant_evaluated
23#include <utility>
24#include <string>
25
26#include "test_macros.h"
27
28template <class T>
29concept HasEqual = requires(T t) { t == t; };
30template <class T>
31concept HasLess = requires(T t) { t < t; };
32template <class T, class U = T>
33concept HasSpaceship = requires(T t, U u) { t <=> u; };
34
35constexpr bool test() {
36 {
37 // Pairs of different types should compare with strong ordering.
38 using P1 = std::pair<int, int>;
39 using P2 = std::pair<long long, long long>;
40 ASSERT_SAME_TYPE(decltype(P1() <=> P2()), std::strong_ordering);
41 assert((P1(1, 1) <=> P2(1, 2)) == std::strong_ordering::less);
42 assert((P1(2, 1) <=> P2(1, 2)) == std::strong_ordering::greater);
43 assert((P1(0, 0) <=> P2(0, 0)) == std::strong_ordering::equal);
44 }
45 {
46 // Pairs of different types should compare with partial ordering.
47 using P1 = std::pair<int, int>;
48 using P2 = std::pair<double, double>;
49 ASSERT_SAME_TYPE(decltype(P1() <=> P2()), std::partial_ordering);
50 assert((P1(1, 1) <=> P2(1.0, 2.0)) == std::partial_ordering::less);
51 assert((P1(2, 1) <=> P2(1.0, 2.0)) == std::partial_ordering::greater);
52 assert((P1(0, 0) <=> P2(0.0, 0.0)) == std::partial_ordering::equivalent);
53 }
54 { static_assert(!HasSpaceship<std::pair<int, int>, std::pair<std::string, int>>); }
55 {
56 // Pairs of types that both have strong ordering should compare with strong ordering.
57 using P = std::pair<int, int>;
58 ASSERT_SAME_TYPE(decltype(P() <=> P()), std::strong_ordering);
59 assert((P(1, 1) <=> P(1, 2)) == std::strong_ordering::less);
60 assert((P(2, 1) <=> P(1, 2)) == std::strong_ordering::greater);
61 assert((P(0, 0) <=> P(0, 0)) == std::strong_ordering::equal);
62 }
63 {
64 // Pairs of int and a type with no spaceship operator should compare with weak ordering.
65 struct NoSpaceship {
66 int value;
67 constexpr bool operator==(const NoSpaceship&) const = default;
68 constexpr bool operator<(const NoSpaceship& other) const { return value < other.value; }
69 };
70 using P = std::pair<int, NoSpaceship>;
71 ASSERT_SAME_TYPE(decltype(P() <=> P()), std::weak_ordering);
72 assert((P(1, {1}) <=> P(1, {2})) == std::weak_ordering::less);
73 assert((P(2, {1}) <=> P(1, {2})) == std::weak_ordering::greater);
74 assert((P(0, {0}) <=> P(0, {0})) == std::weak_ordering::equivalent);
75 }
76 {
77 // Pairs of int (strongly ordered) and double (partially ordered) should compare with partial ordering.
78 using P = std::pair<int, double>;
79 constexpr double nan = std::numeric_limits<double>::quiet_NaN();
80 ASSERT_SAME_TYPE(decltype(P() <=> P()), std::partial_ordering);
81 assert((P(1, 1.0) <=> P(1, 2.0)) == std::partial_ordering::less);
82 assert((P(1, 1.0) <=> P(1, 1.0)) == std::partial_ordering::equivalent);
83 assert((P(1, -0.0) <=> P(1, 0.0)) == std::partial_ordering::equivalent);
84 assert((P(1, 2.0) <=> P(1, 1.0)) == std::partial_ordering::greater);
85 assert((P(1, nan) <=> P(2, nan)) == std::partial_ordering::less);
86 assert((P(2, nan) <=> P(1, nan)) == std::partial_ordering::greater);
87 assert((P(1, nan) <=> P(1, nan)) == std::partial_ordering::unordered);
88 }
89 {
90 using P = std::pair<double, int>;
91 constexpr double nan = std::numeric_limits<double>::quiet_NaN();
92 ASSERT_SAME_TYPE(decltype(P() <=> P()), std::partial_ordering);
93 assert((P(2.0, 1) <=> P(1.0, 2)) == std::partial_ordering::greater);
94 assert((P(1.0, 1) <=> P(1.0, 2)) == std::partial_ordering::less);
95 assert((P(nan, 1) <=> P(nan, 2)) == std::partial_ordering::unordered);
96 }
97 {
98 struct NoRelative {
99 constexpr bool operator==(const NoRelative&) const;
100 };
101 static_assert(HasEqual<std::pair<int, NoRelative>>);
102 static_assert(!HasLess<std::pair<int, NoRelative>>);
103 static_assert(!HasSpaceship<std::pair<int, NoRelative>>);
104 }
105 {
106 struct NoLessThan {
107 constexpr bool operator==(const NoLessThan&) const;
108 constexpr bool operator>(const NoLessThan&) const;
109 };
110 static_assert(HasEqual<std::pair<int, NoLessThan>>);
111 static_assert(!HasLess<std::pair<int, NoLessThan>>);
112 static_assert(!HasSpaceship<std::pair<int, NoLessThan>>);
113 }
114
115#ifdef TEST_COMPILER_GCC
116 // GCC cannot evaluate NaN @ non-NaN constexpr, so test that runtime-only.
117 if (!std::is_constant_evaluated())
118#endif
119 {
120 {
121 using P = std::pair<int, double>;
122 constexpr double nan = std::numeric_limits<double>::quiet_NaN();
123 assert((P(1, 2.0) <=> P(1, nan)) == std::partial_ordering::unordered);
124 }
125 {
126 using P = std::pair<double, int>;
127 constexpr double nan = std::numeric_limits<double>::quiet_NaN();
128 assert((P(1.0, 1) <=> P(nan, 2)) == std::partial_ordering::unordered);
129 }
130 }
131
132 return true;
133}
134
135int main(int, char**) {
136 test();
137 static_assert(test());
138
139 return 0;
140}
141

source code of libcxx/test/std/utilities/utility/pairs/pairs.spec/three_way_comparison.pass.cpp