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

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