]> git.ipfire.org Git - thirdparty/gcc.git/blob - libstdc++-v3/include/std/optional
Implement P0513R0, Poisoning the Hash.
[thirdparty/gcc.git] / libstdc++-v3 / include / std / optional
1 // <optional> -*- C++ -*-
2
3 // Copyright (C) 2013-2016 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 #if __cplusplus <= 201402L
33 # include <bits/c++17_warning.h>
34 #else
35
36 #include <utility>
37 #include <type_traits>
38 #include <stdexcept>
39 #include <new>
40 #include <initializer_list>
41 #include <bits/functexcept.h>
42 #include <bits/functional_hash.h>
43 #include <bits/enable_special_members.h>
44
45 namespace std _GLIBCXX_VISIBILITY(default)
46 {
47 _GLIBCXX_BEGIN_NAMESPACE_VERSION
48
49 /**
50 * @addtogroup utilities
51 * @{
52 */
53
54 template<typename _Tp>
55 class optional;
56
57 /// Tag type to disengage optional objects.
58 struct nullopt_t
59 {
60 // Do not user-declare default constructor at all for
61 // optional_value = {} syntax to work.
62 // nullopt_t() = delete;
63
64 // Used for constructing nullopt.
65 enum class _Construct { _Token };
66
67 // Must be constexpr for nullopt_t to be literal.
68 explicit constexpr nullopt_t(_Construct) { }
69 };
70
71 /// Tag to disengage optional objects.
72 constexpr nullopt_t nullopt { nullopt_t::_Construct::_Token };
73
74 /**
75 * @brief Exception class thrown when a disengaged optional object is
76 * dereferenced.
77 * @ingroup exceptions
78 */
79 class bad_optional_access : public logic_error
80 {
81 // XXX See LEWG 72, https://issues.isocpp.org/show_bug.cgi?id=72
82 public:
83 bad_optional_access() : logic_error("bad optional access") { }
84 // XXX This constructor is non-standard. Should not be inline
85 explicit bad_optional_access(const char* __arg) : logic_error(__arg) { }
86
87 virtual ~bad_optional_access() noexcept = default;
88 };
89
90 void
91 __throw_bad_optional_access(const char*)
92 __attribute__((__noreturn__));
93
94 // XXX Does not belong here.
95 inline void
96 __throw_bad_optional_access(const char* __s)
97 { _GLIBCXX_THROW_OR_ABORT(bad_optional_access(__s)); }
98
99 /**
100 * @brief Class template that holds the necessary state for @ref optional
101 * and that has the responsibility for construction and the special members.
102 *
103 * Such a separate base class template is necessary in order to
104 * conditionally enable the special members (e.g. copy/move constructors).
105 * Note that this means that @ref _Optional_base implements the
106 * functionality for copy and move assignment, but not for converting
107 * assignment.
108 *
109 * @see optional, _Enable_special_members
110 */
111 template<typename _Tp, bool _ShouldProvideDestructor =
112 !is_trivially_destructible<_Tp>::value>
113 class _Optional_base
114 {
115 private:
116 // Remove const to avoid prohibition of reusing object storage for
117 // const-qualified types in [3.8/9]. This is strictly internal
118 // and even optional itself is oblivious to it.
119 using _Stored_type = remove_const_t<_Tp>;
120
121 public:
122
123 // Constructors for disengaged optionals.
124 constexpr _Optional_base() noexcept
125 : _M_empty{} { }
126
127 constexpr _Optional_base(nullopt_t) noexcept
128 : _Optional_base{} { }
129
130 // Constructors for engaged optionals.
131 template<typename... _Args>
132 constexpr explicit _Optional_base(in_place_t, _Args&&... __args)
133 : _M_payload(std::forward<_Args>(__args)...), _M_engaged(true) { }
134
135 template<typename _Up, typename... _Args,
136 enable_if_t<is_constructible<_Tp,
137 initializer_list<_Up>&,
138 _Args&&...>::value,
139 int>...>
140 constexpr explicit _Optional_base(in_place_t,
141 initializer_list<_Up> __il,
142 _Args&&... __args)
143 : _M_payload(__il, std::forward<_Args>(__args)...),
144 _M_engaged(true) { }
145
146 // Copy and move constructors.
147 _Optional_base(const _Optional_base& __other)
148 {
149 if (__other._M_engaged)
150 this->_M_construct(__other._M_get());
151 }
152
153 _Optional_base(_Optional_base&& __other)
154 noexcept(is_nothrow_move_constructible<_Tp>())
155 {
156 if (__other._M_engaged)
157 this->_M_construct(std::move(__other._M_get()));
158 }
159
160 // Assignment operators.
161 _Optional_base&
162 operator=(const _Optional_base& __other)
163 {
164 if (this->_M_engaged && __other._M_engaged)
165 this->_M_get() = __other._M_get();
166 else
167 {
168 if (__other._M_engaged)
169 this->_M_construct(__other._M_get());
170 else
171 this->_M_reset();
172 }
173
174 return *this;
175 }
176
177 _Optional_base&
178 operator=(_Optional_base&& __other)
179 noexcept(__and_<is_nothrow_move_constructible<_Tp>,
180 is_nothrow_move_assignable<_Tp>>())
181 {
182 if (this->_M_engaged && __other._M_engaged)
183 this->_M_get() = std::move(__other._M_get());
184 else
185 {
186 if (__other._M_engaged)
187 this->_M_construct(std::move(__other._M_get()));
188 else
189 this->_M_reset();
190 }
191 return *this;
192 }
193
194 // Destructor.
195 ~_Optional_base()
196 {
197 if (this->_M_engaged)
198 this->_M_payload.~_Stored_type();
199 }
200
201 // The following functionality is also needed by optional, hence the
202 // protected accessibility.
203 protected:
204 constexpr bool _M_is_engaged() const noexcept
205 { return this->_M_engaged; }
206
207 // The _M_get operations have _M_engaged as a precondition.
208 constexpr _Tp&
209 _M_get() noexcept
210 { return _M_payload; }
211
212 constexpr const _Tp&
213 _M_get() const noexcept
214 { return _M_payload; }
215
216 // The _M_construct operation has !_M_engaged as a precondition
217 // while _M_destruct has _M_engaged as a precondition.
218 template<typename... _Args>
219 void
220 _M_construct(_Args&&... __args)
221 noexcept(is_nothrow_constructible<_Stored_type, _Args...>())
222 {
223 ::new (std::__addressof(this->_M_payload))
224 _Stored_type(std::forward<_Args>(__args)...);
225 this->_M_engaged = true;
226 }
227
228 void
229 _M_destruct()
230 {
231 this->_M_engaged = false;
232 this->_M_payload.~_Stored_type();
233 }
234
235 // _M_reset is a 'safe' operation with no precondition.
236 void
237 _M_reset()
238 {
239 if (this->_M_engaged)
240 this->_M_destruct();
241 }
242
243 private:
244 struct _Empty_byte { };
245 union {
246 _Empty_byte _M_empty;
247 _Stored_type _M_payload;
248 };
249 bool _M_engaged = false;
250 };
251
252 /// Partial specialization that is exactly identical to the primary template
253 /// save for not providing a destructor, to fulfill triviality requirements.
254 template<typename _Tp>
255 class _Optional_base<_Tp, false>
256 {
257 private:
258 using _Stored_type = remove_const_t<_Tp>;
259
260 public:
261 constexpr _Optional_base() noexcept
262 : _M_empty{} { }
263
264 constexpr _Optional_base(nullopt_t) noexcept
265 : _Optional_base{} { }
266
267 template<typename... _Args>
268 constexpr explicit _Optional_base(in_place_t, _Args&&... __args)
269 : _M_payload(std::forward<_Args>(__args)...), _M_engaged(true) { }
270
271 template<typename _Up, typename... _Args,
272 enable_if_t<is_constructible<_Tp,
273 initializer_list<_Up>&,
274 _Args&&...>::value,
275 int>...>
276 constexpr explicit _Optional_base(in_place_t,
277 initializer_list<_Up> __il,
278 _Args&&... __args)
279 : _M_payload(__il, std::forward<_Args>(__args)...),
280 _M_engaged(true) { }
281
282 _Optional_base(const _Optional_base& __other)
283 {
284 if (__other._M_engaged)
285 this->_M_construct(__other._M_get());
286 }
287
288 _Optional_base(_Optional_base&& __other)
289 noexcept(is_nothrow_move_constructible<_Tp>())
290 {
291 if (__other._M_engaged)
292 this->_M_construct(std::move(__other._M_get()));
293 }
294
295 _Optional_base&
296 operator=(const _Optional_base& __other)
297 {
298 if (this->_M_engaged && __other._M_engaged)
299 this->_M_get() = __other._M_get();
300 else
301 {
302 if (__other._M_engaged)
303 this->_M_construct(__other._M_get());
304 else
305 this->_M_reset();
306 }
307 return *this;
308 }
309
310 _Optional_base&
311 operator=(_Optional_base&& __other)
312 noexcept(__and_<is_nothrow_move_constructible<_Tp>,
313 is_nothrow_move_assignable<_Tp>>())
314 {
315 if (this->_M_engaged && __other._M_engaged)
316 this->_M_get() = std::move(__other._M_get());
317 else
318 {
319 if (__other._M_engaged)
320 this->_M_construct(std::move(__other._M_get()));
321 else
322 this->_M_reset();
323 }
324 return *this;
325 }
326
327 // Sole difference
328 // ~_Optional_base() noexcept = default;
329
330 protected:
331 constexpr bool _M_is_engaged() const noexcept
332 { return this->_M_engaged; }
333
334 constexpr _Tp&
335 _M_get() noexcept
336 { return _M_payload; }
337
338 constexpr const _Tp&
339 _M_get() const noexcept
340 { return _M_payload; }
341
342 template<typename... _Args>
343 void
344 _M_construct(_Args&&... __args)
345 noexcept(is_nothrow_constructible<_Stored_type, _Args...>())
346 {
347 ::new (std::__addressof(this->_M_payload))
348 _Stored_type(std::forward<_Args>(__args)...);
349 this->_M_engaged = true;
350 }
351
352 void
353 _M_destruct()
354 {
355 this->_M_engaged = false;
356 this->_M_payload.~_Stored_type();
357 }
358
359 void
360 _M_reset()
361 {
362 if (this->_M_engaged)
363 this->_M_destruct();
364 }
365
366 private:
367 struct _Empty_byte { };
368 union
369 {
370 _Empty_byte _M_empty;
371 _Stored_type _M_payload;
372 };
373 bool _M_engaged = false;
374 };
375
376 template<typename _Tp>
377 class optional;
378
379 template<typename _Tp, typename _Up>
380 using __converts_from_optional =
381 __or_<is_constructible<_Tp, const optional<_Up>&>,
382 is_constructible<_Tp, optional<_Up>&>,
383 is_constructible<_Tp, const optional<_Up>&&>,
384 is_constructible<_Tp, optional<_Up>&&>,
385 is_convertible<const optional<_Up>&, _Tp>,
386 is_convertible<optional<_Up>&, _Tp>,
387 is_convertible<const optional<_Up>&&, _Tp>,
388 is_convertible<optional<_Up>&&, _Tp>>;
389
390 template<typename _Tp, typename _Up>
391 using __assigns_from_optional =
392 __or_<is_assignable<_Tp&, const optional<_Up>&>,
393 is_assignable<_Tp&, optional<_Up>&>,
394 is_assignable<_Tp&, const optional<_Up>&&>,
395 is_assignable<_Tp&, optional<_Up>&&>>;
396
397 /**
398 * @brief Class template for optional values.
399 */
400 template<typename _Tp>
401 class optional
402 : private _Optional_base<_Tp>,
403 private _Enable_copy_move<
404 // Copy constructor.
405 is_copy_constructible<_Tp>::value,
406 // Copy assignment.
407 __and_<is_copy_constructible<_Tp>, is_copy_assignable<_Tp>>::value,
408 // Move constructor.
409 is_move_constructible<_Tp>::value,
410 // Move assignment.
411 __and_<is_move_constructible<_Tp>, is_move_assignable<_Tp>>::value,
412 // Unique tag type.
413 optional<_Tp>>
414 {
415 static_assert(__and_<__not_<is_same<remove_cv_t<_Tp>, nullopt_t>>,
416 __not_<is_same<remove_cv_t<_Tp>, in_place_t>>,
417 __not_<is_reference<_Tp>>>(),
418 "Invalid instantiation of optional<T>");
419
420 private:
421 using _Base = _Optional_base<_Tp>;
422
423 public:
424 using value_type = _Tp;
425
426 constexpr optional() = default;
427
428 constexpr optional(nullopt_t) noexcept
429 : _Base(nullopt) { }
430
431 // Converting constructors for engaged optionals.
432 template <typename _Up = _Tp,
433 enable_if_t<__and_<
434 __not_<is_same<optional<_Tp>, decay_t<_Up>>>,
435 is_constructible<_Tp, _Up&&>,
436 is_convertible<_Up&&, _Tp>
437 >::value, bool> = true>
438 constexpr optional(_Up&& __t)
439 : _Base(std::in_place, std::forward<_Up>(__t)) { }
440
441 template <typename _Up = _Tp,
442 enable_if_t<__and_<
443 __not_<is_same<optional<_Tp>, decay_t<_Up>>>,
444 is_constructible<_Tp, _Up&&>,
445 __not_<is_convertible<_Up&&, _Tp>>
446 >::value, bool> = false>
447 explicit constexpr optional(_Up&& __t)
448 : _Base(std::in_place, std::forward<_Up>(__t)) { }
449
450 template <typename _Up,
451 enable_if_t<__and_<
452 __not_<is_same<_Tp, _Up>>,
453 is_constructible<_Tp, const _Up&>,
454 is_convertible<const _Up&, _Tp>,
455 __not_<__converts_from_optional<_Tp, _Up>>
456 >::value, bool> = true>
457 constexpr optional(const optional<_Up>& __t)
458 {
459 if (__t)
460 emplace(*__t);
461 }
462
463 template <typename _Up,
464 enable_if_t<__and_<
465 __not_<is_same<_Tp, _Up>>,
466 is_constructible<_Tp, const _Up&>,
467 __not_<is_convertible<const _Up&, _Tp>>,
468 __not_<__converts_from_optional<_Tp, _Up>>
469 >::value, bool> = false>
470 explicit constexpr optional(const optional<_Up>& __t)
471 {
472 if (__t)
473 emplace(*__t);
474 }
475
476 template <typename _Up,
477 enable_if_t<__and_<
478 __not_<is_same<_Tp, _Up>>,
479 is_constructible<_Tp, _Up&&>,
480 is_convertible<_Up&&, _Tp>,
481 __not_<__converts_from_optional<_Tp, _Up>>
482 >::value, bool> = true>
483 constexpr optional(optional<_Up>&& __t)
484 {
485 if (__t)
486 emplace(std::move(*__t));
487 }
488
489 template <typename _Up,
490 enable_if_t<__and_<
491 __not_<is_same<_Tp, _Up>>,
492 is_constructible<_Tp, _Up&&>,
493 __not_<is_convertible<_Up&&, _Tp>>,
494 __not_<__converts_from_optional<_Tp, _Up>>
495 >::value, bool> = false>
496 explicit constexpr optional(optional<_Up>&& __t)
497 {
498 if (__t)
499 emplace(std::move(*__t));
500 }
501
502 template<typename... _Args>
503 explicit constexpr optional(in_place_t, _Args&&... __args)
504 : _Base(std::in_place, std::forward<_Args>(__args)...) { }
505
506 template<typename _Up, typename... _Args,
507 enable_if_t<is_constructible<_Tp,
508 initializer_list<_Up>&,
509 _Args&&...>::value,
510 int>...>
511 explicit constexpr optional(in_place_t,
512 initializer_list<_Up> __il,
513 _Args&&... __args)
514 : _Base(std::in_place, __il, std::forward<_Args>(__args)...) { }
515
516 // Assignment operators.
517 optional&
518 operator=(nullopt_t) noexcept
519 {
520 this->_M_reset();
521 return *this;
522 }
523
524 template<typename _Up = _Tp>
525 enable_if_t<__and_<
526 __not_<is_same<optional<_Tp>, decay_t<_Up>>>,
527 is_constructible<_Tp, _Up>,
528 __not_<__and_<is_scalar<_Tp>,
529 is_same<_Tp, decay_t<_Up>>>>,
530 is_assignable<_Tp&, _Up>>::value,
531 optional&>
532 operator=(_Up&& __u)
533 {
534 if (this->_M_is_engaged())
535 this->_M_get() = std::forward<_Up>(__u);
536 else
537 this->_M_construct(std::forward<_Up>(__u));
538
539 return *this;
540 }
541
542 template<typename _Up>
543 enable_if_t<__and_<
544 __not_<is_same<_Tp, _Up>>,
545 is_constructible<_Tp, const _Up&>,
546 is_assignable<_Tp&, _Up>,
547 __not_<__converts_from_optional<_Tp, _Up>>,
548 __not_<__assigns_from_optional<_Tp, _Up>>
549 >::value,
550 optional&>
551 operator=(const optional<_Up>& __u)
552 {
553 if (__u)
554 {
555 if (this->_M_is_engaged())
556 this->_M_get() = *__u;
557 else
558 this->_M_construct(*__u);
559 }
560 else
561 {
562 this->_M_reset();
563 }
564 return *this;
565 }
566
567 template<typename _Up>
568 enable_if_t<__and_<
569 __not_<is_same<_Tp, _Up>>,
570 is_constructible<_Tp, _Up>,
571 is_assignable<_Tp&, _Up>,
572 __not_<__converts_from_optional<_Tp, _Up>>,
573 __not_<__assigns_from_optional<_Tp, _Up>>
574 >::value,
575 optional&>
576 operator=(optional<_Up>&& __u)
577 {
578 if (__u)
579 {
580 if (this->_M_is_engaged())
581 this->_M_get() = std::move(*__u);
582 else
583 this->_M_construct(std::move(*__u));
584 }
585 else
586 {
587 this->_M_reset();
588 }
589
590 return *this;
591 }
592
593 template<typename... _Args>
594 enable_if_t<is_constructible<_Tp, _Args&&...>::value>
595 emplace(_Args&&... __args)
596 {
597 this->_M_reset();
598 this->_M_construct(std::forward<_Args>(__args)...);
599 }
600
601 template<typename _Up, typename... _Args>
602 enable_if_t<is_constructible<_Tp, initializer_list<_Up>&,
603 _Args&&...>::value>
604 emplace(initializer_list<_Up> __il, _Args&&... __args)
605 {
606 this->_M_reset();
607 this->_M_construct(__il, std::forward<_Args>(__args)...);
608 }
609
610 // Destructor is implicit, implemented in _Optional_base.
611
612 // Swap.
613 void
614 swap(optional& __other)
615 noexcept(is_nothrow_move_constructible<_Tp>()
616 && noexcept(swap(declval<_Tp&>(), declval<_Tp&>())))
617 {
618 using std::swap;
619
620 if (this->_M_is_engaged() && __other._M_is_engaged())
621 swap(this->_M_get(), __other._M_get());
622 else if (this->_M_is_engaged())
623 {
624 __other._M_construct(std::move(this->_M_get()));
625 this->_M_destruct();
626 }
627 else if (__other._M_is_engaged())
628 {
629 this->_M_construct(std::move(__other._M_get()));
630 __other._M_destruct();
631 }
632 }
633
634 // Observers.
635 constexpr const _Tp*
636 operator->() const
637 { return std::__addressof(this->_M_get()); }
638
639 _Tp*
640 operator->()
641 { return std::__addressof(this->_M_get()); }
642
643 constexpr const _Tp&
644 operator*() const&
645 { return this->_M_get(); }
646
647 constexpr _Tp&
648 operator*()&
649 { return this->_M_get(); }
650
651 constexpr _Tp&&
652 operator*()&&
653 { return std::move(this->_M_get()); }
654
655 constexpr const _Tp&&
656 operator*() const&&
657 { return std::move(this->_M_get()); }
658
659 constexpr explicit operator bool() const noexcept
660 { return this->_M_is_engaged(); }
661
662 constexpr bool has_value() const noexcept
663 { return this->_M_is_engaged(); }
664
665 constexpr const _Tp&
666 value() const&
667 {
668 return this->_M_is_engaged()
669 ? this->_M_get()
670 : (__throw_bad_optional_access("Attempt to access value of a "
671 "disengaged optional object"),
672 this->_M_get());
673 }
674
675 constexpr _Tp&
676 value()&
677 {
678 return this->_M_is_engaged()
679 ? this->_M_get()
680 : (__throw_bad_optional_access("Attempt to access value of a "
681 "disengaged optional object"),
682 this->_M_get());
683 }
684
685 constexpr _Tp&&
686 value()&&
687 {
688 return this->_M_is_engaged()
689 ? std::move(this->_M_get())
690 : (__throw_bad_optional_access("Attempt to access value of a "
691 "disengaged optional object"),
692 std::move(this->_M_get()));
693 }
694
695 constexpr const _Tp&&
696 value() const&&
697 {
698 return this->_M_is_engaged()
699 ? std::move(this->_M_get())
700 : (__throw_bad_optional_access("Attempt to access value of a "
701 "disengaged optional object"),
702 std::move(this->_M_get()));
703 }
704
705 template<typename _Up>
706 constexpr _Tp
707 value_or(_Up&& __u) const&
708 {
709 static_assert(__and_<is_copy_constructible<_Tp>,
710 is_convertible<_Up&&, _Tp>>(),
711 "Cannot return value");
712
713 return this->_M_is_engaged()
714 ? this->_M_get()
715 : static_cast<_Tp>(std::forward<_Up>(__u));
716 }
717
718 template<typename _Up>
719 _Tp
720 value_or(_Up&& __u) &&
721 {
722 static_assert(__and_<is_move_constructible<_Tp>,
723 is_convertible<_Up&&, _Tp>>(),
724 "Cannot return value" );
725
726 return this->_M_is_engaged()
727 ? std::move(this->_M_get())
728 : static_cast<_Tp>(std::forward<_Up>(__u));
729 }
730 void reset() noexcept { this->_M_reset(); }
731 };
732
733 template<typename _Tp>
734 using __optional_relop_t =
735 enable_if_t<is_convertible<_Tp, bool>::value, bool>;
736
737 // Comparisons between optional values.
738 template<typename _Tp>
739 constexpr auto
740 operator==(const optional<_Tp>& __lhs, const optional<_Tp>& __rhs)
741 -> __optional_relop_t<decltype(declval<_Tp>() == declval<_Tp>())>
742 {
743 return static_cast<bool>(__lhs) == static_cast<bool>(__rhs)
744 && (!__lhs || *__lhs == *__rhs);
745 }
746
747 template<typename _Tp>
748 constexpr auto
749 operator!=(const optional<_Tp>& __lhs, const optional<_Tp>& __rhs)
750 -> __optional_relop_t<decltype(declval<_Tp>() != declval<_Tp>())>
751 {
752 return static_cast<bool>(__lhs) != static_cast<bool>(__rhs)
753 || (static_cast<bool>(__lhs) && *__lhs != *__rhs);
754 }
755
756 template<typename _Tp>
757 constexpr auto
758 operator<(const optional<_Tp>& __lhs, const optional<_Tp>& __rhs)
759 -> __optional_relop_t<decltype(declval<_Tp>() < declval<_Tp>())>
760 {
761 return static_cast<bool>(__rhs) && (!__lhs || *__lhs < *__rhs);
762 }
763
764 template<typename _Tp>
765 constexpr auto
766 operator>(const optional<_Tp>& __lhs, const optional<_Tp>& __rhs)
767 -> __optional_relop_t<decltype(declval<_Tp>() > declval<_Tp>())>
768 {
769 return static_cast<bool>(__lhs) && (!__rhs || *__lhs > *__rhs);
770 }
771
772 template<typename _Tp>
773 constexpr auto
774 operator<=(const optional<_Tp>& __lhs, const optional<_Tp>& __rhs)
775 -> __optional_relop_t<decltype(declval<_Tp>() <= declval<_Tp>())>
776 {
777 return !__lhs || (static_cast<bool>(__rhs) && *__lhs <= *__rhs);
778 }
779
780 template<typename _Tp>
781 constexpr auto
782 operator>=(const optional<_Tp>& __lhs, const optional<_Tp>& __rhs)
783 -> __optional_relop_t<decltype(declval<_Tp>() >= declval<_Tp>())>
784 {
785 return !__rhs || (static_cast<bool>(__lhs) && *__lhs >= *__rhs);
786 }
787
788 // Comparisons with nullopt.
789 template<typename _Tp>
790 constexpr bool
791 operator==(const optional<_Tp>& __lhs, nullopt_t) noexcept
792 { return !__lhs; }
793
794 template<typename _Tp>
795 constexpr bool
796 operator==(nullopt_t, const optional<_Tp>& __rhs) noexcept
797 { return !__rhs; }
798
799 template<typename _Tp>
800 constexpr bool
801 operator!=(const optional<_Tp>& __lhs, nullopt_t) noexcept
802 { return static_cast<bool>(__lhs); }
803
804 template<typename _Tp>
805 constexpr bool
806 operator!=(nullopt_t, const optional<_Tp>& __rhs) noexcept
807 { return static_cast<bool>(__rhs); }
808
809 template<typename _Tp>
810 constexpr bool
811 operator<(const optional<_Tp>& /* __lhs */, nullopt_t) noexcept
812 { return false; }
813
814 template<typename _Tp>
815 constexpr bool
816 operator<(nullopt_t, const optional<_Tp>& __rhs) noexcept
817 { return static_cast<bool>(__rhs); }
818
819 template<typename _Tp>
820 constexpr bool
821 operator>(const optional<_Tp>& __lhs, nullopt_t) noexcept
822 { return static_cast<bool>(__lhs); }
823
824 template<typename _Tp>
825 constexpr bool
826 operator>(nullopt_t, const optional<_Tp>& /* __rhs */) noexcept
827 { return false; }
828
829 template<typename _Tp>
830 constexpr bool
831 operator<=(const optional<_Tp>& __lhs, nullopt_t) noexcept
832 { return !__lhs; }
833
834 template<typename _Tp>
835 constexpr bool
836 operator<=(nullopt_t, const optional<_Tp>& /* __rhs */) noexcept
837 { return true; }
838
839 template<typename _Tp>
840 constexpr bool
841 operator>=(const optional<_Tp>& /* __lhs */, nullopt_t) noexcept
842 { return true; }
843
844 template<typename _Tp>
845 constexpr bool
846 operator>=(nullopt_t, const optional<_Tp>& __rhs) noexcept
847 { return !__rhs; }
848
849 // Comparisons with value type.
850 template<typename _Tp>
851 constexpr auto
852 operator==(const optional<_Tp>& __lhs, const _Tp& __rhs)
853 -> __optional_relop_t<decltype(declval<_Tp>() == declval<_Tp>())>
854 { return __lhs && *__lhs == __rhs; }
855
856 template<typename _Tp>
857 constexpr auto
858 operator==(const _Tp& __lhs, const optional<_Tp>& __rhs)
859 -> __optional_relop_t<decltype(declval<_Tp>() == declval<_Tp>())>
860 { return __rhs && __lhs == *__rhs; }
861
862 template<typename _Tp>
863 constexpr auto
864 operator!=(const optional<_Tp>& __lhs, const _Tp& __rhs)
865 -> __optional_relop_t<decltype(declval<_Tp>() != declval<_Tp>())>
866 { return !__lhs || *__lhs != __rhs; }
867
868 template<typename _Tp>
869 constexpr auto
870 operator!=(const _Tp& __lhs, const optional<_Tp>& __rhs)
871 -> __optional_relop_t<decltype(declval<_Tp>() != declval<_Tp>())>
872 { return !__rhs || __lhs != *__rhs; }
873
874 template<typename _Tp>
875 constexpr auto
876 operator<(const optional<_Tp>& __lhs, const _Tp& __rhs)
877 -> __optional_relop_t<decltype(declval<_Tp>() < declval<_Tp>())>
878 { return !__lhs || *__lhs < __rhs; }
879
880 template<typename _Tp>
881 constexpr auto
882 operator<(const _Tp& __lhs, const optional<_Tp>& __rhs)
883 -> __optional_relop_t<decltype(declval<_Tp>() < declval<_Tp>())>
884 { return __rhs && __lhs < *__rhs; }
885
886 template<typename _Tp>
887 constexpr auto
888 operator>(const optional<_Tp>& __lhs, const _Tp& __rhs)
889 -> __optional_relop_t<decltype(declval<_Tp>() > declval<_Tp>())>
890 { return __lhs && *__lhs > __rhs; }
891
892 template<typename _Tp>
893 constexpr auto
894 operator>(const _Tp& __lhs, const optional<_Tp>& __rhs)
895 -> __optional_relop_t<decltype(declval<_Tp>() > declval<_Tp>())>
896 { return !__rhs || __lhs > *__rhs; }
897
898 template<typename _Tp>
899 constexpr auto
900 operator<=(const optional<_Tp>& __lhs, const _Tp& __rhs)
901 -> __optional_relop_t<decltype(declval<_Tp>() <= declval<_Tp>())>
902 { return !__lhs || *__lhs <= __rhs; }
903
904 template<typename _Tp>
905 constexpr auto
906 operator<=(const _Tp& __lhs, const optional<_Tp>& __rhs)
907 -> __optional_relop_t<decltype(declval<_Tp>() <= declval<_Tp>())>
908 { return __rhs && __lhs <= *__rhs; }
909
910 template<typename _Tp>
911 constexpr auto
912 operator>=(const optional<_Tp>& __lhs, const _Tp& __rhs)
913 -> __optional_relop_t<decltype(declval<_Tp>() >= declval<_Tp>())>
914 { return __lhs && *__lhs >= __rhs; }
915
916 template<typename _Tp>
917 constexpr auto
918 operator>=(const _Tp& __lhs, const optional<_Tp>& __rhs)
919 -> __optional_relop_t<decltype(declval<_Tp>() >= declval<_Tp>())>
920 { return !__rhs || __lhs >= *__rhs; }
921
922 // Swap and creation functions.
923 template<typename _Tp>
924 inline void
925 swap(optional<_Tp>& __lhs, optional<_Tp>& __rhs)
926 noexcept(noexcept(__lhs.swap(__rhs)))
927 { __lhs.swap(__rhs); }
928
929 template<typename _Tp>
930 constexpr optional<decay_t<_Tp>>
931 make_optional(_Tp&& __t)
932 { return optional<decay_t<_Tp>> { std::forward<_Tp>(__t) }; }
933
934 template<typename _Tp, typename ..._Args>
935 constexpr optional<_Tp>
936 make_optional(_Args&&... __args)
937 { return optional<_Tp> { in_place, std::forward<_Args>(__args)... }; }
938
939 template<typename _Tp, typename _Up, typename ..._Args>
940 constexpr optional<_Tp>
941 make_optional(initializer_list<_Up> __il, _Args&&... __args)
942 { return optional<_Tp> { in_place, __il, std::forward<_Args>(__args)... }; }
943
944 // Hash.
945 template<typename _Tp>
946 struct hash<optional<_Tp>> : private __poison_hash<remove_const_t<_Tp>>
947 {
948 using result_type = size_t;
949 using argument_type = optional<_Tp>;
950
951 size_t
952 operator()(const optional<_Tp>& __t) const
953 noexcept(noexcept(hash<_Tp> {}(*__t)))
954 {
955 // We pick an arbitrary hash for disengaged optionals which hopefully
956 // usual values of _Tp won't typically hash to.
957 constexpr size_t __magic_disengaged_hash = static_cast<size_t>(-3333);
958 return __t ? hash<_Tp> {}(*__t) : __magic_disengaged_hash;
959 }
960 };
961
962 /// @}
963
964 _GLIBCXX_END_NAMESPACE_VERSION
965 } // namespace std
966
967 #endif // C++17
968
969 #endif // _GLIBCXX_OPTIONAL