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#ifndef _LIBCPP___OPTIONAL_COMPARISON_H
10#define _LIBCPP___OPTIONAL_COMPARISON_H
11
12#include <__compare/compare_three_way_result.h>
13#include <__compare/ordering.h>
14#include <__compare/three_way_comparable.h>
15#include <__config>
16#include <__optional/nullopt_t.h>
17#include <__type_traits/enable_if.h>
18#include <__type_traits/is_constructible.h>
19#include <__type_traits/is_core_convertible.h>
20#include <__type_traits/is_swappable.h>
21#include <__utility/declval.h>
22
23#include <__fwd/optional.h>
24
25#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
26# pragma GCC system_header
27#endif
28
29_LIBCPP_PUSH_MACROS
30#include <__undef_macros>
31
32#if _LIBCPP_STD_VER >= 17
33
34_LIBCPP_BEGIN_NAMESPACE_STD
35
36// [optional.relops] Relational operators
37
38template <
39 class _Tp,
40 class _Up,
41 enable_if_t<__is_core_convertible_v<decltype(std::declval<const _Tp&>() == std::declval<const _Up&>()), bool>,
42 int> = 0>
43_LIBCPP_HIDE_FROM_ABI constexpr bool operator==(const optional<_Tp>& __x, const optional<_Up>& __y) {
44 if (static_cast<bool>(__x) != static_cast<bool>(__y))
45 return false;
46 if (!static_cast<bool>(__x))
47 return true;
48 return *__x == *__y;
49}
50
51template <
52 class _Tp,
53 class _Up,
54 enable_if_t<__is_core_convertible_v<decltype(std::declval<const _Tp&>() != std::declval<const _Up&>()), bool>,
55 int> = 0>
56_LIBCPP_HIDE_FROM_ABI constexpr bool operator!=(const optional<_Tp>& __x, const optional<_Up>& __y) {
57 if (static_cast<bool>(__x) != static_cast<bool>(__y))
58 return true;
59 if (!static_cast<bool>(__x))
60 return false;
61 return *__x != *__y;
62}
63
64template < class _Tp,
65 class _Up,
66 enable_if_t<__is_core_convertible_v<decltype(std::declval<const _Tp&>() < std::declval<const _Up&>()), bool>,
67 int> = 0>
68_LIBCPP_HIDE_FROM_ABI constexpr bool operator<(const optional<_Tp>& __x, const optional<_Up>& __y) {
69 if (!static_cast<bool>(__y))
70 return false;
71 if (!static_cast<bool>(__x))
72 return true;
73 return *__x < *__y;
74}
75
76template < class _Tp,
77 class _Up,
78 enable_if_t<__is_core_convertible_v<decltype(std::declval<const _Tp&>() > std::declval<const _Up&>()), bool>,
79 int> = 0>
80_LIBCPP_HIDE_FROM_ABI constexpr bool operator>(const optional<_Tp>& __x, const optional<_Up>& __y) {
81 if (!static_cast<bool>(__x))
82 return false;
83 if (!static_cast<bool>(__y))
84 return true;
85 return *__x > *__y;
86}
87
88template <
89 class _Tp,
90 class _Up,
91 enable_if_t<__is_core_convertible_v<decltype(std::declval<const _Tp&>() <= std::declval<const _Up&>()), bool>,
92 int> = 0>
93_LIBCPP_HIDE_FROM_ABI constexpr bool operator<=(const optional<_Tp>& __x, const optional<_Up>& __y) {
94 if (!static_cast<bool>(__x))
95 return true;
96 if (!static_cast<bool>(__y))
97 return false;
98 return *__x <= *__y;
99}
100
101template <
102 class _Tp,
103 class _Up,
104 enable_if_t<__is_core_convertible_v<decltype(std::declval<const _Tp&>() >= std::declval<const _Up&>()), bool>,
105 int> = 0>
106_LIBCPP_HIDE_FROM_ABI constexpr bool operator>=(const optional<_Tp>& __x, const optional<_Up>& __y) {
107 if (!static_cast<bool>(__y))
108 return true;
109 if (!static_cast<bool>(__x))
110 return false;
111 return *__x >= *__y;
112}
113
114# if _LIBCPP_STD_VER >= 20
115
116template <class _Tp, three_way_comparable_with<_Tp> _Up>
117_LIBCPP_HIDE_FROM_ABI constexpr compare_three_way_result_t<_Tp, _Up>
118operator<=>(const optional<_Tp>& __x, const optional<_Up>& __y) {
119 if (__x && __y)
120 return *__x <=> *__y;
121 return __x.has_value() <=> __y.has_value();
122}
123
124# endif // _LIBCPP_STD_VER >= 20
125
126// [optional.nullops] Comparison with nullopt
127
128template <class _Tp>
129_LIBCPP_HIDE_FROM_ABI constexpr bool operator==(const optional<_Tp>& __x, nullopt_t) noexcept {
130 return !static_cast<bool>(__x);
131}
132
133# if _LIBCPP_STD_VER <= 17
134
135template <class _Tp>
136_LIBCPP_HIDE_FROM_ABI constexpr bool operator==(nullopt_t, const optional<_Tp>& __x) noexcept {
137 return !static_cast<bool>(__x);
138}
139
140template <class _Tp>
141_LIBCPP_HIDE_FROM_ABI constexpr bool operator!=(const optional<_Tp>& __x, nullopt_t) noexcept {
142 return static_cast<bool>(__x);
143}
144
145template <class _Tp>
146_LIBCPP_HIDE_FROM_ABI constexpr bool operator!=(nullopt_t, const optional<_Tp>& __x) noexcept {
147 return static_cast<bool>(__x);
148}
149
150template <class _Tp>
151_LIBCPP_HIDE_FROM_ABI constexpr bool operator<(const optional<_Tp>&, nullopt_t) noexcept {
152 return false;
153}
154
155template <class _Tp>
156_LIBCPP_HIDE_FROM_ABI constexpr bool operator<(nullopt_t, const optional<_Tp>& __x) noexcept {
157 return static_cast<bool>(__x);
158}
159
160template <class _Tp>
161_LIBCPP_HIDE_FROM_ABI constexpr bool operator<=(const optional<_Tp>& __x, nullopt_t) noexcept {
162 return !static_cast<bool>(__x);
163}
164
165template <class _Tp>
166_LIBCPP_HIDE_FROM_ABI constexpr bool operator<=(nullopt_t, const optional<_Tp>&) noexcept {
167 return true;
168}
169
170template <class _Tp>
171_LIBCPP_HIDE_FROM_ABI constexpr bool operator>(const optional<_Tp>& __x, nullopt_t) noexcept {
172 return static_cast<bool>(__x);
173}
174
175template <class _Tp>
176_LIBCPP_HIDE_FROM_ABI constexpr bool operator>(nullopt_t, const optional<_Tp>&) noexcept {
177 return false;
178}
179
180template <class _Tp>
181_LIBCPP_HIDE_FROM_ABI constexpr bool operator>=(const optional<_Tp>&, nullopt_t) noexcept {
182 return true;
183}
184
185template <class _Tp>
186_LIBCPP_HIDE_FROM_ABI constexpr bool operator>=(nullopt_t, const optional<_Tp>& __x) noexcept {
187 return !static_cast<bool>(__x);
188}
189
190# else // _LIBCPP_STD_VER <= 17
191
192template <class _Tp>
193_LIBCPP_HIDE_FROM_ABI constexpr strong_ordering operator<=>(const optional<_Tp>& __x, nullopt_t) noexcept {
194 return __x.has_value() <=> false;
195}
196
197# endif // _LIBCPP_STD_VER <= 17
198
199// [optional.comp.with.t] Comparison with T
200
201template <
202 class _Tp,
203 class _Up,
204 enable_if_t<__is_core_convertible_v<decltype(std::declval<const _Tp&>() == std::declval<const _Up&>()), bool>,
205 int> = 0>
206_LIBCPP_HIDE_FROM_ABI constexpr bool operator==(const optional<_Tp>& __x, const _Up& __v) {
207 if (__x.has_value())
208 return *__x == __v;
209 return false;
210}
211
212template <
213 class _Tp,
214 class _Up,
215 enable_if_t<__is_core_convertible_v<decltype(std::declval<const _Tp&>() == std::declval<const _Up&>()), bool>,
216 int> = 0>
217_LIBCPP_HIDE_FROM_ABI constexpr bool operator==(const _Tp& __v, const optional<_Up>& __x) {
218 if (__x.has_value())
219 return __v == *__x;
220 return false;
221}
222
223template <
224 class _Tp,
225 class _Up,
226 enable_if_t<__is_core_convertible_v<decltype(std::declval<const _Tp&>() != std::declval<const _Up&>()), bool>,
227 int> = 0>
228_LIBCPP_HIDE_FROM_ABI constexpr bool operator!=(const optional<_Tp>& __x, const _Up& __v) {
229 if (__x.has_value())
230 return *__x != __v;
231 return true;
232}
233
234template <
235 class _Tp,
236 class _Up,
237 enable_if_t<__is_core_convertible_v<decltype(std::declval<const _Tp&>() != std::declval<const _Up&>()), bool>,
238 int> = 0>
239_LIBCPP_HIDE_FROM_ABI constexpr bool operator!=(const _Tp& __v, const optional<_Up>& __x) {
240 if (__x.has_value())
241 return __v != *__x;
242 return true;
243}
244
245template < class _Tp,
246 class _Up,
247 enable_if_t<__is_core_convertible_v<decltype(std::declval<const _Tp&>() < std::declval<const _Up&>()), bool>,
248 int> = 0>
249_LIBCPP_HIDE_FROM_ABI constexpr bool operator<(const optional<_Tp>& __x, const _Up& __v) {
250 if (__x.has_value())
251 return *__x < __v;
252 return true;
253}
254
255template < class _Tp,
256 class _Up,
257 enable_if_t<__is_core_convertible_v<decltype(std::declval<const _Tp&>() < std::declval<const _Up&>()), bool>,
258 int> = 0>
259_LIBCPP_HIDE_FROM_ABI constexpr bool operator<(const _Tp& __v, const optional<_Up>& __x) {
260 if (__x.has_value())
261 return __v < *__x;
262 return false;
263}
264
265template <
266 class _Tp,
267 class _Up,
268 enable_if_t<__is_core_convertible_v<decltype(std::declval<const _Tp&>() <= std::declval<const _Up&>()), bool>,
269 int> = 0>
270_LIBCPP_HIDE_FROM_ABI constexpr bool operator<=(const optional<_Tp>& __x, const _Up& __v) {
271 if (__x.has_value())
272 return *__x <= __v;
273 return true;
274}
275
276template <
277 class _Tp,
278 class _Up,
279 enable_if_t<__is_core_convertible_v<decltype(std::declval<const _Tp&>() <= std::declval<const _Up&>()), bool>,
280 int> = 0>
281_LIBCPP_HIDE_FROM_ABI constexpr bool operator<=(const _Tp& __v, const optional<_Up>& __x) {
282 if (__x.has_value())
283 return __v <= *__x;
284 return false;
285}
286
287template < class _Tp,
288 class _Up,
289 enable_if_t<__is_core_convertible_v<decltype(std::declval<const _Tp&>() > std::declval<const _Up&>()), bool>,
290 int> = 0>
291_LIBCPP_HIDE_FROM_ABI constexpr bool operator>(const optional<_Tp>& __x, const _Up& __v) {
292 if (__x.has_value())
293 return *__x > __v;
294 return false;
295}
296
297template < class _Tp,
298 class _Up,
299 enable_if_t<__is_core_convertible_v<decltype(std::declval<const _Tp&>() > std::declval<const _Up&>()), bool>,
300 int> = 0>
301_LIBCPP_HIDE_FROM_ABI constexpr bool operator>(const _Tp& __v, const optional<_Up>& __x) {
302 if (__x.has_value())
303 return __v > *__x;
304 return true;
305}
306
307template <
308 class _Tp,
309 class _Up,
310 enable_if_t<__is_core_convertible_v<decltype(std::declval<const _Tp&>() >= std::declval<const _Up&>()), bool>,
311 int> = 0>
312_LIBCPP_HIDE_FROM_ABI constexpr bool operator>=(const optional<_Tp>& __x, const _Up& __v) {
313 if (__x.has_value())
314 return *__x >= __v;
315 return false;
316}
317
318template <
319 class _Tp,
320 class _Up,
321 enable_if_t<__is_core_convertible_v<decltype(std::declval<const _Tp&>() >= std::declval<const _Up&>()), bool>,
322 int> = 0>
323_LIBCPP_HIDE_FROM_ABI constexpr bool operator>=(const _Tp& __v, const optional<_Up>& __x) {
324 if (__x.has_value())
325 return __v >= *__x;
326 return true;
327}
328
329# if _LIBCPP_STD_VER >= 20
330
331template <class _Tp>
332concept __is_derived_from_optional = requires(const _Tp& __t) { []<class _Up>(const optional<_Up>&) {}(__t); };
333
334template <class _Tp, class _Up>
335 requires(!__is_derived_from_optional<_Up>) && three_way_comparable_with<_Tp, _Up>
336_LIBCPP_HIDE_FROM_ABI constexpr compare_three_way_result_t<_Tp, _Up>
337operator<=>(const optional<_Tp>& __x, const _Up& __v) {
338 return __x.has_value() ? *__x <=> __v : strong_ordering::less;
339}
340
341# endif // _LIBCPP_STD_VER >= 20
342
343_LIBCPP_END_NAMESPACE_STD
344
345#endif // _LIBCPP_STD_VER >= 17
346
347_LIBCPP_POP_MACROS
348
349#endif // _LIBCPP___OPTIONAL_COMPARISON_H
350