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
10
11// <variant>
12
13// template <class ...Types>
14// constexpr bool
15// operator==(variant<Types...> const&, variant<Types...> const&) noexcept;
16//
17// template <class ...Types>
18// constexpr bool
19// operator!=(variant<Types...> const&, variant<Types...> const&) noexcept;
20//
21// template <class ...Types>
22// constexpr bool
23// operator<(variant<Types...> const&, variant<Types...> const&) noexcept;
24//
25// template <class ...Types>
26// constexpr bool
27// operator>(variant<Types...> const&, variant<Types...> const&) noexcept;
28//
29// template <class ...Types>
30// constexpr bool
31// operator<=(variant<Types...> const&, variant<Types...> const&) noexcept;
32//
33// template <class ...Types>
34// constexpr bool
35// operator>=(variant<Types...> const&, variant<Types...> const&) noexcept;
36
37#include <cassert>
38#include <type_traits>
39#include <utility>
40#include <variant>
41
42#include "test_comparisons.h"
43#include "test_macros.h"
44
45#if TEST_STD_VER >= 26
46
47// Test SFINAE.
48
49// ==
50static_assert(HasOperatorEqual<std::variant<EqualityComparable>>);
51static_assert(HasOperatorEqual<std::variant<EqualityComparable, int, long>>);
52
53static_assert(!HasOperatorEqual<std::variant<NonComparable>>);
54static_assert(!HasOperatorEqual<std::variant<NonComparable, EqualityComparable>>);
55
56// >
57static_assert(HasOperatorGreaterThan<std::variant<ThreeWayComparable>>);
58static_assert(HasOperatorGreaterThan<std::variant<ThreeWayComparable, int, long>>);
59
60static_assert(!HasOperatorGreaterThan<std::variant<NonComparable>>);
61static_assert(!HasOperatorGreaterThan<std::variant<NonComparable, ThreeWayComparable>>);
62
63// >=
64static_assert(HasOperatorGreaterThanEqual<std::variant<ThreeWayComparable>>);
65static_assert(HasOperatorGreaterThanEqual<std::variant<ThreeWayComparable, int, long>>);
66
67static_assert(!HasOperatorGreaterThanEqual<std::variant<NonComparable>>);
68static_assert(!HasOperatorGreaterThanEqual<std::variant<NonComparable, ThreeWayComparable>>);
69
70// <
71static_assert(HasOperatorLessThan<std::variant<ThreeWayComparable>>);
72static_assert(HasOperatorLessThan<std::variant<ThreeWayComparable, int, long>>);
73
74static_assert(!HasOperatorLessThan<std::variant<NonComparable>>);
75static_assert(!HasOperatorLessThan<std::variant<NonComparable, ThreeWayComparable>>);
76
77// <=
78static_assert(HasOperatorLessThanEqual<std::variant<ThreeWayComparable>>);
79static_assert(HasOperatorLessThanEqual<std::variant<ThreeWayComparable, int, long>>);
80
81static_assert(!HasOperatorLessThanEqual<std::variant<NonComparable>>);
82static_assert(!HasOperatorLessThanEqual<std::variant<NonComparable, ThreeWayComparable>>);
83
84// !=
85static_assert(HasOperatorNotEqual<std::variant<EqualityComparable>>);
86static_assert(HasOperatorNotEqual<std::variant<EqualityComparable, int, long>>);
87
88static_assert(!HasOperatorNotEqual<std::variant<NonComparable>>);
89static_assert(!HasOperatorNotEqual<std::variant<NonComparable, EqualityComparable>>);
90
91#endif
92
93#ifndef TEST_HAS_NO_EXCEPTIONS
94struct MakeEmptyT {
95 MakeEmptyT() = default;
96 MakeEmptyT(MakeEmptyT &&) { throw 42; }
97 MakeEmptyT &operator=(MakeEmptyT &&) { throw 42; }
98};
99inline bool operator==(const MakeEmptyT &, const MakeEmptyT &) {
100 assert(false);
101 return false;
102}
103inline bool operator!=(const MakeEmptyT &, const MakeEmptyT &) {
104 assert(false);
105 return false;
106}
107inline bool operator<(const MakeEmptyT &, const MakeEmptyT &) {
108 assert(false);
109 return false;
110}
111inline bool operator<=(const MakeEmptyT &, const MakeEmptyT &) {
112 assert(false);
113 return false;
114}
115inline bool operator>(const MakeEmptyT &, const MakeEmptyT &) {
116 assert(false);
117 return false;
118}
119inline bool operator>=(const MakeEmptyT &, const MakeEmptyT &) {
120 assert(false);
121 return false;
122}
123
124template <class Variant> void makeEmpty(Variant &v) {
125 Variant v2(std::in_place_type<MakeEmptyT>);
126 try {
127 v = std::move(v2);
128 assert(false);
129 } catch (...) {
130 assert(v.valueless_by_exception());
131 }
132}
133#endif // TEST_HAS_NO_EXCEPTIONS
134
135struct MyBool {
136 bool value;
137 constexpr explicit MyBool(bool v) : value(v) {}
138 constexpr operator bool() const noexcept { return value; }
139};
140
141struct ComparesToMyBool {
142 int value = 0;
143};
144inline constexpr MyBool operator==(const ComparesToMyBool& LHS, const ComparesToMyBool& RHS) noexcept {
145 return MyBool(LHS.value == RHS.value);
146}
147inline constexpr MyBool operator!=(const ComparesToMyBool& LHS, const ComparesToMyBool& RHS) noexcept {
148 return MyBool(LHS.value != RHS.value);
149}
150inline constexpr MyBool operator<(const ComparesToMyBool& LHS, const ComparesToMyBool& RHS) noexcept {
151 return MyBool(LHS.value < RHS.value);
152}
153inline constexpr MyBool operator<=(const ComparesToMyBool& LHS, const ComparesToMyBool& RHS) noexcept {
154 return MyBool(LHS.value <= RHS.value);
155}
156inline constexpr MyBool operator>(const ComparesToMyBool& LHS, const ComparesToMyBool& RHS) noexcept {
157 return MyBool(LHS.value > RHS.value);
158}
159inline constexpr MyBool operator>=(const ComparesToMyBool& LHS, const ComparesToMyBool& RHS) noexcept {
160 return MyBool(LHS.value >= RHS.value);
161}
162
163template <class T1, class T2>
164void test_equality_basic() {
165 {
166 using V = std::variant<T1, T2>;
167 constexpr V v1(std::in_place_index<0>, T1{42});
168 constexpr V v2(std::in_place_index<0>, T1{42});
169 static_assert(v1 == v2, "");
170 static_assert(v2 == v1, "");
171 static_assert(!(v1 != v2), "");
172 static_assert(!(v2 != v1), "");
173 }
174 {
175 using V = std::variant<T1, T2>;
176 constexpr V v1(std::in_place_index<0>, T1{42});
177 constexpr V v2(std::in_place_index<0>, T1{43});
178 static_assert(!(v1 == v2), "");
179 static_assert(!(v2 == v1), "");
180 static_assert(v1 != v2, "");
181 static_assert(v2 != v1, "");
182 }
183 {
184 using V = std::variant<T1, T2>;
185 constexpr V v1(std::in_place_index<0>, T1{42});
186 constexpr V v2(std::in_place_index<1>, T2{42});
187 static_assert(!(v1 == v2), "");
188 static_assert(!(v2 == v1), "");
189 static_assert(v1 != v2, "");
190 static_assert(v2 != v1, "");
191 }
192 {
193 using V = std::variant<T1, T2>;
194 constexpr V v1(std::in_place_index<1>, T2{42});
195 constexpr V v2(std::in_place_index<1>, T2{42});
196 static_assert(v1 == v2, "");
197 static_assert(v2 == v1, "");
198 static_assert(!(v1 != v2), "");
199 static_assert(!(v2 != v1), "");
200 }
201}
202
203void test_equality() {
204 test_equality_basic<int, long>();
205 test_equality_basic<ComparesToMyBool, int>();
206 test_equality_basic<int, ComparesToMyBool>();
207 test_equality_basic<ComparesToMyBool, ComparesToMyBool>();
208#ifndef TEST_HAS_NO_EXCEPTIONS
209 {
210 using V = std::variant<int, MakeEmptyT>;
211 V v1;
212 V v2;
213 makeEmpty(v&: v2);
214 assert(!(v1 == v2));
215 assert(!(v2 == v1));
216 assert(v1 != v2);
217 assert(v2 != v1);
218 }
219 {
220 using V = std::variant<int, MakeEmptyT>;
221 V v1;
222 makeEmpty(v&: v1);
223 V v2;
224 assert(!(v1 == v2));
225 assert(!(v2 == v1));
226 assert(v1 != v2);
227 assert(v2 != v1);
228 }
229 {
230 using V = std::variant<int, MakeEmptyT>;
231 V v1;
232 makeEmpty(v&: v1);
233 V v2;
234 makeEmpty(v&: v2);
235 assert(v1 == v2);
236 assert(v2 == v1);
237 assert(!(v1 != v2));
238 assert(!(v2 != v1));
239 }
240#endif
241}
242
243template <class Var>
244constexpr bool test_less(const Var &l, const Var &r, bool expect_less,
245 bool expect_greater) {
246 static_assert(std::is_same_v<decltype(l < r), bool>, "");
247 static_assert(std::is_same_v<decltype(l <= r), bool>, "");
248 static_assert(std::is_same_v<decltype(l > r), bool>, "");
249 static_assert(std::is_same_v<decltype(l >= r), bool>, "");
250
251 return ((l < r) == expect_less) && (!(l >= r) == expect_less) &&
252 ((l > r) == expect_greater) && (!(l <= r) == expect_greater);
253}
254
255template <class T1, class T2>
256void test_relational_basic() {
257 { // same index, same value
258 using V = std::variant<T1, T2>;
259 constexpr V v1(std::in_place_index<0>, T1{1});
260 constexpr V v2(std::in_place_index<0>, T1{1});
261 static_assert(test_less(v1, v2, false, false), "");
262 }
263 { // same index, value < other_value
264 using V = std::variant<T1, T2>;
265 constexpr V v1(std::in_place_index<0>, T1{0});
266 constexpr V v2(std::in_place_index<0>, T1{1});
267 static_assert(test_less(v1, v2, true, false), "");
268 }
269 { // same index, value > other_value
270 using V = std::variant<T1, T2>;
271 constexpr V v1(std::in_place_index<0>, T1{1});
272 constexpr V v2(std::in_place_index<0>, T1{0});
273 static_assert(test_less(v1, v2, false, true), "");
274 }
275 { // LHS.index() < RHS.index()
276 using V = std::variant<T1, T2>;
277 constexpr V v1(std::in_place_index<0>, T1{0});
278 constexpr V v2(std::in_place_index<1>, T2{0});
279 static_assert(test_less(v1, v2, true, false), "");
280 }
281 { // LHS.index() > RHS.index()
282 using V = std::variant<T1, T2>;
283 constexpr V v1(std::in_place_index<1>, T2{0});
284 constexpr V v2(std::in_place_index<0>, T1{0});
285 static_assert(test_less(v1, v2, false, true), "");
286 }
287}
288
289void test_relational() {
290 test_relational_basic<int, long>();
291 test_relational_basic<ComparesToMyBool, int>();
292 test_relational_basic<int, ComparesToMyBool>();
293 test_relational_basic<ComparesToMyBool, ComparesToMyBool>();
294#ifndef TEST_HAS_NO_EXCEPTIONS
295 { // LHS.index() < RHS.index(), RHS is empty
296 using V = std::variant<int, MakeEmptyT>;
297 V v1;
298 V v2;
299 makeEmpty(v&: v2);
300 assert(test_less(v1, v2, false, true));
301 }
302 { // LHS.index() > RHS.index(), LHS is empty
303 using V = std::variant<int, MakeEmptyT>;
304 V v1;
305 makeEmpty(v&: v1);
306 V v2;
307 assert(test_less(v1, v2, true, false));
308 }
309 { // LHS.index() == RHS.index(), LHS and RHS are empty
310 using V = std::variant<int, MakeEmptyT>;
311 V v1;
312 makeEmpty(v&: v1);
313 V v2;
314 makeEmpty(v&: v2);
315 assert(test_less(v1, v2, false, false));
316 }
317#endif
318}
319
320int main(int, char**) {
321 test_equality();
322 test_relational();
323
324 return 0;
325}
326

source code of libcxx/test/std/utilities/variant/variant.relops/relops.pass.cpp