1 | // <optional> -*- C++ -*- |
2 | |
3 | // Copyright (C) 2013-2021 Free Software Foundation, Inc. |
4 | // |
5 | // This file is part of the GNU ISO C++ Library. This library is free |
6 | // software; you can redistribute it and/or modify it under the |
7 | // terms of the GNU General Public License as published by the |
8 | // Free Software Foundation; either version 3, or (at your option) |
9 | // any later version. |
10 | |
11 | // This library is distributed in the hope that it will be useful, |
12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 | // GNU General Public License for more details. |
15 | |
16 | // Under Section 7 of GPL version 3, you are granted additional |
17 | // permissions described in the GCC Runtime Library Exception, version |
18 | // 3.1, as published by the Free Software Foundation. |
19 | |
20 | // You should have received a copy of the GNU General Public License and |
21 | // a copy of the GCC Runtime Library Exception along with this program; |
22 | // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see |
23 | // <http://www.gnu.org/licenses/>. |
24 | |
25 | /** @file include/optional |
26 | * This is a Standard C++ Library header. |
27 | */ |
28 | |
29 | #ifndef _GLIBCXX_OPTIONAL |
30 | #define _GLIBCXX_OPTIONAL 1 |
31 | |
32 | #pragma GCC system_header |
33 | |
34 | #if __cplusplus >= 201703L |
35 | |
36 | #include <utility> |
37 | #include <type_traits> |
38 | #include <exception> |
39 | #include <new> |
40 | #include <initializer_list> |
41 | #include <bits/exception_defines.h> |
42 | #include <bits/functional_hash.h> |
43 | #include <bits/enable_special_members.h> |
44 | #if __cplusplus > 201703L |
45 | # include <compare> |
46 | #endif |
47 | |
48 | namespace std _GLIBCXX_VISIBILITY(default) |
49 | { |
50 | _GLIBCXX_BEGIN_NAMESPACE_VERSION |
51 | |
52 | /** |
53 | * @addtogroup utilities |
54 | * @{ |
55 | */ |
56 | |
57 | #define __cpp_lib_optional 201606L |
58 | |
59 | template<typename _Tp> |
60 | class optional; |
61 | |
62 | /// Tag type to disengage optional objects. |
63 | struct nullopt_t |
64 | { |
65 | // Do not user-declare default constructor at all for |
66 | // optional_value = {} syntax to work. |
67 | // nullopt_t() = delete; |
68 | |
69 | // Used for constructing nullopt. |
70 | enum class _Construct { _Token }; |
71 | |
72 | // Must be constexpr for nullopt_t to be literal. |
73 | explicit constexpr nullopt_t(_Construct) { } |
74 | }; |
75 | |
76 | /// Tag to disengage optional objects. |
77 | inline constexpr nullopt_t nullopt { nullopt_t::_Construct::_Token }; |
78 | |
79 | /** |
80 | * @brief Exception class thrown when a disengaged optional object is |
81 | * dereferenced. |
82 | * @ingroup exceptions |
83 | */ |
84 | class bad_optional_access : public exception |
85 | { |
86 | public: |
87 | bad_optional_access() = default; |
88 | virtual ~bad_optional_access() = default; |
89 | |
90 | const char* what() const noexcept override |
91 | { return "bad optional access" ; } |
92 | }; |
93 | |
94 | void |
95 | __throw_bad_optional_access() |
96 | __attribute__((__noreturn__)); |
97 | |
98 | // XXX Does not belong here. |
99 | inline void |
100 | __throw_bad_optional_access() |
101 | { _GLIBCXX_THROW_OR_ABORT(bad_optional_access()); } |
102 | |
103 | // This class template manages construction/destruction of |
104 | // the contained value for a std::optional. |
105 | template <typename _Tp> |
106 | struct _Optional_payload_base |
107 | { |
108 | using _Stored_type = remove_const_t<_Tp>; |
109 | |
110 | _Optional_payload_base() = default; |
111 | ~_Optional_payload_base() = default; |
112 | |
113 | template<typename... _Args> |
114 | constexpr |
115 | _Optional_payload_base(in_place_t __tag, _Args&&... __args) |
116 | : _M_payload(__tag, std::forward<_Args>(__args)...), |
117 | _M_engaged(true) |
118 | { } |
119 | |
120 | template<typename _Up, typename... _Args> |
121 | constexpr |
122 | _Optional_payload_base(std::initializer_list<_Up> __il, |
123 | _Args&&... __args) |
124 | : _M_payload(__il, std::forward<_Args>(__args)...), |
125 | _M_engaged(true) |
126 | { } |
127 | |
128 | // Constructor used by _Optional_base copy constructor when the |
129 | // contained value is not trivially copy constructible. |
130 | constexpr |
131 | _Optional_payload_base(bool __engaged, |
132 | const _Optional_payload_base& __other) |
133 | { |
134 | if (__other._M_engaged) |
135 | this->_M_construct(__other._M_get()); |
136 | } |
137 | |
138 | // Constructor used by _Optional_base move constructor when the |
139 | // contained value is not trivially move constructible. |
140 | constexpr |
141 | _Optional_payload_base(bool __engaged, |
142 | _Optional_payload_base&& __other) |
143 | { |
144 | if (__other._M_engaged) |
145 | this->_M_construct(std::move(__other._M_get())); |
146 | } |
147 | |
148 | // Copy constructor is only used to when the contained value is |
149 | // trivially copy constructible. |
150 | _Optional_payload_base(const _Optional_payload_base&) = default; |
151 | |
152 | // Move constructor is only used to when the contained value is |
153 | // trivially copy constructible. |
154 | _Optional_payload_base(_Optional_payload_base&&) = default; |
155 | |
156 | _Optional_payload_base& |
157 | operator=(const _Optional_payload_base&) = default; |
158 | |
159 | _Optional_payload_base& |
160 | operator=(_Optional_payload_base&&) = default; |
161 | |
162 | // used to perform non-trivial copy assignment. |
163 | constexpr void |
164 | _M_copy_assign(const _Optional_payload_base& __other) |
165 | { |
166 | if (this->_M_engaged && __other._M_engaged) |
167 | this->_M_get() = __other._M_get(); |
168 | else |
169 | { |
170 | if (__other._M_engaged) |
171 | this->_M_construct(__other._M_get()); |
172 | else |
173 | this->_M_reset(); |
174 | } |
175 | } |
176 | |
177 | // used to perform non-trivial move assignment. |
178 | constexpr void |
179 | _M_move_assign(_Optional_payload_base&& __other) |
180 | noexcept(__and_v<is_nothrow_move_constructible<_Tp>, |
181 | is_nothrow_move_assignable<_Tp>>) |
182 | { |
183 | if (this->_M_engaged && __other._M_engaged) |
184 | this->_M_get() = std::move(__other._M_get()); |
185 | else |
186 | { |
187 | if (__other._M_engaged) |
188 | this->_M_construct(std::move(__other._M_get())); |
189 | else |
190 | this->_M_reset(); |
191 | } |
192 | } |
193 | |
194 | struct _Empty_byte { }; |
195 | |
196 | template<typename _Up, bool = is_trivially_destructible_v<_Up>> |
197 | union _Storage |
198 | { |
199 | constexpr _Storage() noexcept : _M_empty() { } |
200 | |
201 | template<typename... _Args> |
202 | constexpr |
203 | _Storage(in_place_t, _Args&&... __args) |
204 | : _M_value(std::forward<_Args>(__args)...) |
205 | { } |
206 | |
207 | template<typename _Vp, typename... _Args> |
208 | constexpr |
209 | _Storage(std::initializer_list<_Vp> __il, _Args&&... __args) |
210 | : _M_value(__il, std::forward<_Args>(__args)...) |
211 | { } |
212 | |
213 | _Empty_byte _M_empty; |
214 | _Up _M_value; |
215 | }; |
216 | |
217 | template<typename _Up> |
218 | union _Storage<_Up, false> |
219 | { |
220 | constexpr _Storage() noexcept : _M_empty() { } |
221 | |
222 | template<typename... _Args> |
223 | constexpr |
224 | _Storage(in_place_t, _Args&&... __args) |
225 | : _M_value(std::forward<_Args>(__args)...) |
226 | { } |
227 | |
228 | template<typename _Vp, typename... _Args> |
229 | constexpr |
230 | _Storage(std::initializer_list<_Vp> __il, _Args&&... __args) |
231 | : _M_value(__il, std::forward<_Args>(__args)...) |
232 | { } |
233 | |
234 | // User-provided destructor is needed when _Up has non-trivial dtor. |
235 | ~_Storage() { } |
236 | |
237 | _Empty_byte _M_empty; |
238 | _Up _M_value; |
239 | }; |
240 | |
241 | _Storage<_Stored_type> _M_payload; |
242 | |
243 | bool _M_engaged = false; |
244 | |
245 | template<typename... _Args> |
246 | void |
247 | _M_construct(_Args&&... __args) |
248 | noexcept(is_nothrow_constructible_v<_Stored_type, _Args...>) |
249 | { |
250 | ::new ((void *) std::__addressof(this->_M_payload)) |
251 | _Stored_type(std::forward<_Args>(__args)...); |
252 | this->_M_engaged = true; |
253 | } |
254 | |
255 | constexpr void |
256 | _M_destroy() noexcept |
257 | { |
258 | _M_engaged = false; |
259 | _M_payload._M_value.~_Stored_type(); |
260 | } |
261 | |
262 | // The _M_get() operations have _M_engaged as a precondition. |
263 | // They exist to access the contained value with the appropriate |
264 | // const-qualification, because _M_payload has had the const removed. |
265 | |
266 | constexpr _Tp& |
267 | _M_get() noexcept |
268 | { return this->_M_payload._M_value; } |
269 | |
270 | constexpr const _Tp& |
271 | _M_get() const noexcept |
272 | { return this->_M_payload._M_value; } |
273 | |
274 | // _M_reset is a 'safe' operation with no precondition. |
275 | constexpr void |
276 | _M_reset() noexcept |
277 | { |
278 | if (this->_M_engaged) |
279 | _M_destroy(); |
280 | } |
281 | }; |
282 | |
283 | // Class template that manages the payload for optionals. |
284 | template <typename _Tp, |
285 | bool /*_HasTrivialDestructor*/ = |
286 | is_trivially_destructible_v<_Tp>, |
287 | bool /*_HasTrivialCopy */ = |
288 | is_trivially_copy_assignable_v<_Tp> |
289 | && is_trivially_copy_constructible_v<_Tp>, |
290 | bool /*_HasTrivialMove */ = |
291 | is_trivially_move_assignable_v<_Tp> |
292 | && is_trivially_move_constructible_v<_Tp>> |
293 | struct _Optional_payload; |
294 | |
295 | // Payload for potentially-constexpr optionals (trivial copy/move/destroy). |
296 | template <typename _Tp> |
297 | struct _Optional_payload<_Tp, true, true, true> |
298 | : _Optional_payload_base<_Tp> |
299 | { |
300 | using _Optional_payload_base<_Tp>::_Optional_payload_base; |
301 | |
302 | _Optional_payload() = default; |
303 | }; |
304 | |
305 | // Payload for optionals with non-trivial copy construction/assignment. |
306 | template <typename _Tp> |
307 | struct _Optional_payload<_Tp, true, false, true> |
308 | : _Optional_payload_base<_Tp> |
309 | { |
310 | using _Optional_payload_base<_Tp>::_Optional_payload_base; |
311 | |
312 | _Optional_payload() = default; |
313 | ~_Optional_payload() = default; |
314 | _Optional_payload(const _Optional_payload&) = default; |
315 | _Optional_payload(_Optional_payload&&) = default; |
316 | _Optional_payload& operator=(_Optional_payload&&) = default; |
317 | |
318 | // Non-trivial copy assignment. |
319 | constexpr |
320 | _Optional_payload& |
321 | operator=(const _Optional_payload& __other) |
322 | { |
323 | this->_M_copy_assign(__other); |
324 | return *this; |
325 | } |
326 | }; |
327 | |
328 | // Payload for optionals with non-trivial move construction/assignment. |
329 | template <typename _Tp> |
330 | struct _Optional_payload<_Tp, true, true, false> |
331 | : _Optional_payload_base<_Tp> |
332 | { |
333 | using _Optional_payload_base<_Tp>::_Optional_payload_base; |
334 | |
335 | _Optional_payload() = default; |
336 | ~_Optional_payload() = default; |
337 | _Optional_payload(const _Optional_payload&) = default; |
338 | _Optional_payload(_Optional_payload&&) = default; |
339 | _Optional_payload& operator=(const _Optional_payload&) = default; |
340 | |
341 | // Non-trivial move assignment. |
342 | constexpr |
343 | _Optional_payload& |
344 | operator=(_Optional_payload&& __other) |
345 | noexcept(__and_v<is_nothrow_move_constructible<_Tp>, |
346 | is_nothrow_move_assignable<_Tp>>) |
347 | { |
348 | this->_M_move_assign(std::move(__other)); |
349 | return *this; |
350 | } |
351 | }; |
352 | |
353 | // Payload for optionals with non-trivial copy and move assignment. |
354 | template <typename _Tp> |
355 | struct _Optional_payload<_Tp, true, false, false> |
356 | : _Optional_payload_base<_Tp> |
357 | { |
358 | using _Optional_payload_base<_Tp>::_Optional_payload_base; |
359 | |
360 | _Optional_payload() = default; |
361 | ~_Optional_payload() = default; |
362 | _Optional_payload(const _Optional_payload&) = default; |
363 | _Optional_payload(_Optional_payload&&) = default; |
364 | |
365 | // Non-trivial copy assignment. |
366 | constexpr |
367 | _Optional_payload& |
368 | operator=(const _Optional_payload& __other) |
369 | { |
370 | this->_M_copy_assign(__other); |
371 | return *this; |
372 | } |
373 | |
374 | // Non-trivial move assignment. |
375 | constexpr |
376 | _Optional_payload& |
377 | operator=(_Optional_payload&& __other) |
378 | noexcept(__and_v<is_nothrow_move_constructible<_Tp>, |
379 | is_nothrow_move_assignable<_Tp>>) |
380 | { |
381 | this->_M_move_assign(std::move(__other)); |
382 | return *this; |
383 | } |
384 | }; |
385 | |
386 | // Payload for optionals with non-trivial destructors. |
387 | template <typename _Tp, bool _Copy, bool _Move> |
388 | struct _Optional_payload<_Tp, false, _Copy, _Move> |
389 | : _Optional_payload<_Tp, true, false, false> |
390 | { |
391 | // Base class implements all the constructors and assignment operators: |
392 | using _Optional_payload<_Tp, true, false, false>::_Optional_payload; |
393 | _Optional_payload() = default; |
394 | _Optional_payload(const _Optional_payload&) = default; |
395 | _Optional_payload(_Optional_payload&&) = default; |
396 | _Optional_payload& operator=(const _Optional_payload&) = default; |
397 | _Optional_payload& operator=(_Optional_payload&&) = default; |
398 | |
399 | // Destructor needs to destroy the contained value: |
400 | ~_Optional_payload() { this->_M_reset(); } |
401 | }; |
402 | |
403 | // Common base class for _Optional_base<T> to avoid repeating these |
404 | // member functions in each specialization. |
405 | template<typename _Tp, typename _Dp> |
406 | class _Optional_base_impl |
407 | { |
408 | protected: |
409 | using _Stored_type = remove_const_t<_Tp>; |
410 | |
411 | // The _M_construct operation has !_M_engaged as a precondition |
412 | // while _M_destruct has _M_engaged as a precondition. |
413 | template<typename... _Args> |
414 | void |
415 | _M_construct(_Args&&... __args) |
416 | noexcept(is_nothrow_constructible_v<_Stored_type, _Args...>) |
417 | { |
418 | ::new |
419 | (std::__addressof(static_cast<_Dp*>(this)->_M_payload._M_payload)) |
420 | _Stored_type(std::forward<_Args>(__args)...); |
421 | static_cast<_Dp*>(this)->_M_payload._M_engaged = true; |
422 | } |
423 | |
424 | void |
425 | _M_destruct() noexcept |
426 | { static_cast<_Dp*>(this)->_M_payload._M_destroy(); } |
427 | |
428 | // _M_reset is a 'safe' operation with no precondition. |
429 | constexpr void |
430 | _M_reset() noexcept |
431 | { static_cast<_Dp*>(this)->_M_payload._M_reset(); } |
432 | |
433 | constexpr bool _M_is_engaged() const noexcept |
434 | { return static_cast<const _Dp*>(this)->_M_payload._M_engaged; } |
435 | |
436 | // The _M_get operations have _M_engaged as a precondition. |
437 | constexpr _Tp& |
438 | _M_get() noexcept |
439 | { |
440 | __glibcxx_assert(this->_M_is_engaged()); |
441 | return static_cast<_Dp*>(this)->_M_payload._M_get(); |
442 | } |
443 | |
444 | constexpr const _Tp& |
445 | _M_get() const noexcept |
446 | { |
447 | __glibcxx_assert(this->_M_is_engaged()); |
448 | return static_cast<const _Dp*>(this)->_M_payload._M_get(); |
449 | } |
450 | }; |
451 | |
452 | /** |
453 | * @brief Class template that provides copy/move constructors of optional. |
454 | * |
455 | * Such a separate base class template is necessary in order to |
456 | * conditionally make copy/move constructors trivial. |
457 | * |
458 | * When the contained value is trivially copy/move constructible, |
459 | * the copy/move constructors of _Optional_base will invoke the |
460 | * trivial copy/move constructor of _Optional_payload. Otherwise, |
461 | * they will invoke _Optional_payload(bool, const _Optional_payload&) |
462 | * or _Optional_payload(bool, _Optional_payload&&) to initialize |
463 | * the contained value, if copying/moving an engaged optional. |
464 | * |
465 | * Whether the other special members are trivial is determined by the |
466 | * _Optional_payload<_Tp> specialization used for the _M_payload member. |
467 | * |
468 | * @see optional, _Enable_special_members |
469 | */ |
470 | template<typename _Tp, |
471 | bool = is_trivially_copy_constructible_v<_Tp>, |
472 | bool = is_trivially_move_constructible_v<_Tp>> |
473 | struct _Optional_base |
474 | : _Optional_base_impl<_Tp, _Optional_base<_Tp>> |
475 | { |
476 | // Constructors for disengaged optionals. |
477 | constexpr _Optional_base() = default; |
478 | |
479 | // Constructors for engaged optionals. |
480 | template<typename... _Args, |
481 | enable_if_t<is_constructible_v<_Tp, _Args...>, bool> = false> |
482 | constexpr explicit |
483 | _Optional_base(in_place_t, _Args&&... __args) |
484 | : _M_payload(in_place, std::forward<_Args>(__args)...) |
485 | { } |
486 | |
487 | template<typename _Up, typename... _Args, |
488 | enable_if_t<is_constructible_v<_Tp, |
489 | initializer_list<_Up>&, |
490 | _Args...>, bool> = false> |
491 | constexpr explicit |
492 | _Optional_base(in_place_t, |
493 | initializer_list<_Up> __il, |
494 | _Args&&... __args) |
495 | : _M_payload(in_place, __il, std::forward<_Args>(__args)...) |
496 | { } |
497 | |
498 | // Copy and move constructors. |
499 | constexpr |
500 | _Optional_base(const _Optional_base& __other) |
501 | : _M_payload(__other._M_payload._M_engaged, __other._M_payload) |
502 | { } |
503 | |
504 | constexpr |
505 | _Optional_base(_Optional_base&& __other) |
506 | noexcept(is_nothrow_move_constructible_v<_Tp>) |
507 | : _M_payload(__other._M_payload._M_engaged, |
508 | std::move(__other._M_payload)) |
509 | { } |
510 | |
511 | // Assignment operators. |
512 | _Optional_base& operator=(const _Optional_base&) = default; |
513 | _Optional_base& operator=(_Optional_base&&) = default; |
514 | |
515 | _Optional_payload<_Tp> _M_payload; |
516 | }; |
517 | |
518 | template<typename _Tp> |
519 | struct _Optional_base<_Tp, false, true> |
520 | : _Optional_base_impl<_Tp, _Optional_base<_Tp>> |
521 | { |
522 | // Constructors for disengaged optionals. |
523 | constexpr _Optional_base() = default; |
524 | |
525 | // Constructors for engaged optionals. |
526 | template<typename... _Args, |
527 | enable_if_t<is_constructible_v<_Tp, _Args...>, bool> = false> |
528 | constexpr explicit |
529 | _Optional_base(in_place_t, _Args&&... __args) |
530 | : _M_payload(in_place, std::forward<_Args>(__args)...) |
531 | { } |
532 | |
533 | template<typename _Up, typename... _Args, |
534 | enable_if_t<is_constructible_v<_Tp, |
535 | initializer_list<_Up>&, |
536 | _Args...>, bool> = false> |
537 | constexpr explicit |
538 | _Optional_base(in_place_t, |
539 | initializer_list<_Up> __il, |
540 | _Args... __args) |
541 | : _M_payload(in_place, __il, std::forward<_Args>(__args)...) |
542 | { } |
543 | |
544 | // Copy and move constructors. |
545 | constexpr _Optional_base(const _Optional_base& __other) |
546 | : _M_payload(__other._M_payload._M_engaged, __other._M_payload) |
547 | { } |
548 | |
549 | constexpr _Optional_base(_Optional_base&& __other) = default; |
550 | |
551 | // Assignment operators. |
552 | _Optional_base& operator=(const _Optional_base&) = default; |
553 | _Optional_base& operator=(_Optional_base&&) = default; |
554 | |
555 | _Optional_payload<_Tp> _M_payload; |
556 | }; |
557 | |
558 | template<typename _Tp> |
559 | struct _Optional_base<_Tp, true, false> |
560 | : _Optional_base_impl<_Tp, _Optional_base<_Tp>> |
561 | { |
562 | // Constructors for disengaged optionals. |
563 | constexpr _Optional_base() = default; |
564 | |
565 | // Constructors for engaged optionals. |
566 | template<typename... _Args, |
567 | enable_if_t<is_constructible_v<_Tp, _Args...>, bool> = false> |
568 | constexpr explicit |
569 | _Optional_base(in_place_t, _Args&&... __args) |
570 | : _M_payload(in_place, std::forward<_Args>(__args)...) |
571 | { } |
572 | |
573 | template<typename _Up, typename... _Args, |
574 | enable_if_t<is_constructible_v<_Tp, |
575 | initializer_list<_Up>&, |
576 | _Args...>, bool> = false> |
577 | constexpr explicit |
578 | _Optional_base(in_place_t, |
579 | initializer_list<_Up> __il, |
580 | _Args&&... __args) |
581 | : _M_payload(in_place, __il, std::forward<_Args>(__args)...) |
582 | { } |
583 | |
584 | // Copy and move constructors. |
585 | constexpr _Optional_base(const _Optional_base& __other) = default; |
586 | |
587 | constexpr |
588 | _Optional_base(_Optional_base&& __other) |
589 | noexcept(is_nothrow_move_constructible_v<_Tp>) |
590 | : _M_payload(__other._M_payload._M_engaged, |
591 | std::move(__other._M_payload)) |
592 | { } |
593 | |
594 | // Assignment operators. |
595 | _Optional_base& operator=(const _Optional_base&) = default; |
596 | _Optional_base& operator=(_Optional_base&&) = default; |
597 | |
598 | _Optional_payload<_Tp> _M_payload; |
599 | }; |
600 | |
601 | template<typename _Tp> |
602 | struct _Optional_base<_Tp, true, true> |
603 | : _Optional_base_impl<_Tp, _Optional_base<_Tp>> |
604 | { |
605 | // Constructors for disengaged optionals. |
606 | constexpr _Optional_base() = default; |
607 | |
608 | // Constructors for engaged optionals. |
609 | template<typename... _Args, |
610 | enable_if_t<is_constructible_v<_Tp, _Args...>, bool> = false> |
611 | constexpr explicit |
612 | _Optional_base(in_place_t, _Args&&... __args) |
613 | : _M_payload(in_place, std::forward<_Args>(__args)...) |
614 | { } |
615 | |
616 | template<typename _Up, typename... _Args, |
617 | enable_if_t<is_constructible_v<_Tp, |
618 | initializer_list<_Up>&, |
619 | _Args...>, bool> = false> |
620 | constexpr explicit |
621 | _Optional_base(in_place_t, |
622 | initializer_list<_Up> __il, |
623 | _Args&&... __args) |
624 | : _M_payload(in_place, __il, std::forward<_Args>(__args)...) |
625 | { } |
626 | |
627 | // Copy and move constructors. |
628 | constexpr _Optional_base(const _Optional_base& __other) = default; |
629 | constexpr _Optional_base(_Optional_base&& __other) = default; |
630 | |
631 | // Assignment operators. |
632 | _Optional_base& operator=(const _Optional_base&) = default; |
633 | _Optional_base& operator=(_Optional_base&&) = default; |
634 | |
635 | _Optional_payload<_Tp> _M_payload; |
636 | }; |
637 | |
638 | template<typename _Tp> |
639 | class optional; |
640 | |
641 | template<typename _Tp, typename _Up> |
642 | using __converts_from_optional = |
643 | __or_<is_constructible<_Tp, const optional<_Up>&>, |
644 | is_constructible<_Tp, optional<_Up>&>, |
645 | is_constructible<_Tp, const optional<_Up>&&>, |
646 | is_constructible<_Tp, optional<_Up>&&>, |
647 | is_convertible<const optional<_Up>&, _Tp>, |
648 | is_convertible<optional<_Up>&, _Tp>, |
649 | is_convertible<const optional<_Up>&&, _Tp>, |
650 | is_convertible<optional<_Up>&&, _Tp>>; |
651 | |
652 | template<typename _Tp, typename _Up> |
653 | using __assigns_from_optional = |
654 | __or_<is_assignable<_Tp&, const optional<_Up>&>, |
655 | is_assignable<_Tp&, optional<_Up>&>, |
656 | is_assignable<_Tp&, const optional<_Up>&&>, |
657 | is_assignable<_Tp&, optional<_Up>&&>>; |
658 | |
659 | /** |
660 | * @brief Class template for optional values. |
661 | */ |
662 | template<typename _Tp> |
663 | class optional |
664 | : private _Optional_base<_Tp>, |
665 | private _Enable_copy_move< |
666 | // Copy constructor. |
667 | is_copy_constructible_v<_Tp>, |
668 | // Copy assignment. |
669 | __and_v<is_copy_constructible<_Tp>, is_copy_assignable<_Tp>>, |
670 | // Move constructor. |
671 | is_move_constructible_v<_Tp>, |
672 | // Move assignment. |
673 | __and_v<is_move_constructible<_Tp>, is_move_assignable<_Tp>>, |
674 | // Unique tag type. |
675 | optional<_Tp>> |
676 | { |
677 | static_assert(!is_same_v<remove_cv_t<_Tp>, nullopt_t>); |
678 | static_assert(!is_same_v<remove_cv_t<_Tp>, in_place_t>); |
679 | static_assert(!is_reference_v<_Tp>); |
680 | |
681 | private: |
682 | using _Base = _Optional_base<_Tp>; |
683 | |
684 | // SFINAE helpers |
685 | template<typename _Up> |
686 | using __not_self = __not_<is_same<optional, __remove_cvref_t<_Up>>>; |
687 | template<typename _Up> |
688 | using __not_tag = __not_<is_same<in_place_t, __remove_cvref_t<_Up>>>; |
689 | template<typename... _Cond> |
690 | using _Requires = enable_if_t<__and_v<_Cond...>, bool>; |
691 | |
692 | public: |
693 | using value_type = _Tp; |
694 | |
695 | constexpr optional() noexcept { } |
696 | |
697 | constexpr optional(nullopt_t) noexcept { } |
698 | |
699 | // Converting constructors for engaged optionals. |
700 | template<typename _Up = _Tp, |
701 | _Requires<__not_self<_Up>, __not_tag<_Up>, |
702 | is_constructible<_Tp, _Up>, |
703 | is_convertible<_Up, _Tp>> = true> |
704 | constexpr |
705 | optional(_Up&& __t) |
706 | noexcept(is_nothrow_constructible_v<_Tp, _Up>) |
707 | : _Base(std::in_place, std::forward<_Up>(__t)) { } |
708 | |
709 | template<typename _Up = _Tp, |
710 | _Requires<__not_self<_Up>, __not_tag<_Up>, |
711 | is_constructible<_Tp, _Up>, |
712 | __not_<is_convertible<_Up, _Tp>>> = false> |
713 | explicit constexpr |
714 | optional(_Up&& __t) |
715 | noexcept(is_nothrow_constructible_v<_Tp, _Up>) |
716 | : _Base(std::in_place, std::forward<_Up>(__t)) { } |
717 | |
718 | template<typename _Up, |
719 | _Requires<__not_<is_same<_Tp, _Up>>, |
720 | is_constructible<_Tp, const _Up&>, |
721 | is_convertible<const _Up&, _Tp>, |
722 | __not_<__converts_from_optional<_Tp, _Up>>> = true> |
723 | constexpr |
724 | optional(const optional<_Up>& __t) |
725 | noexcept(is_nothrow_constructible_v<_Tp, const _Up&>) |
726 | { |
727 | if (__t) |
728 | emplace(*__t); |
729 | } |
730 | |
731 | template<typename _Up, |
732 | _Requires<__not_<is_same<_Tp, _Up>>, |
733 | is_constructible<_Tp, const _Up&>, |
734 | __not_<is_convertible<const _Up&, _Tp>>, |
735 | __not_<__converts_from_optional<_Tp, _Up>>> = false> |
736 | explicit constexpr |
737 | optional(const optional<_Up>& __t) |
738 | noexcept(is_nothrow_constructible_v<_Tp, const _Up&>) |
739 | { |
740 | if (__t) |
741 | emplace(*__t); |
742 | } |
743 | |
744 | template<typename _Up, |
745 | _Requires<__not_<is_same<_Tp, _Up>>, |
746 | is_constructible<_Tp, _Up>, |
747 | is_convertible<_Up, _Tp>, |
748 | __not_<__converts_from_optional<_Tp, _Up>>> = true> |
749 | constexpr |
750 | optional(optional<_Up>&& __t) |
751 | noexcept(is_nothrow_constructible_v<_Tp, _Up>) |
752 | { |
753 | if (__t) |
754 | emplace(std::move(*__t)); |
755 | } |
756 | |
757 | template<typename _Up, |
758 | _Requires<__not_<is_same<_Tp, _Up>>, |
759 | is_constructible<_Tp, _Up>, |
760 | __not_<is_convertible<_Up, _Tp>>, |
761 | __not_<__converts_from_optional<_Tp, _Up>>> = false> |
762 | explicit constexpr |
763 | optional(optional<_Up>&& __t) |
764 | noexcept(is_nothrow_constructible_v<_Tp, _Up>) |
765 | { |
766 | if (__t) |
767 | emplace(std::move(*__t)); |
768 | } |
769 | |
770 | template<typename... _Args, |
771 | _Requires<is_constructible<_Tp, _Args...>> = false> |
772 | explicit constexpr |
773 | optional(in_place_t, _Args&&... __args) |
774 | noexcept(is_nothrow_constructible_v<_Tp, _Args...>) |
775 | : _Base(std::in_place, std::forward<_Args>(__args)...) { } |
776 | |
777 | template<typename _Up, typename... _Args, |
778 | _Requires<is_constructible<_Tp, |
779 | initializer_list<_Up>&, |
780 | _Args...>> = false> |
781 | explicit constexpr |
782 | optional(in_place_t, initializer_list<_Up> __il, _Args&&... __args) |
783 | noexcept(is_nothrow_constructible_v<_Tp, initializer_list<_Up>&, |
784 | _Args...>) |
785 | : _Base(std::in_place, __il, std::forward<_Args>(__args)...) { } |
786 | |
787 | |
788 | // Assignment operators. |
789 | optional& |
790 | operator=(nullopt_t) noexcept |
791 | { |
792 | this->_M_reset(); |
793 | return *this; |
794 | } |
795 | |
796 | template<typename _Up = _Tp> |
797 | enable_if_t<__and_v<__not_self<_Up>, |
798 | __not_<__and_<is_scalar<_Tp>, |
799 | is_same<_Tp, decay_t<_Up>>>>, |
800 | is_constructible<_Tp, _Up>, |
801 | is_assignable<_Tp&, _Up>>, |
802 | optional&> |
803 | operator=(_Up&& __u) |
804 | noexcept(__and_v<is_nothrow_constructible<_Tp, _Up>, |
805 | is_nothrow_assignable<_Tp&, _Up>>) |
806 | { |
807 | if (this->_M_is_engaged()) |
808 | this->_M_get() = std::forward<_Up>(__u); |
809 | else |
810 | this->_M_construct(std::forward<_Up>(__u)); |
811 | |
812 | return *this; |
813 | } |
814 | |
815 | template<typename _Up> |
816 | enable_if_t<__and_v<__not_<is_same<_Tp, _Up>>, |
817 | is_constructible<_Tp, const _Up&>, |
818 | is_assignable<_Tp&, const _Up&>, |
819 | __not_<__converts_from_optional<_Tp, _Up>>, |
820 | __not_<__assigns_from_optional<_Tp, _Up>>>, |
821 | optional&> |
822 | operator=(const optional<_Up>& __u) |
823 | noexcept(__and_v<is_nothrow_constructible<_Tp, const _Up&>, |
824 | is_nothrow_assignable<_Tp&, const _Up&>>) |
825 | { |
826 | if (__u) |
827 | { |
828 | if (this->_M_is_engaged()) |
829 | this->_M_get() = *__u; |
830 | else |
831 | this->_M_construct(*__u); |
832 | } |
833 | else |
834 | { |
835 | this->_M_reset(); |
836 | } |
837 | return *this; |
838 | } |
839 | |
840 | template<typename _Up> |
841 | enable_if_t<__and_v<__not_<is_same<_Tp, _Up>>, |
842 | is_constructible<_Tp, _Up>, |
843 | is_assignable<_Tp&, _Up>, |
844 | __not_<__converts_from_optional<_Tp, _Up>>, |
845 | __not_<__assigns_from_optional<_Tp, _Up>>>, |
846 | optional&> |
847 | operator=(optional<_Up>&& __u) |
848 | noexcept(__and_v<is_nothrow_constructible<_Tp, _Up>, |
849 | is_nothrow_assignable<_Tp&, _Up>>) |
850 | { |
851 | if (__u) |
852 | { |
853 | if (this->_M_is_engaged()) |
854 | this->_M_get() = std::move(*__u); |
855 | else |
856 | this->_M_construct(std::move(*__u)); |
857 | } |
858 | else |
859 | { |
860 | this->_M_reset(); |
861 | } |
862 | |
863 | return *this; |
864 | } |
865 | |
866 | template<typename... _Args> |
867 | enable_if_t<is_constructible_v<_Tp, _Args...>, _Tp&> |
868 | emplace(_Args&&... __args) |
869 | noexcept(is_nothrow_constructible_v<_Tp, _Args...>) |
870 | { |
871 | this->_M_reset(); |
872 | this->_M_construct(std::forward<_Args>(__args)...); |
873 | return this->_M_get(); |
874 | } |
875 | |
876 | template<typename _Up, typename... _Args> |
877 | enable_if_t<is_constructible_v<_Tp, initializer_list<_Up>&, _Args...>, |
878 | _Tp&> |
879 | emplace(initializer_list<_Up> __il, _Args&&... __args) |
880 | noexcept(is_nothrow_constructible_v<_Tp, initializer_list<_Up>&, |
881 | _Args...>) |
882 | { |
883 | this->_M_reset(); |
884 | this->_M_construct(__il, std::forward<_Args>(__args)...); |
885 | return this->_M_get(); |
886 | } |
887 | |
888 | // Destructor is implicit, implemented in _Optional_base. |
889 | |
890 | // Swap. |
891 | void |
892 | swap(optional& __other) |
893 | noexcept(is_nothrow_move_constructible_v<_Tp> |
894 | && is_nothrow_swappable_v<_Tp>) |
895 | { |
896 | using std::swap; |
897 | |
898 | if (this->_M_is_engaged() && __other._M_is_engaged()) |
899 | swap(this->_M_get(), __other._M_get()); |
900 | else if (this->_M_is_engaged()) |
901 | { |
902 | __other._M_construct(std::move(this->_M_get())); |
903 | this->_M_destruct(); |
904 | } |
905 | else if (__other._M_is_engaged()) |
906 | { |
907 | this->_M_construct(std::move(__other._M_get())); |
908 | __other._M_destruct(); |
909 | } |
910 | } |
911 | |
912 | // Observers. |
913 | constexpr const _Tp* |
914 | operator->() const noexcept |
915 | { return std::__addressof(this->_M_get()); } |
916 | |
917 | constexpr _Tp* |
918 | operator->() noexcept |
919 | { return std::__addressof(this->_M_get()); } |
920 | |
921 | constexpr const _Tp& |
922 | operator*() const& noexcept |
923 | { return this->_M_get(); } |
924 | |
925 | constexpr _Tp& |
926 | operator*()& noexcept |
927 | { return this->_M_get(); } |
928 | |
929 | constexpr _Tp&& |
930 | operator*()&& noexcept |
931 | { return std::move(this->_M_get()); } |
932 | |
933 | constexpr const _Tp&& |
934 | operator*() const&& noexcept |
935 | { return std::move(this->_M_get()); } |
936 | |
937 | constexpr explicit operator bool() const noexcept |
938 | { return this->_M_is_engaged(); } |
939 | |
940 | constexpr bool has_value() const noexcept |
941 | { return this->_M_is_engaged(); } |
942 | |
943 | constexpr const _Tp& |
944 | value() const& |
945 | { |
946 | return this->_M_is_engaged() |
947 | ? this->_M_get() |
948 | : (__throw_bad_optional_access(), this->_M_get()); |
949 | } |
950 | |
951 | constexpr _Tp& |
952 | value()& |
953 | { |
954 | return this->_M_is_engaged() |
955 | ? this->_M_get() |
956 | : (__throw_bad_optional_access(), this->_M_get()); |
957 | } |
958 | |
959 | constexpr _Tp&& |
960 | value()&& |
961 | { |
962 | return this->_M_is_engaged() |
963 | ? std::move(this->_M_get()) |
964 | : (__throw_bad_optional_access(), std::move(this->_M_get())); |
965 | } |
966 | |
967 | constexpr const _Tp&& |
968 | value() const&& |
969 | { |
970 | return this->_M_is_engaged() |
971 | ? std::move(this->_M_get()) |
972 | : (__throw_bad_optional_access(), std::move(this->_M_get())); |
973 | } |
974 | |
975 | template<typename _Up> |
976 | constexpr _Tp |
977 | value_or(_Up&& __u) const& |
978 | { |
979 | static_assert(is_copy_constructible_v<_Tp>); |
980 | static_assert(is_convertible_v<_Up&&, _Tp>); |
981 | |
982 | return this->_M_is_engaged() |
983 | ? this->_M_get() : static_cast<_Tp>(std::forward<_Up>(__u)); |
984 | } |
985 | |
986 | template<typename _Up> |
987 | constexpr _Tp |
988 | value_or(_Up&& __u) && |
989 | { |
990 | static_assert(is_move_constructible_v<_Tp>); |
991 | static_assert(is_convertible_v<_Up&&, _Tp>); |
992 | |
993 | return this->_M_is_engaged() |
994 | ? std::move(this->_M_get()) |
995 | : static_cast<_Tp>(std::forward<_Up>(__u)); |
996 | } |
997 | |
998 | void reset() noexcept { this->_M_reset(); } |
999 | }; |
1000 | |
1001 | template<typename _Tp> |
1002 | using __optional_relop_t = |
1003 | enable_if_t<is_convertible<_Tp, bool>::value, bool>; |
1004 | |
1005 | template<typename _Tp, typename _Up> |
1006 | using __optional_eq_t = __optional_relop_t< |
1007 | decltype(std::declval<const _Tp&>() == std::declval<const _Up&>()) |
1008 | >; |
1009 | |
1010 | template<typename _Tp, typename _Up> |
1011 | using __optional_ne_t = __optional_relop_t< |
1012 | decltype(std::declval<const _Tp&>() != std::declval<const _Up&>()) |
1013 | >; |
1014 | |
1015 | template<typename _Tp, typename _Up> |
1016 | using __optional_lt_t = __optional_relop_t< |
1017 | decltype(std::declval<const _Tp&>() < std::declval<const _Up&>()) |
1018 | >; |
1019 | |
1020 | template<typename _Tp, typename _Up> |
1021 | using __optional_gt_t = __optional_relop_t< |
1022 | decltype(std::declval<const _Tp&>() > std::declval<const _Up&>()) |
1023 | >; |
1024 | |
1025 | template<typename _Tp, typename _Up> |
1026 | using __optional_le_t = __optional_relop_t< |
1027 | decltype(std::declval<const _Tp&>() <= std::declval<const _Up&>()) |
1028 | >; |
1029 | |
1030 | template<typename _Tp, typename _Up> |
1031 | using __optional_ge_t = __optional_relop_t< |
1032 | decltype(std::declval<const _Tp&>() >= std::declval<const _Up&>()) |
1033 | >; |
1034 | |
1035 | // Comparisons between optional values. |
1036 | template<typename _Tp, typename _Up> |
1037 | constexpr auto |
1038 | operator==(const optional<_Tp>& __lhs, const optional<_Up>& __rhs) |
1039 | -> __optional_eq_t<_Tp, _Up> |
1040 | { |
1041 | return static_cast<bool>(__lhs) == static_cast<bool>(__rhs) |
1042 | && (!__lhs || *__lhs == *__rhs); |
1043 | } |
1044 | |
1045 | template<typename _Tp, typename _Up> |
1046 | constexpr auto |
1047 | operator!=(const optional<_Tp>& __lhs, const optional<_Up>& __rhs) |
1048 | -> __optional_ne_t<_Tp, _Up> |
1049 | { |
1050 | return static_cast<bool>(__lhs) != static_cast<bool>(__rhs) |
1051 | || (static_cast<bool>(__lhs) && *__lhs != *__rhs); |
1052 | } |
1053 | |
1054 | template<typename _Tp, typename _Up> |
1055 | constexpr auto |
1056 | operator<(const optional<_Tp>& __lhs, const optional<_Up>& __rhs) |
1057 | -> __optional_lt_t<_Tp, _Up> |
1058 | { |
1059 | return static_cast<bool>(__rhs) && (!__lhs || *__lhs < *__rhs); |
1060 | } |
1061 | |
1062 | template<typename _Tp, typename _Up> |
1063 | constexpr auto |
1064 | operator>(const optional<_Tp>& __lhs, const optional<_Up>& __rhs) |
1065 | -> __optional_gt_t<_Tp, _Up> |
1066 | { |
1067 | return static_cast<bool>(__lhs) && (!__rhs || *__lhs > *__rhs); |
1068 | } |
1069 | |
1070 | template<typename _Tp, typename _Up> |
1071 | constexpr auto |
1072 | operator<=(const optional<_Tp>& __lhs, const optional<_Up>& __rhs) |
1073 | -> __optional_le_t<_Tp, _Up> |
1074 | { |
1075 | return !__lhs || (static_cast<bool>(__rhs) && *__lhs <= *__rhs); |
1076 | } |
1077 | |
1078 | template<typename _Tp, typename _Up> |
1079 | constexpr auto |
1080 | operator>=(const optional<_Tp>& __lhs, const optional<_Up>& __rhs) |
1081 | -> __optional_ge_t<_Tp, _Up> |
1082 | { |
1083 | return !__rhs || (static_cast<bool>(__lhs) && *__lhs >= *__rhs); |
1084 | } |
1085 | |
1086 | #ifdef __cpp_lib_three_way_comparison |
1087 | template<typename _Tp, three_way_comparable_with<_Tp> _Up> |
1088 | constexpr compare_three_way_result_t<_Tp, _Up> |
1089 | operator<=>(const optional<_Tp>& __x, const optional<_Up>& __y) |
1090 | { |
1091 | return __x && __y ? *__x <=> *__y : bool(__x) <=> bool(__y); |
1092 | } |
1093 | #endif |
1094 | |
1095 | // Comparisons with nullopt. |
1096 | template<typename _Tp> |
1097 | constexpr bool |
1098 | operator==(const optional<_Tp>& __lhs, nullopt_t) noexcept |
1099 | { return !__lhs; } |
1100 | |
1101 | #ifdef __cpp_lib_three_way_comparison |
1102 | template<typename _Tp> |
1103 | constexpr strong_ordering |
1104 | operator<=>(const optional<_Tp>& __x, nullopt_t) noexcept |
1105 | { return bool(__x) <=> false; } |
1106 | #else |
1107 | template<typename _Tp> |
1108 | constexpr bool |
1109 | operator==(nullopt_t, const optional<_Tp>& __rhs) noexcept |
1110 | { return !__rhs; } |
1111 | |
1112 | template<typename _Tp> |
1113 | constexpr bool |
1114 | operator!=(const optional<_Tp>& __lhs, nullopt_t) noexcept |
1115 | { return static_cast<bool>(__lhs); } |
1116 | |
1117 | template<typename _Tp> |
1118 | constexpr bool |
1119 | operator!=(nullopt_t, const optional<_Tp>& __rhs) noexcept |
1120 | { return static_cast<bool>(__rhs); } |
1121 | |
1122 | template<typename _Tp> |
1123 | constexpr bool |
1124 | operator<(const optional<_Tp>& /* __lhs */, nullopt_t) noexcept |
1125 | { return false; } |
1126 | |
1127 | template<typename _Tp> |
1128 | constexpr bool |
1129 | operator<(nullopt_t, const optional<_Tp>& __rhs) noexcept |
1130 | { return static_cast<bool>(__rhs); } |
1131 | |
1132 | template<typename _Tp> |
1133 | constexpr bool |
1134 | operator>(const optional<_Tp>& __lhs, nullopt_t) noexcept |
1135 | { return static_cast<bool>(__lhs); } |
1136 | |
1137 | template<typename _Tp> |
1138 | constexpr bool |
1139 | operator>(nullopt_t, const optional<_Tp>& /* __rhs */) noexcept |
1140 | { return false; } |
1141 | |
1142 | template<typename _Tp> |
1143 | constexpr bool |
1144 | operator<=(const optional<_Tp>& __lhs, nullopt_t) noexcept |
1145 | { return !__lhs; } |
1146 | |
1147 | template<typename _Tp> |
1148 | constexpr bool |
1149 | operator<=(nullopt_t, const optional<_Tp>& /* __rhs */) noexcept |
1150 | { return true; } |
1151 | |
1152 | template<typename _Tp> |
1153 | constexpr bool |
1154 | operator>=(const optional<_Tp>& /* __lhs */, nullopt_t) noexcept |
1155 | { return true; } |
1156 | |
1157 | template<typename _Tp> |
1158 | constexpr bool |
1159 | operator>=(nullopt_t, const optional<_Tp>& __rhs) noexcept |
1160 | { return !__rhs; } |
1161 | #endif // three-way-comparison |
1162 | |
1163 | // Comparisons with value type. |
1164 | template<typename _Tp, typename _Up> |
1165 | constexpr auto |
1166 | operator==(const optional<_Tp>& __lhs, const _Up& __rhs) |
1167 | -> __optional_eq_t<_Tp, _Up> |
1168 | { return __lhs && *__lhs == __rhs; } |
1169 | |
1170 | template<typename _Tp, typename _Up> |
1171 | constexpr auto |
1172 | operator==(const _Up& __lhs, const optional<_Tp>& __rhs) |
1173 | -> __optional_eq_t<_Up, _Tp> |
1174 | { return __rhs && __lhs == *__rhs; } |
1175 | |
1176 | template<typename _Tp, typename _Up> |
1177 | constexpr auto |
1178 | operator!=(const optional<_Tp>& __lhs, const _Up& __rhs) |
1179 | -> __optional_ne_t<_Tp, _Up> |
1180 | { return !__lhs || *__lhs != __rhs; } |
1181 | |
1182 | template<typename _Tp, typename _Up> |
1183 | constexpr auto |
1184 | operator!=(const _Up& __lhs, const optional<_Tp>& __rhs) |
1185 | -> __optional_ne_t<_Up, _Tp> |
1186 | { return !__rhs || __lhs != *__rhs; } |
1187 | |
1188 | template<typename _Tp, typename _Up> |
1189 | constexpr auto |
1190 | operator<(const optional<_Tp>& __lhs, const _Up& __rhs) |
1191 | -> __optional_lt_t<_Tp, _Up> |
1192 | { return !__lhs || *__lhs < __rhs; } |
1193 | |
1194 | template<typename _Tp, typename _Up> |
1195 | constexpr auto |
1196 | operator<(const _Up& __lhs, const optional<_Tp>& __rhs) |
1197 | -> __optional_lt_t<_Up, _Tp> |
1198 | { return __rhs && __lhs < *__rhs; } |
1199 | |
1200 | template<typename _Tp, typename _Up> |
1201 | constexpr auto |
1202 | operator>(const optional<_Tp>& __lhs, const _Up& __rhs) |
1203 | -> __optional_gt_t<_Tp, _Up> |
1204 | { return __lhs && *__lhs > __rhs; } |
1205 | |
1206 | template<typename _Tp, typename _Up> |
1207 | constexpr auto |
1208 | operator>(const _Up& __lhs, const optional<_Tp>& __rhs) |
1209 | -> __optional_gt_t<_Up, _Tp> |
1210 | { return !__rhs || __lhs > *__rhs; } |
1211 | |
1212 | template<typename _Tp, typename _Up> |
1213 | constexpr auto |
1214 | operator<=(const optional<_Tp>& __lhs, const _Up& __rhs) |
1215 | -> __optional_le_t<_Tp, _Up> |
1216 | { return !__lhs || *__lhs <= __rhs; } |
1217 | |
1218 | template<typename _Tp, typename _Up> |
1219 | constexpr auto |
1220 | operator<=(const _Up& __lhs, const optional<_Tp>& __rhs) |
1221 | -> __optional_le_t<_Up, _Tp> |
1222 | { return __rhs && __lhs <= *__rhs; } |
1223 | |
1224 | template<typename _Tp, typename _Up> |
1225 | constexpr auto |
1226 | operator>=(const optional<_Tp>& __lhs, const _Up& __rhs) |
1227 | -> __optional_ge_t<_Tp, _Up> |
1228 | { return __lhs && *__lhs >= __rhs; } |
1229 | |
1230 | template<typename _Tp, typename _Up> |
1231 | constexpr auto |
1232 | operator>=(const _Up& __lhs, const optional<_Tp>& __rhs) |
1233 | -> __optional_ge_t<_Up, _Tp> |
1234 | { return !__rhs || __lhs >= *__rhs; } |
1235 | |
1236 | #ifdef __cpp_lib_three_way_comparison |
1237 | template<typename _Tp> |
1238 | inline constexpr bool __is_optional_v = false; |
1239 | template<typename _Tp> |
1240 | inline constexpr bool __is_optional_v<optional<_Tp>> = true; |
1241 | |
1242 | template<typename _Tp, typename _Up> |
1243 | requires (!__is_optional_v<_Up>) |
1244 | && three_way_comparable_with<_Tp, _Up> |
1245 | constexpr compare_three_way_result_t<_Tp, _Up> |
1246 | operator<=>(const optional<_Tp>& __x, const _Up& __v) |
1247 | { return bool(__x) ? *__x <=> __v : strong_ordering::less; } |
1248 | #endif |
1249 | |
1250 | // Swap and creation functions. |
1251 | |
1252 | // _GLIBCXX_RESOLVE_LIB_DEFECTS |
1253 | // 2748. swappable traits for optionals |
1254 | template<typename _Tp> |
1255 | inline enable_if_t<is_move_constructible_v<_Tp> && is_swappable_v<_Tp>> |
1256 | swap(optional<_Tp>& __lhs, optional<_Tp>& __rhs) |
1257 | noexcept(noexcept(__lhs.swap(__rhs))) |
1258 | { __lhs.swap(__rhs); } |
1259 | |
1260 | template<typename _Tp> |
1261 | enable_if_t<!(is_move_constructible_v<_Tp> && is_swappable_v<_Tp>)> |
1262 | swap(optional<_Tp>&, optional<_Tp>&) = delete; |
1263 | |
1264 | template<typename _Tp> |
1265 | constexpr |
1266 | enable_if_t<is_constructible_v<decay_t<_Tp>, _Tp>, |
1267 | optional<decay_t<_Tp>>> |
1268 | make_optional(_Tp&& __t) |
1269 | noexcept(is_nothrow_constructible_v<optional<decay_t<_Tp>>, _Tp>) |
1270 | { return optional<decay_t<_Tp>>{ std::forward<_Tp>(__t) }; } |
1271 | |
1272 | template<typename _Tp, typename... _Args> |
1273 | constexpr |
1274 | enable_if_t<is_constructible_v<_Tp, _Args...>, |
1275 | optional<_Tp>> |
1276 | make_optional(_Args&&... __args) |
1277 | noexcept(is_nothrow_constructible_v<_Tp, _Args...>) |
1278 | { return optional<_Tp>{ in_place, std::forward<_Args>(__args)... }; } |
1279 | |
1280 | template<typename _Tp, typename _Up, typename... _Args> |
1281 | constexpr |
1282 | enable_if_t<is_constructible_v<_Tp, initializer_list<_Up>&, _Args...>, |
1283 | optional<_Tp>> |
1284 | make_optional(initializer_list<_Up> __il, _Args&&... __args) |
1285 | noexcept(is_nothrow_constructible_v<_Tp, initializer_list<_Up>&, _Args...>) |
1286 | { return optional<_Tp>{ in_place, __il, std::forward<_Args>(__args)... }; } |
1287 | |
1288 | // Hash. |
1289 | |
1290 | template<typename _Tp, typename _Up = remove_const_t<_Tp>, |
1291 | bool = __poison_hash<_Up>::__enable_hash_call> |
1292 | struct __optional_hash_call_base |
1293 | { |
1294 | size_t |
1295 | operator()(const optional<_Tp>& __t) const |
1296 | noexcept(noexcept(hash<_Up>{}(*__t))) |
1297 | { |
1298 | // We pick an arbitrary hash for disengaged optionals which hopefully |
1299 | // usual values of _Tp won't typically hash to. |
1300 | constexpr size_t __magic_disengaged_hash = static_cast<size_t>(-3333); |
1301 | return __t ? hash<_Up>{}(*__t) : __magic_disengaged_hash; |
1302 | } |
1303 | }; |
1304 | |
1305 | template<typename _Tp, typename _Up> |
1306 | struct __optional_hash_call_base<_Tp, _Up, false> {}; |
1307 | |
1308 | template<typename _Tp> |
1309 | struct hash<optional<_Tp>> |
1310 | : private __poison_hash<remove_const_t<_Tp>>, |
1311 | public __optional_hash_call_base<_Tp> |
1312 | { |
1313 | using result_type [[__deprecated__]] = size_t; |
1314 | using argument_type [[__deprecated__]] = optional<_Tp>; |
1315 | }; |
1316 | |
1317 | template<typename _Tp> |
1318 | struct __is_fast_hash<hash<optional<_Tp>>> : __is_fast_hash<hash<_Tp>> |
1319 | { }; |
1320 | |
1321 | /// @} |
1322 | |
1323 | #if __cpp_deduction_guides >= 201606 |
1324 | template <typename _Tp> optional(_Tp) -> optional<_Tp>; |
1325 | #endif |
1326 | |
1327 | _GLIBCXX_END_NAMESPACE_VERSION |
1328 | } // namespace std |
1329 | |
1330 | #endif // C++17 |
1331 | |
1332 | #endif // _GLIBCXX_OPTIONAL |
1333 | |