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