xref: /llvm-project/libcxx/test/std/utilities/variant/variant.relops/relops.pass.cpp (revision bb43a0cd4adc4f1fa12e0d2fd1fe9aa6b5c00e34)
1 // -*- C++ -*-
2 //===----------------------------------------------------------------------===//
3 //
4 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5 // See https://llvm.org/LICENSE.txt for license information.
6 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //
8 //===----------------------------------------------------------------------===//
9 
10 // UNSUPPORTED: c++03, c++11, c++14
11 
12 // Throwing bad_variant_access is supported starting in macosx10.13
13 // XFAIL: with_system_cxx_lib=macosx10.12 && !no-exceptions
14 // XFAIL: with_system_cxx_lib=macosx10.11 && !no-exceptions
15 // XFAIL: with_system_cxx_lib=macosx10.10 && !no-exceptions
16 // XFAIL: with_system_cxx_lib=macosx10.9 && !no-exceptions
17 
18 // <variant>
19 
20 // template <class ...Types>
21 // constexpr bool
22 // operator==(variant<Types...> const&, variant<Types...> const&) noexcept;
23 //
24 // template <class ...Types>
25 // constexpr bool
26 // operator!=(variant<Types...> const&, variant<Types...> const&) noexcept;
27 //
28 // template <class ...Types>
29 // constexpr bool
30 // operator<(variant<Types...> const&, variant<Types...> const&) noexcept;
31 //
32 // template <class ...Types>
33 // constexpr bool
34 // operator>(variant<Types...> const&, variant<Types...> const&) noexcept;
35 //
36 // template <class ...Types>
37 // constexpr bool
38 // operator<=(variant<Types...> const&, variant<Types...> const&) noexcept;
39 //
40 // template <class ...Types>
41 // constexpr bool
42 // operator>=(variant<Types...> const&, variant<Types...> const&) noexcept;
43 
44 #include <cassert>
45 #include <type_traits>
46 #include <utility>
47 #include <variant>
48 
49 #include "test_macros.h"
50 
51 #ifndef TEST_HAS_NO_EXCEPTIONS
52 struct MakeEmptyT {
53   MakeEmptyT() = default;
54   MakeEmptyT(MakeEmptyT &&) { throw 42; }
55   MakeEmptyT &operator=(MakeEmptyT &&) { throw 42; }
56 };
57 inline bool operator==(const MakeEmptyT &, const MakeEmptyT &) {
58   assert(false);
59   return false;
60 }
61 inline bool operator!=(const MakeEmptyT &, const MakeEmptyT &) {
62   assert(false);
63   return false;
64 }
65 inline bool operator<(const MakeEmptyT &, const MakeEmptyT &) {
66   assert(false);
67   return false;
68 }
69 inline bool operator<=(const MakeEmptyT &, const MakeEmptyT &) {
70   assert(false);
71   return false;
72 }
73 inline bool operator>(const MakeEmptyT &, const MakeEmptyT &) {
74   assert(false);
75   return false;
76 }
77 inline bool operator>=(const MakeEmptyT &, const MakeEmptyT &) {
78   assert(false);
79   return false;
80 }
81 
82 template <class Variant> void makeEmpty(Variant &v) {
83   Variant v2(std::in_place_type<MakeEmptyT>);
84   try {
85     v = std::move(v2);
86     assert(false);
87   } catch (...) {
88     assert(v.valueless_by_exception());
89   }
90 }
91 #endif // TEST_HAS_NO_EXCEPTIONS
92 
93 struct MyBool {
94   bool value;
95   constexpr explicit MyBool(bool v) : value(v) {}
96   constexpr operator bool() const noexcept { return value; }
97 };
98 
99 struct ComparesToMyBool {
100   int value = 0;
101 };
102 inline constexpr MyBool operator==(const ComparesToMyBool& LHS, const ComparesToMyBool& RHS) noexcept {
103   return MyBool(LHS.value == RHS.value);
104 }
105 inline constexpr MyBool operator!=(const ComparesToMyBool& LHS, const ComparesToMyBool& RHS) noexcept {
106   return MyBool(LHS.value != RHS.value);
107 }
108 inline constexpr MyBool operator<(const ComparesToMyBool& LHS, const ComparesToMyBool& RHS) noexcept {
109   return MyBool(LHS.value < RHS.value);
110 }
111 inline constexpr MyBool operator<=(const ComparesToMyBool& LHS, const ComparesToMyBool& RHS) noexcept {
112   return MyBool(LHS.value <= RHS.value);
113 }
114 inline constexpr MyBool operator>(const ComparesToMyBool& LHS, const ComparesToMyBool& RHS) noexcept {
115   return MyBool(LHS.value > RHS.value);
116 }
117 inline constexpr MyBool operator>=(const ComparesToMyBool& LHS, const ComparesToMyBool& RHS) noexcept {
118   return MyBool(LHS.value >= RHS.value);
119 }
120 
121 template <class T1, class T2>
122 void test_equality_basic() {
123   {
124     using V = std::variant<T1, T2>;
125     constexpr V v1(std::in_place_index<0>, T1{42});
126     constexpr V v2(std::in_place_index<0>, T1{42});
127     static_assert(v1 == v2, "");
128     static_assert(v2 == v1, "");
129     static_assert(!(v1 != v2), "");
130     static_assert(!(v2 != v1), "");
131   }
132   {
133     using V = std::variant<T1, T2>;
134     constexpr V v1(std::in_place_index<0>, T1{42});
135     constexpr V v2(std::in_place_index<0>, T1{43});
136     static_assert(!(v1 == v2), "");
137     static_assert(!(v2 == v1), "");
138     static_assert(v1 != v2, "");
139     static_assert(v2 != v1, "");
140   }
141   {
142     using V = std::variant<T1, T2>;
143     constexpr V v1(std::in_place_index<0>, T1{42});
144     constexpr V v2(std::in_place_index<1>, T2{42});
145     static_assert(!(v1 == v2), "");
146     static_assert(!(v2 == v1), "");
147     static_assert(v1 != v2, "");
148     static_assert(v2 != v1, "");
149   }
150   {
151     using V = std::variant<T1, T2>;
152     constexpr V v1(std::in_place_index<1>, T2{42});
153     constexpr V v2(std::in_place_index<1>, T2{42});
154     static_assert(v1 == v2, "");
155     static_assert(v2 == v1, "");
156     static_assert(!(v1 != v2), "");
157     static_assert(!(v2 != v1), "");
158   }
159 }
160 
161 void test_equality() {
162   test_equality_basic<int, long>();
163   test_equality_basic<ComparesToMyBool, int>();
164   test_equality_basic<int, ComparesToMyBool>();
165   test_equality_basic<ComparesToMyBool, ComparesToMyBool>();
166 #ifndef TEST_HAS_NO_EXCEPTIONS
167   {
168     using V = std::variant<int, MakeEmptyT>;
169     V v1;
170     V v2;
171     makeEmpty(v2);
172     assert(!(v1 == v2));
173     assert(!(v2 == v1));
174     assert(v1 != v2);
175     assert(v2 != v1);
176   }
177   {
178     using V = std::variant<int, MakeEmptyT>;
179     V v1;
180     makeEmpty(v1);
181     V v2;
182     assert(!(v1 == v2));
183     assert(!(v2 == v1));
184     assert(v1 != v2);
185     assert(v2 != v1);
186   }
187   {
188     using V = std::variant<int, MakeEmptyT>;
189     V v1;
190     makeEmpty(v1);
191     V v2;
192     makeEmpty(v2);
193     assert(v1 == v2);
194     assert(v2 == v1);
195     assert(!(v1 != v2));
196     assert(!(v2 != v1));
197   }
198 #endif
199 }
200 
201 template <class Var>
202 constexpr bool test_less(const Var &l, const Var &r, bool expect_less,
203                          bool expect_greater) {
204   static_assert(std::is_same_v<decltype(l < r), bool>, "");
205   static_assert(std::is_same_v<decltype(l <= r), bool>, "");
206   static_assert(std::is_same_v<decltype(l > r), bool>, "");
207   static_assert(std::is_same_v<decltype(l >= r), bool>, "");
208 
209   return ((l < r) == expect_less) && (!(l >= r) == expect_less) &&
210          ((l > r) == expect_greater) && (!(l <= r) == expect_greater);
211 }
212 
213 template <class T1, class T2>
214 void test_relational_basic() {
215   { // same index, same value
216     using V = std::variant<T1, T2>;
217     constexpr V v1(std::in_place_index<0>, T1{1});
218     constexpr V v2(std::in_place_index<0>, T1{1});
219     static_assert(test_less(v1, v2, false, false), "");
220   }
221   { // same index, value < other_value
222     using V = std::variant<T1, T2>;
223     constexpr V v1(std::in_place_index<0>, T1{0});
224     constexpr V v2(std::in_place_index<0>, T1{1});
225     static_assert(test_less(v1, v2, true, false), "");
226   }
227   { // same index, value > other_value
228     using V = std::variant<T1, T2>;
229     constexpr V v1(std::in_place_index<0>, T1{1});
230     constexpr V v2(std::in_place_index<0>, T1{0});
231     static_assert(test_less(v1, v2, false, true), "");
232   }
233   { // LHS.index() < RHS.index()
234     using V = std::variant<T1, T2>;
235     constexpr V v1(std::in_place_index<0>, T1{0});
236     constexpr V v2(std::in_place_index<1>, T2{0});
237     static_assert(test_less(v1, v2, true, false), "");
238   }
239   { // LHS.index() > RHS.index()
240     using V = std::variant<T1, T2>;
241     constexpr V v1(std::in_place_index<1>, T2{0});
242     constexpr V v2(std::in_place_index<0>, T1{0});
243     static_assert(test_less(v1, v2, false, true), "");
244   }
245 }
246 
247 void test_relational() {
248   test_relational_basic<int, long>();
249   test_relational_basic<ComparesToMyBool, int>();
250   test_relational_basic<int, ComparesToMyBool>();
251   test_relational_basic<ComparesToMyBool, ComparesToMyBool>();
252 #ifndef TEST_HAS_NO_EXCEPTIONS
253   { // LHS.index() < RHS.index(), RHS is empty
254     using V = std::variant<int, MakeEmptyT>;
255     V v1;
256     V v2;
257     makeEmpty(v2);
258     assert(test_less(v1, v2, false, true));
259   }
260   { // LHS.index() > RHS.index(), LHS is empty
261     using V = std::variant<int, MakeEmptyT>;
262     V v1;
263     makeEmpty(v1);
264     V v2;
265     assert(test_less(v1, v2, true, false));
266   }
267   { // LHS.index() == RHS.index(), LHS and RHS are empty
268     using V = std::variant<int, MakeEmptyT>;
269     V v1;
270     makeEmpty(v1);
271     V v2;
272     makeEmpty(v2);
273     assert(test_less(v1, v2, false, false));
274   }
275 #endif
276 }
277 
278 int main(int, char**) {
279   test_equality();
280   test_relational();
281 
282   return 0;
283 }
284