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