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