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