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 // UNSUPPORTED: c++03, c++11, c++14, c++17
10
11 // <variant>
12
13 // template <class... Types> class variant;
14
15 // template <class... Types> requires (three_way_comparable<Types> && ...)
16 // constexpr std::common_comparison_category_t<
17 // std::compare_three_way_result_t<Types>...>
18 // operator<=>(const variant<Types...>& t, const variant<Types...>& u);
19
20 #include <cassert>
21 #include <limits>
22 #include <type_traits>
23 #include <utility>
24 #include <variant>
25
26 #include "test_macros.h"
27 #include "test_comparisons.h"
28
29 #ifndef TEST_HAS_NO_EXCEPTIONS
30 // MakeEmptyT throws in operator=(&&), so we can move to it to create valueless-by-exception variants.
31 struct MakeEmptyT {
32 MakeEmptyT() = default;
MakeEmptyTMakeEmptyT33 MakeEmptyT(MakeEmptyT&&) { throw 42; }
operator =MakeEmptyT34 MakeEmptyT& operator=(MakeEmptyT&&) { throw 42; }
35 };
operator ==(const MakeEmptyT &,const MakeEmptyT &)36 inline bool operator==(const MakeEmptyT&, const MakeEmptyT&) {
37 assert(false);
38 return false;
39 }
operator <=>(const MakeEmptyT &,const MakeEmptyT &)40 inline std::weak_ordering operator<=>(const MakeEmptyT&, const MakeEmptyT&) {
41 assert(false);
42 return std::weak_ordering::equivalent;
43 }
44
45 template <class Variant>
makeEmpty(Variant & v)46 void makeEmpty(Variant& v) {
47 Variant v2(std::in_place_type<MakeEmptyT>);
48 try {
49 v = std::move(v2);
50 assert(false);
51 } catch (...) {
52 assert(v.valueless_by_exception());
53 }
54 }
55
test_empty()56 void test_empty() {
57 {
58 using V = std::variant<int, MakeEmptyT>;
59 V v1;
60 V v2;
61 makeEmpty(v2);
62 assert(testOrder(v1, v2, std::weak_ordering::greater));
63 }
64 {
65 using V = std::variant<int, MakeEmptyT>;
66 V v1;
67 makeEmpty(v1);
68 V v2;
69 assert(testOrder(v1, v2, std::weak_ordering::less));
70 }
71 {
72 using V = std::variant<int, MakeEmptyT>;
73 V v1;
74 makeEmpty(v1);
75 V v2;
76 makeEmpty(v2);
77 assert(testOrder(v1, v2, std::weak_ordering::equivalent));
78 }
79 }
80 #endif // TEST_HAS_NO_EXCEPTIONS
81
82 template <class T1, class T2, class Order>
test_with_types()83 constexpr bool test_with_types() {
84 using V = std::variant<T1, T2>;
85 AssertOrderReturn<Order, V>();
86 { // same index, same value
87 constexpr V v1(std::in_place_index<0>, T1{1});
88 constexpr V v2(std::in_place_index<0>, T1{1});
89 assert(testOrder(v1, v2, Order::equivalent));
90 }
91 { // same index, value < other_value
92 constexpr V v1(std::in_place_index<0>, T1{0});
93 constexpr V v2(std::in_place_index<0>, T1{1});
94 assert(testOrder(v1, v2, Order::less));
95 }
96 { // same index, value > other_value
97 constexpr V v1(std::in_place_index<0>, T1{1});
98 constexpr V v2(std::in_place_index<0>, T1{0});
99 assert(testOrder(v1, v2, Order::greater));
100 }
101 { // LHS.index() < RHS.index()
102 constexpr V v1(std::in_place_index<0>, T1{0});
103 constexpr V v2(std::in_place_index<1>, T2{0});
104 assert(testOrder(v1, v2, Order::less));
105 }
106 { // LHS.index() > RHS.index()
107 constexpr V v1(std::in_place_index<1>, T2{0});
108 constexpr V v2(std::in_place_index<0>, T1{0});
109 assert(testOrder(v1, v2, Order::greater));
110 }
111
112 return true;
113 }
114
test_three_way()115 constexpr bool test_three_way() {
116 assert((test_with_types<int, double, std::partial_ordering>()));
117 assert((test_with_types<int, long, std::strong_ordering>()));
118
119 {
120 using V = std::variant<int, double>;
121 constexpr double nan = std::numeric_limits<double>::quiet_NaN();
122 {
123 constexpr V v1(std::in_place_type<int>, 1);
124 constexpr V v2(std::in_place_type<double>, nan);
125 assert(testOrder(v1, v2, std::partial_ordering::less));
126 }
127 {
128 constexpr V v1(std::in_place_type<double>, nan);
129 constexpr V v2(std::in_place_type<int>, 2);
130 assert(testOrder(v1, v2, std::partial_ordering::greater));
131 }
132 {
133 constexpr V v1(std::in_place_type<double>, nan);
134 constexpr V v2(std::in_place_type<double>, nan);
135 assert(testOrder(v1, v2, std::partial_ordering::unordered));
136 }
137 }
138
139 return true;
140 }
141
142 // SFINAE tests
143 template <class T, class U = T>
144 concept has_three_way_op = requires (T& t, U& u) { t <=> u; };
145
146 // std::three_way_comparable is a more stringent requirement that demands
147 // operator== and a few other things.
148 using std::three_way_comparable;
149
150 struct HasSimpleOrdering {
151 constexpr bool operator==(const HasSimpleOrdering&) const;
152 constexpr bool operator<(const HasSimpleOrdering&) const;
153 };
154
155 struct HasOnlySpaceship {
156 constexpr bool operator==(const HasOnlySpaceship&) const = delete;
157 constexpr std::weak_ordering operator<=>(const HasOnlySpaceship&) const;
158 };
159
160 struct HasFullOrdering {
161 constexpr bool operator==(const HasFullOrdering&) const;
162 constexpr std::weak_ordering operator<=>(const HasFullOrdering&) const;
163 };
164
165 // operator<=> must resolve the return types of all its union types'
166 // operator<=>s to determine its own return type, so it is detectable by SFINAE
167 static_assert(!has_three_way_op<HasSimpleOrdering>);
168 static_assert(!has_three_way_op<std::variant<int, HasSimpleOrdering>>);
169
170 static_assert(!three_way_comparable<HasSimpleOrdering>);
171 static_assert(!three_way_comparable<std::variant<int, HasSimpleOrdering>>);
172
173 static_assert(has_three_way_op<HasOnlySpaceship>);
174 static_assert(!has_three_way_op<std::variant<int, HasOnlySpaceship>>);
175
176 static_assert(!three_way_comparable<HasOnlySpaceship>);
177 static_assert(!three_way_comparable<std::variant<int, HasOnlySpaceship>>);
178
179 static_assert( has_three_way_op<HasFullOrdering>);
180 static_assert( has_three_way_op<std::variant<int, HasFullOrdering>>);
181
182 static_assert( three_way_comparable<HasFullOrdering>);
183 static_assert( three_way_comparable<std::variant<int, HasFullOrdering>>);
184
main(int,char **)185 int main(int, char**) {
186 test_three_way();
187 static_assert(test_three_way());
188
189 #ifndef TEST_HAS_NO_EXCEPTIONS
190 test_empty();
191 #endif // TEST_HAS_NO_EXCEPTIONS
192
193 return 0;
194 }
195