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