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 // <tuple> 10 11 // template <class... Types> class tuple; 12 13 // template<class... TTypes, class... UTypes> 14 // auto 15 // operator<=>(const tuple<TTypes...>& t, const tuple<UTypes...>& u); 16 17 // UNSUPPORTED: c++03, c++11, c++14, c++17 18 19 #include "test_macros.h" 20 21 #if defined(TEST_COMPILER_CLANG) || defined(TEST_COMPILER_GCC) 22 #pragma GCC diagnostic ignored "-Wsign-compare" 23 #elif defined(TEST_COMPILER_MSVC) 24 #pragma warning(disable: 4242 4244) // Various truncation warnings 25 #endif 26 27 #include <cassert> 28 #include <compare> 29 #include <limits> 30 #include <tuple> 31 #include <type_traits> // std::is_constant_evaluated 32 33 // A custom three-way result type 34 struct CustomEquality { 35 friend constexpr bool operator==(const CustomEquality&, int) noexcept { return true; } 36 friend constexpr bool operator<(const CustomEquality&, int) noexcept { return false; } 37 friend constexpr bool operator<(int, const CustomEquality&) noexcept { return false; } 38 }; 39 40 constexpr bool test() { 41 // Empty tuple 42 { 43 typedef std::tuple<> T0; 44 // No member types yields strong ordering (all are equal). 45 ASSERT_SAME_TYPE(decltype(T0() <=> T0()), std::strong_ordering); 46 assert((T0() <=> T0()) == std::strong_ordering::equal); 47 } 48 // Mixed types with integers, which compare strongly ordered 49 { 50 typedef std::tuple<long> T1; 51 typedef std::tuple<short> T2; 52 ASSERT_SAME_TYPE(decltype(T1() <=> T2()), std::strong_ordering); 53 assert((T1(1) <=> T2(1)) == std::strong_ordering::equal); 54 assert((T1(1) <=> T2(0)) == std::strong_ordering::greater); 55 assert((T1(1) <=> T2(2)) == std::strong_ordering::less); 56 } 57 { 58 typedef std::tuple<long, unsigned int> T1; 59 typedef std::tuple<short, unsigned long> T2; 60 ASSERT_SAME_TYPE(decltype(T1() <=> T2()), std::strong_ordering); 61 assert((T1(1, 2) <=> T2(1, 2)) == std::strong_ordering::equal); 62 assert((T1(1, 2) <=> T2(0, 2)) == std::strong_ordering::greater); 63 assert((T1(1, 2) <=> T2(2, 2)) == std::strong_ordering::less); 64 assert((T1(1, 2) <=> T2(1, 1)) == std::strong_ordering::greater); 65 assert((T1(1, 2) <=> T2(1, 3)) == std::strong_ordering::less); 66 } 67 { 68 typedef std::tuple<long, int, unsigned short> T1; 69 typedef std::tuple<short, long, unsigned int> T2; 70 ASSERT_SAME_TYPE(decltype(T1() <=> T2()), std::strong_ordering); 71 assert((T1(1, 2, 3) <=> T2(1, 2, 3)) == std::strong_ordering::equal); 72 assert((T1(1, 2, 3) <=> T2(0, 2, 3)) == std::strong_ordering::greater); 73 assert((T1(1, 2, 3) <=> T2(2, 2, 3)) == std::strong_ordering::less); 74 assert((T1(1, 2, 3) <=> T2(1, 1, 3)) == std::strong_ordering::greater); 75 assert((T1(1, 2, 3) <=> T2(1, 3, 3)) == std::strong_ordering::less); 76 assert((T1(1, 2, 3) <=> T2(1, 2, 2)) == std::strong_ordering::greater); 77 assert((T1(1, 2, 3) <=> T2(1, 2, 4)) == std::strong_ordering::less); 78 } 79 // Mixed types with floating point, which compare partially ordered 80 { 81 typedef std::tuple<long> T1; 82 typedef std::tuple<double> T2; 83 ASSERT_SAME_TYPE(decltype(T1() <=> T2()), std::partial_ordering); 84 assert((T1(1) <=> T2(1)) == std::partial_ordering::equivalent); 85 assert((T1(1) <=> T2(0.9)) == std::partial_ordering::greater); 86 assert((T1(1) <=> T2(1.1)) == std::partial_ordering::less); 87 } 88 { 89 typedef std::tuple<long, float> T1; 90 typedef std::tuple<double, unsigned int> T2; 91 ASSERT_SAME_TYPE(decltype(T1() <=> T2()), std::partial_ordering); 92 assert((T1(1, 2) <=> T2(1, 2)) == std::partial_ordering::equivalent); 93 assert((T1(1, 2) <=> T2(0.9, 2)) == std::partial_ordering::greater); 94 assert((T1(1, 2) <=> T2(1.1, 2)) == std::partial_ordering::less); 95 assert((T1(1, 2) <=> T2(1, 1)) == std::partial_ordering::greater); 96 assert((T1(1, 2) <=> T2(1, 3)) == std::partial_ordering::less); 97 } 98 { 99 typedef std::tuple<short, float, double> T1; 100 typedef std::tuple<double, long, unsigned int> T2; 101 ASSERT_SAME_TYPE(decltype(T1() <=> T2()), std::partial_ordering); 102 assert((T1(1, 2, 3) <=> T2(1, 2, 3)) == std::partial_ordering::equivalent); 103 assert((T1(1, 2, 3) <=> T2(0.9, 2, 3)) == std::partial_ordering::greater); 104 assert((T1(1, 2, 3) <=> T2(1.1, 2, 3)) == std::partial_ordering::less); 105 assert((T1(1, 2, 3) <=> T2(1, 1, 3)) == std::partial_ordering::greater); 106 assert((T1(1, 2, 3) <=> T2(1, 3, 3)) == std::partial_ordering::less); 107 assert((T1(1, 2, 3) <=> T2(1, 2, 2)) == std::partial_ordering::greater); 108 assert((T1(1, 2, 3) <=> T2(1, 2, 4)) == std::partial_ordering::less); 109 } 110 { 111 typedef std::tuple<float> T1; 112 typedef std::tuple<double> T2; 113 constexpr double nan = std::numeric_limits<double>::quiet_NaN(); 114 // Comparisons with NaN and non-NaN are non-constexpr in GCC, so both sides must be NaN 115 assert((T1(nan) <=> T2(nan)) == std::partial_ordering::unordered); 116 } 117 { 118 typedef std::tuple<double, double> T1; 119 typedef std::tuple<float, float> T2; 120 constexpr double nan = std::numeric_limits<double>::quiet_NaN(); 121 assert((T1(nan, 2) <=> T2(nan, 2)) == std::partial_ordering::unordered); 122 assert((T1(1, nan) <=> T2(1, nan)) == std::partial_ordering::unordered); 123 } 124 { 125 typedef std::tuple<double, float, float> T1; 126 typedef std::tuple<double, double, float> T2; 127 constexpr double nan = std::numeric_limits<double>::quiet_NaN(); 128 assert((T1(nan, 2, 3) <=> T2(nan, 2, 3)) == std::partial_ordering::unordered); 129 assert((T1(1, nan, 3) <=> T2(1, nan, 3)) == std::partial_ordering::unordered); 130 assert((T1(1, 2, nan) <=> T2(1, 2, nan)) == std::partial_ordering::unordered); 131 } 132 // Ordering classes and synthesized three way comparison 133 { 134 typedef std::tuple<long, int, unsigned int> T1; 135 typedef std::tuple<int, long, unsigned short> T2; 136 // All strongly ordered members yields strong ordering. 137 ASSERT_SAME_TYPE(decltype(T1() <=> T2()), std::strong_ordering); 138 } 139 { 140 struct WeakSpaceship { 141 constexpr bool operator==(const WeakSpaceship&) const { return true; } 142 constexpr std::weak_ordering operator<=>(const WeakSpaceship&) const { return std::weak_ordering::equivalent; } 143 }; 144 { 145 typedef std::tuple<int, unsigned int, WeakSpaceship> T1; 146 typedef std::tuple<int, unsigned long, WeakSpaceship> T2; 147 // Strongly ordered members and a weakly ordered member yields weak ordering. 148 ASSERT_SAME_TYPE(decltype(T1() <=> T2()), std::weak_ordering); 149 } 150 { 151 typedef std::tuple<unsigned int, int, WeakSpaceship> T1; 152 typedef std::tuple<double, long, WeakSpaceship> T2; 153 // Doubles are partially ordered, so one partial, one strong, and one weak ordering 154 // yields partial ordering. 155 ASSERT_SAME_TYPE(decltype(T1() <=> T2()), std::partial_ordering); 156 } 157 } 158 { 159 struct NoSpaceship { 160 constexpr bool operator==(const NoSpaceship&) const { return true; } 161 constexpr bool operator<(const NoSpaceship&) const { return false; } 162 }; 163 typedef std::tuple<int, unsigned int, NoSpaceship> T1; 164 typedef std::tuple<int, unsigned long, NoSpaceship> T2; 165 // Strongly ordered members and a weakly ordered member (synthesized) yields weak ordering. 166 ASSERT_SAME_TYPE(decltype(T1() <=> T2()), std::weak_ordering); 167 } 168 { 169 struct SpaceshipNoEquals { 170 constexpr std::strong_ordering operator<=>(const SpaceshipNoEquals&) const { return std::strong_ordering::equal; } 171 constexpr bool operator<(const SpaceshipNoEquals&) const { return false; } 172 }; 173 typedef std::tuple<int, unsigned int, SpaceshipNoEquals> T1; 174 typedef std::tuple<int, unsigned long, SpaceshipNoEquals> T2; 175 // Spaceship operator with no == operator falls back on the < operator and weak ordering. 176 ASSERT_SAME_TYPE(decltype(T1() <=> T2()), std::weak_ordering); 177 } 178 { 179 struct CustomSpaceship { 180 constexpr CustomEquality operator<=>(const CustomSpaceship&) const { return CustomEquality(); } 181 }; 182 typedef std::tuple<int, unsigned int, CustomSpaceship> T1; 183 typedef std::tuple<short, unsigned long, CustomSpaceship> T2; 184 typedef std::tuple<CustomSpaceship> T3; 185 // Custom three way return types cannot be used in synthesized three way comparison, 186 // but they can be used for (rewritten) operator< when synthesizing a weak ordering. 187 ASSERT_SAME_TYPE(decltype(T1() <=> T2()), std::weak_ordering); 188 ASSERT_SAME_TYPE(decltype(T3() <=> T3()), std::weak_ordering); 189 } 190 { 191 typedef std::tuple<long, int> T1; 192 typedef std::tuple<long, unsigned int> T2; 193 // Even with the warning suppressed (-Wno-sign-compare) there should still be no <=> operator 194 // between signed and unsigned types, so we should end up with a synthesized weak ordering. 195 ASSERT_SAME_TYPE(decltype(T1() <=> T2()), std::weak_ordering); 196 } 197 198 #ifdef TEST_COMPILER_GCC 199 // GCC cannot evaluate NaN @ non-NaN constexpr, so test that runtime-only. 200 if (!std::is_constant_evaluated()) 201 #endif 202 { 203 { 204 typedef std::tuple<double> T1; 205 typedef std::tuple<int> T2; 206 constexpr double nan = std::numeric_limits<double>::quiet_NaN(); 207 ASSERT_SAME_TYPE(decltype(T1() <=> T2()), std::partial_ordering); 208 assert((T1(nan) <=> T2(1)) == std::partial_ordering::unordered); 209 } 210 { 211 typedef std::tuple<double, double> T1; 212 typedef std::tuple<int, int> T2; 213 constexpr double nan = std::numeric_limits<double>::quiet_NaN(); 214 ASSERT_SAME_TYPE(decltype(T1() <=> T2()), std::partial_ordering); 215 assert((T1(nan, 2) <=> T2(1, 2)) == std::partial_ordering::unordered); 216 assert((T1(1, nan) <=> T2(1, 2)) == std::partial_ordering::unordered); 217 } 218 { 219 typedef std::tuple<double, double, double> T1; 220 typedef std::tuple<int, int, int> T2; 221 constexpr double nan = std::numeric_limits<double>::quiet_NaN(); 222 ASSERT_SAME_TYPE(decltype(T1() <=> T2()), std::partial_ordering); 223 assert((T1(nan, 2, 3) <=> T2(1, 2, 3)) == std::partial_ordering::unordered); 224 assert((T1(1, nan, 3) <=> T2(1, 2, 3)) == std::partial_ordering::unordered); 225 assert((T1(1, 2, nan) <=> T2(1, 2, 3)) == std::partial_ordering::unordered); 226 } 227 } 228 229 return true; 230 } 231 232 int main(int, char**) { 233 test(); 234 static_assert(test()); 235 236 return 0; 237 } 238