]>
Commit | Line | Data |
---|---|---|
435e56fb VV |
1 | // <optional> -*- C++ -*- |
2 | ||
a5544970 | 3 | // Copyright (C) 2013-2019 Free Software Foundation, Inc. |
435e56fb VV |
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 | ||
c6888c62 JW |
32 | #pragma GCC system_header |
33 | ||
34 | #if __cplusplus >= 201703L | |
435e56fb VV |
35 | |
36 | #include <utility> | |
37 | #include <type_traits> | |
beb0086f | 38 | #include <exception> |
435e56fb VV |
39 | #include <new> |
40 | #include <initializer_list> | |
beb0086f | 41 | #include <bits/exception_defines.h> |
435e56fb VV |
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 | ||
56a9eaf9 | 54 | #define __cpp_lib_optional 201606L |
c6888c62 | 55 | |
435e56fb VV |
56 | template<typename _Tp> |
57 | class optional; | |
58 | ||
435e56fb VV |
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 | ||
435e56fb | 73 | /// Tag to disengage optional objects. |
288695f7 | 74 | inline constexpr nullopt_t nullopt { nullopt_t::_Construct::_Token }; |
435e56fb | 75 | |
435e56fb VV |
76 | /** |
77 | * @brief Exception class thrown when a disengaged optional object is | |
78 | * dereferenced. | |
79 | * @ingroup exceptions | |
80 | */ | |
fd231ad7 | 81 | class bad_optional_access : public exception |
435e56fb VV |
82 | { |
83 | public: | |
fd231ad7 | 84 | bad_optional_access() { } |
d6ed6b07 | 85 | |
fd231ad7 | 86 | virtual const char* what() const noexcept override |
d6ed6b07 | 87 | { return "bad optional access"; } |
435e56fb VV |
88 | |
89 | virtual ~bad_optional_access() noexcept = default; | |
90 | }; | |
91 | ||
92 | void | |
fd231ad7 | 93 | __throw_bad_optional_access() |
435e56fb VV |
94 | __attribute__((__noreturn__)); |
95 | ||
96 | // XXX Does not belong here. | |
97 | inline void | |
fd231ad7 VV |
98 | __throw_bad_optional_access() |
99 | { _GLIBCXX_THROW_OR_ABORT(bad_optional_access()); } | |
435e56fb | 100 | |
d942bc80 JW |
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 | |
447346e4 | 105 | { |
d942bc80 JW |
106 | using _Stored_type = remove_const_t<_Tp>; |
107 | ||
108 | _Optional_payload_base() = default; | |
109 | ~_Optional_payload_base() = default; | |
447346e4 | 110 | |
d942bc80 | 111 | template<typename... _Args> |
d6ed6b07 | 112 | constexpr |
d942bc80 JW |
113 | _Optional_payload_base(in_place_t __tag, _Args&&... __args) |
114 | : _M_payload(__tag, std::forward<_Args>(__args)...), | |
115 | _M_engaged(true) | |
116 | { } | |
447346e4 VV |
117 | |
118 | template<typename _Up, typename... _Args> | |
d6ed6b07 | 119 | constexpr |
d942bc80 JW |
120 | _Optional_payload_base(std::initializer_list<_Up> __il, |
121 | _Args&&... __args) | |
447346e4 | 122 | : _M_payload(__il, std::forward<_Args>(__args)...), |
d6ed6b07 JW |
123 | _M_engaged(true) |
124 | { } | |
125 | ||
d942bc80 JW |
126 | // Constructor used by _Optional_base copy constructor when the |
127 | // contained value is not trivially copy constructible. | |
447346e4 | 128 | constexpr |
d942bc80 JW |
129 | _Optional_payload_base(bool __engaged, |
130 | const _Optional_payload_base& __other) | |
447346e4 VV |
131 | { |
132 | if (__other._M_engaged) | |
d942bc80 | 133 | this->_M_construct(__other._M_get()); |
447346e4 VV |
134 | } |
135 | ||
d942bc80 JW |
136 | // Constructor used by _Optional_base move constructor when the |
137 | // contained value is not trivially move constructible. | |
d6ed6b07 | 138 | constexpr |
d942bc80 JW |
139 | _Optional_payload_base(bool __engaged, |
140 | _Optional_payload_base&& __other) | |
447346e4 VV |
141 | { |
142 | if (__other._M_engaged) | |
d942bc80 | 143 | this->_M_construct(std::move(__other._M_get())); |
447346e4 VV |
144 | } |
145 | ||
d942bc80 JW |
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; | |
447346e4 | 149 | |
d942bc80 JW |
150 | // Move constructor is only used to when the contained value is |
151 | // trivially copy constructible. | |
152 | _Optional_payload_base(_Optional_payload_base&&) = default; | |
447346e4 | 153 | |
d942bc80 JW |
154 | _Optional_payload_base& |
155 | operator=(const _Optional_payload_base&) = default; | |
156 | ||
157 | _Optional_payload_base& | |
158 | operator=(_Optional_payload_base&&) = default; | |
d6ed6b07 | 159 | |
50b0a3d6 JW |
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 | ||
447346e4 | 192 | struct _Empty_byte { }; |
d6ed6b07 | 193 | |
d942bc80 JW |
194 | template<typename _Up, bool = is_trivially_destructible_v<_Up>> |
195 | union _Storage | |
196 | { | |
197 | constexpr _Storage() noexcept : _M_empty() { } | |
447346e4 | 198 | |
d942bc80 JW |
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; | |
447346e4 VV |
242 | |
243 | template<typename... _Args> | |
244 | void | |
245 | _M_construct(_Args&&... __args) | |
b655b8fc | 246 | noexcept(is_nothrow_constructible_v<_Stored_type, _Args...>) |
447346e4 VV |
247 | { |
248 | ::new ((void *) std::__addressof(this->_M_payload)) | |
249 | _Stored_type(std::forward<_Args>(__args)...); | |
250 | this->_M_engaged = true; | |
251 | } | |
252 | ||
d942bc80 JW |
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 | ||
447346e4 | 264 | constexpr _Tp& |
d6ed6b07 | 265 | _M_get() noexcept |
d942bc80 | 266 | { return this->_M_payload._M_value; } |
447346e4 VV |
267 | |
268 | constexpr const _Tp& | |
d6ed6b07 | 269 | _M_get() const noexcept |
d942bc80 | 270 | { return this->_M_payload._M_value; } |
447346e4 VV |
271 | |
272 | // _M_reset is a 'safe' operation with no precondition. | |
d942bc80 | 273 | constexpr void |
447346e4 VV |
274 | _M_reset() noexcept |
275 | { | |
276 | if (this->_M_engaged) | |
d942bc80 | 277 | _M_destroy(); |
447346e4 VV |
278 | } |
279 | }; | |
280 | ||
d942bc80 JW |
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). | |
447346e4 VV |
294 | template <typename _Tp> |
295 | struct _Optional_payload<_Tp, true, true, true> | |
d942bc80 | 296 | : _Optional_payload_base<_Tp> |
250f5b6c | 297 | { |
d942bc80 | 298 | using _Optional_payload_base<_Tp>::_Optional_payload_base; |
435e56fb | 299 | |
d942bc80 | 300 | _Optional_payload() = default; |
250f5b6c | 301 | }; |
435e56fb | 302 | |
d942bc80 | 303 | // Payload for optionals with non-trivial copy construction/assignment. |
250f5b6c | 304 | template <typename _Tp> |
447346e4 | 305 | struct _Optional_payload<_Tp, true, false, true> |
d942bc80 | 306 | : _Optional_payload_base<_Tp> |
250f5b6c | 307 | { |
d942bc80 | 308 | using _Optional_payload_base<_Tp>::_Optional_payload_base; |
447346e4 | 309 | |
d942bc80 JW |
310 | _Optional_payload() = default; |
311 | ~_Optional_payload() = default; | |
447346e4 VV |
312 | _Optional_payload(const _Optional_payload&) = default; |
313 | _Optional_payload(_Optional_payload&&) = default; | |
d942bc80 | 314 | _Optional_payload& operator=(_Optional_payload&&) = default; |
447346e4 | 315 | |
d942bc80 | 316 | // Non-trivial copy assignment. |
4fea8205 | 317 | constexpr |
447346e4 VV |
318 | _Optional_payload& |
319 | operator=(const _Optional_payload& __other) | |
320 | { | |
50b0a3d6 | 321 | this->_M_copy_assign(__other); |
447346e4 VV |
322 | return *this; |
323 | } | |
447346e4 VV |
324 | }; |
325 | ||
d942bc80 | 326 | // Payload for optionals with non-trivial move construction/assignment. |
447346e4 VV |
327 | template <typename _Tp> |
328 | struct _Optional_payload<_Tp, true, true, false> | |
d942bc80 | 329 | : _Optional_payload_base<_Tp> |
447346e4 | 330 | { |
d942bc80 | 331 | using _Optional_payload_base<_Tp>::_Optional_payload_base; |
447346e4 | 332 | |
d942bc80 JW |
333 | _Optional_payload() = default; |
334 | ~_Optional_payload() = default; | |
447346e4 VV |
335 | _Optional_payload(const _Optional_payload&) = default; |
336 | _Optional_payload(_Optional_payload&&) = default; | |
d942bc80 | 337 | _Optional_payload& operator=(const _Optional_payload&) = default; |
447346e4 | 338 | |
d942bc80 | 339 | // Non-trivial move assignment. |
4fea8205 | 340 | constexpr |
447346e4 VV |
341 | _Optional_payload& |
342 | operator=(_Optional_payload&& __other) | |
b655b8fc JW |
343 | noexcept(__and_v<is_nothrow_move_constructible<_Tp>, |
344 | is_nothrow_move_assignable<_Tp>>) | |
435e56fb | 345 | { |
50b0a3d6 | 346 | this->_M_move_assign(std::move(__other)); |
447346e4 | 347 | return *this; |
435e56fb | 348 | } |
447346e4 VV |
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> | |
d942bc80 | 354 | : _Optional_payload_base<_Tp> |
447346e4 | 355 | { |
d942bc80 | 356 | using _Optional_payload_base<_Tp>::_Optional_payload_base; |
447346e4 | 357 | |
d942bc80 JW |
358 | _Optional_payload() = default; |
359 | ~_Optional_payload() = default; | |
447346e4 VV |
360 | _Optional_payload(const _Optional_payload&) = default; |
361 | _Optional_payload(_Optional_payload&&) = default; | |
435e56fb | 362 | |
50b0a3d6 | 363 | // Non-trivial copy assignment. |
4fea8205 | 364 | constexpr |
c89f2d24 VV |
365 | _Optional_payload& |
366 | operator=(const _Optional_payload& __other) | |
367 | { | |
50b0a3d6 | 368 | this->_M_copy_assign(__other); |
c89f2d24 VV |
369 | return *this; |
370 | } | |
371 | ||
d942bc80 | 372 | // Non-trivial move assignment. |
4fea8205 | 373 | constexpr |
c89f2d24 VV |
374 | _Optional_payload& |
375 | operator=(_Optional_payload&& __other) | |
b655b8fc JW |
376 | noexcept(__and_v<is_nothrow_move_constructible<_Tp>, |
377 | is_nothrow_move_assignable<_Tp>>) | |
c89f2d24 | 378 | { |
50b0a3d6 | 379 | this->_M_move_assign(std::move(__other)); |
c89f2d24 VV |
380 | return *this; |
381 | } | |
d942bc80 | 382 | }; |
c89f2d24 | 383 | |
d942bc80 JW |
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; | |
435e56fb | 396 | |
d942bc80 JW |
397 | // Destructor needs to destroy the contained value: |
398 | ~_Optional_payload() { this->_M_reset(); } | |
c89f2d24 | 399 | }; |
447346e4 | 400 | |
d942bc80 JW |
401 | // Common base class for _Optional_base<T> to avoid repeating these |
402 | // member functions in each specialization. | |
c89f2d24 VV |
403 | template<typename _Tp, typename _Dp> |
404 | class _Optional_base_impl | |
405 | { | |
406 | protected: | |
250f5b6c | 407 | using _Stored_type = remove_const_t<_Tp>; |
d942bc80 | 408 | |
c89f2d24 VV |
409 | // The _M_construct operation has !_M_engaged as a precondition |
410 | // while _M_destruct has _M_engaged as a precondition. | |
250f5b6c | 411 | template<typename... _Args> |
d6ed6b07 JW |
412 | void |
413 | _M_construct(_Args&&... __args) | |
b655b8fc | 414 | noexcept(is_nothrow_constructible_v<_Stored_type, _Args...>) |
d6ed6b07 JW |
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 | } | |
d942bc80 | 421 | |
c89f2d24 VV |
422 | void |
423 | _M_destruct() noexcept | |
d942bc80 JW |
424 | { static_cast<_Dp*>(this)->_M_payload._M_destroy(); } |
425 | ||
c89f2d24 | 426 | // _M_reset is a 'safe' operation with no precondition. |
d942bc80 | 427 | constexpr void |
c89f2d24 | 428 | _M_reset() noexcept |
d942bc80 JW |
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 | |
c89f2d24 | 437 | { |
d942bc80 JW |
438 | __glibcxx_assert(this->_M_is_engaged()); |
439 | return static_cast<_Dp*>(this)->_M_payload._M_get(); | |
c89f2d24 | 440 | } |
d942bc80 JW |
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 | }; | |
435e56fb | 449 | |
250f5b6c | 450 | /** |
d942bc80 | 451 | * @brief Class template that provides copy/move constructors of optional. |
250f5b6c VV |
452 | * |
453 | * Such a separate base class template is necessary in order to | |
c89f2d24 | 454 | * conditionally make copy/move constructors trivial. |
d942bc80 JW |
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 | * | |
250f5b6c VV |
466 | * @see optional, _Enable_special_members |
467 | */ | |
c89f2d24 VV |
468 | template<typename _Tp, |
469 | bool = is_trivially_copy_constructible_v<_Tp>, | |
470 | bool = is_trivially_move_constructible_v<_Tp>> | |
d942bc80 JW |
471 | struct _Optional_base |
472 | : _Optional_base_impl<_Tp, _Optional_base<_Tp>> | |
435e56fb | 473 | { |
250f5b6c | 474 | // Constructors for disengaged optionals. |
c89f2d24 | 475 | constexpr _Optional_base() = default; |
435e56fb | 476 | |
250f5b6c | 477 | // Constructors for engaged optionals. |
2ae2d394 VV |
478 | template<typename... _Args, |
479 | enable_if_t<is_constructible_v<_Tp, _Args&&...>, bool> = false> | |
435e56fb | 480 | constexpr explicit _Optional_base(in_place_t, _Args&&... __args) |
250f5b6c VV |
481 | : _M_payload(in_place, |
482 | std::forward<_Args>(__args)...) { } | |
435e56fb VV |
483 | |
484 | template<typename _Up, typename... _Args, | |
2ae2d394 VV |
485 | enable_if_t<is_constructible_v<_Tp, |
486 | initializer_list<_Up>&, | |
487 | _Args&&...>, bool> = false> | |
435e56fb VV |
488 | constexpr explicit _Optional_base(in_place_t, |
489 | initializer_list<_Up> __il, | |
490 | _Args&&... __args) | |
250f5b6c VV |
491 | : _M_payload(in_place, |
492 | __il, std::forward<_Args>(__args)...) | |
493 | { } | |
435e56fb | 494 | |
250f5b6c VV |
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 | { } | |
435e56fb | 500 | |
250f5b6c | 501 | constexpr _Optional_base(_Optional_base&& __other) |
b655b8fc | 502 | noexcept(is_nothrow_move_constructible_v<_Tp>) |
250f5b6c VV |
503 | : _M_payload(__other._M_payload._M_engaged, |
504 | std::move(__other._M_payload)) | |
505 | { } | |
435e56fb | 506 | |
250f5b6c | 507 | // Assignment operators. |
c89f2d24 VV |
508 | _Optional_base& operator=(const _Optional_base&) = default; |
509 | _Optional_base& operator=(_Optional_base&&) = default; | |
510 | ||
c89f2d24 VV |
511 | _Optional_payload<_Tp> _M_payload; |
512 | }; | |
513 | ||
514 | template<typename _Tp> | |
d942bc80 JW |
515 | struct _Optional_base<_Tp, false, true> |
516 | : _Optional_base_impl<_Tp, _Optional_base<_Tp>> | |
c89f2d24 | 517 | { |
c89f2d24 VV |
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 | ||
c89f2d24 VV |
551 | _Optional_payload<_Tp> _M_payload; |
552 | }; | |
553 | ||
554 | template<typename _Tp> | |
d942bc80 JW |
555 | struct _Optional_base<_Tp, true, false> |
556 | : _Optional_base_impl<_Tp, _Optional_base<_Tp>> | |
c89f2d24 | 557 | { |
c89f2d24 VV |
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) | |
b655b8fc | 583 | noexcept(is_nothrow_move_constructible_v<_Tp>) |
c89f2d24 VV |
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 | ||
c89f2d24 VV |
592 | _Optional_payload<_Tp> _M_payload; |
593 | }; | |
435e56fb | 594 | |
c89f2d24 | 595 | template<typename _Tp> |
d942bc80 JW |
596 | struct _Optional_base<_Tp, true, true> |
597 | : _Optional_base_impl<_Tp, _Optional_base<_Tp>> | |
c89f2d24 | 598 | { |
c89f2d24 VV |
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 | ||
250f5b6c | 628 | _Optional_payload<_Tp> _M_payload; |
435e56fb VV |
629 | }; |
630 | ||
631 | template<typename _Tp> | |
632 | class optional; | |
633 | ||
b641f833 VV |
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>&&>>; | |
435e56fb VV |
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< | |
b655b8fc JW |
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>> | |
435e56fb | 669 | { |
9057edd3 JW |
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>); | |
435e56fb VV |
673 | |
674 | private: | |
675 | using _Base = _Optional_base<_Tp>; | |
676 | ||
b655b8fc JW |
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 | ||
435e56fb VV |
685 | public: |
686 | using value_type = _Tp; | |
687 | ||
435e56fb | 688 | constexpr optional() = default; |
a577f786 | 689 | |
c89f2d24 | 690 | constexpr optional(nullopt_t) noexcept { } |
a577f786 | 691 | |
435e56fb | 692 | // Converting constructors for engaged optionals. |
b655b8fc JW |
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) | |
a577f786 | 707 | : _Base(std::in_place, std::forward<_Up>(__t)) { } |
435e56fb | 708 | |
b655b8fc JW |
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 | } | |
435e56fb | 720 | |
b655b8fc JW |
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 | } | |
435e56fb VV |
732 | |
733 | template <typename _Up, | |
b655b8fc JW |
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 | } | |
435e56fb VV |
744 | |
745 | template <typename _Up, | |
b655b8fc JW |
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 | } | |
a577f786 | 756 | |
2ae2d394 | 757 | template<typename... _Args, |
b655b8fc JW |
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)...) { } | |
a577f786 VV |
762 | |
763 | template<typename _Up, typename... _Args, | |
b655b8fc JW |
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)...) { } | |
435e56fb | 770 | |
40f3e913 | 771 | // Assignment operators. |
435e56fb VV |
772 | optional& |
773 | operator=(nullopt_t) noexcept | |
774 | { | |
b655b8fc JW |
775 | this->_M_reset(); |
776 | return *this; | |
435e56fb VV |
777 | } |
778 | ||
f320e6a0 | 779 | template<typename _Up = _Tp> |
b655b8fc JW |
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>>, | |
f320e6a0 | 785 | optional&> |
b655b8fc JW |
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)); | |
435e56fb | 792 | |
b655b8fc JW |
793 | return *this; |
794 | } | |
435e56fb | 795 | |
f320e6a0 | 796 | template<typename _Up> |
b655b8fc JW |
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>>>, | |
f320e6a0 | 802 | optional&> |
b655b8fc JW |
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 | } | |
435e56fb | 818 | |
f320e6a0 | 819 | template<typename _Up> |
b655b8fc JW |
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>>>, | |
f320e6a0 | 825 | optional&> |
b655b8fc JW |
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 | } | |
435e56fb VV |
842 | |
843 | template<typename... _Args> | |
b655b8fc | 844 | enable_if_t<is_constructible_v<_Tp, _Args&&...>, _Tp&> |
435e56fb VV |
845 | emplace(_Args&&... __args) |
846 | { | |
435e56fb VV |
847 | this->_M_reset(); |
848 | this->_M_construct(std::forward<_Args>(__args)...); | |
df990182 | 849 | return this->_M_get(); |
435e56fb VV |
850 | } |
851 | ||
852 | template<typename _Up, typename... _Args> | |
b655b8fc JW |
853 | enable_if_t<is_constructible_v<_Tp, initializer_list<_Up>&, |
854 | _Args&&...>, _Tp&> | |
435e56fb VV |
855 | emplace(initializer_list<_Up> __il, _Args&&... __args) |
856 | { | |
857 | this->_M_reset(); | |
858 | this->_M_construct(__il, std::forward<_Args>(__args)...); | |
df990182 | 859 | return this->_M_get(); |
435e56fb VV |
860 | } |
861 | ||
40f3e913 | 862 | // Destructor is implicit, implemented in _Optional_base. |
435e56fb | 863 | |
40f3e913 | 864 | // Swap. |
435e56fb VV |
865 | void |
866 | swap(optional& __other) | |
b655b8fc JW |
867 | noexcept(is_nothrow_move_constructible_v<_Tp> |
868 | && is_nothrow_swappable_v<_Tp>) | |
435e56fb | 869 | { |
b655b8fc | 870 | using std::swap; |
435e56fb | 871 | |
b655b8fc JW |
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()) | |
435e56fb VV |
875 | { |
876 | __other._M_construct(std::move(this->_M_get())); | |
877 | this->_M_destruct(); | |
878 | } | |
b655b8fc | 879 | else if (__other._M_is_engaged()) |
435e56fb VV |
880 | { |
881 | this->_M_construct(std::move(__other._M_get())); | |
882 | __other._M_destruct(); | |
883 | } | |
884 | } | |
885 | ||
40f3e913 | 886 | // Observers. |
435e56fb VV |
887 | constexpr const _Tp* |
888 | operator->() const | |
ca9e949f | 889 | { return std::__addressof(this->_M_get()); } |
435e56fb | 890 | |
b752e2c9 | 891 | constexpr _Tp* |
435e56fb VV |
892 | operator->() |
893 | { return std::__addressof(this->_M_get()); } | |
894 | ||
895 | constexpr const _Tp& | |
896 | operator*() const& | |
897 | { return this->_M_get(); } | |
898 | ||
899 | constexpr _Tp& | |
900 | operator*()& | |
901 | { return this->_M_get(); } | |
902 | ||
903 | constexpr _Tp&& | |
904 | operator*()&& | |
905 | { return std::move(this->_M_get()); } | |
906 | ||
907 | constexpr const _Tp&& | |
908 | operator*() const&& | |
909 | { return std::move(this->_M_get()); } | |
910 | ||
911 | constexpr explicit operator bool() const noexcept | |
912 | { return this->_M_is_engaged(); } | |
913 | ||
25a69162 VV |
914 | constexpr bool has_value() const noexcept |
915 | { return this->_M_is_engaged(); } | |
916 | ||
435e56fb VV |
917 | constexpr const _Tp& |
918 | value() const& | |
919 | { | |
920 | return this->_M_is_engaged() | |
d942bc80 JW |
921 | ? this->_M_get() |
922 | : (__throw_bad_optional_access(), this->_M_get()); | |
435e56fb VV |
923 | } |
924 | ||
925 | constexpr _Tp& | |
926 | value()& | |
927 | { | |
928 | return this->_M_is_engaged() | |
d942bc80 JW |
929 | ? this->_M_get() |
930 | : (__throw_bad_optional_access(), this->_M_get()); | |
435e56fb VV |
931 | } |
932 | ||
933 | constexpr _Tp&& | |
934 | value()&& | |
935 | { | |
936 | return this->_M_is_engaged() | |
d942bc80 JW |
937 | ? std::move(this->_M_get()) |
938 | : (__throw_bad_optional_access(), std::move(this->_M_get())); | |
435e56fb VV |
939 | } |
940 | ||
941 | constexpr const _Tp&& | |
942 | value() const&& | |
943 | { | |
944 | return this->_M_is_engaged() | |
d942bc80 JW |
945 | ? std::move(this->_M_get()) |
946 | : (__throw_bad_optional_access(), std::move(this->_M_get())); | |
435e56fb VV |
947 | } |
948 | ||
949 | template<typename _Up> | |
950 | constexpr _Tp | |
951 | value_or(_Up&& __u) const& | |
952 | { | |
9057edd3 JW |
953 | static_assert(is_copy_constructible_v<_Tp>); |
954 | static_assert(is_convertible_v<_Up&&, _Tp>); | |
435e56fb VV |
955 | |
956 | return this->_M_is_engaged() | |
d942bc80 | 957 | ? this->_M_get() : static_cast<_Tp>(std::forward<_Up>(__u)); |
435e56fb VV |
958 | } |
959 | ||
960 | template<typename _Up> | |
02c9b9cc | 961 | constexpr _Tp |
435e56fb VV |
962 | value_or(_Up&& __u) && |
963 | { | |
9057edd3 JW |
964 | static_assert(is_move_constructible_v<_Tp>); |
965 | static_assert(is_convertible_v<_Up&&, _Tp>); | |
435e56fb VV |
966 | |
967 | return this->_M_is_engaged() | |
968 | ? std::move(this->_M_get()) | |
969 | : static_cast<_Tp>(std::forward<_Up>(__u)); | |
970 | } | |
b655b8fc | 971 | |
a181f672 | 972 | void reset() noexcept { this->_M_reset(); } |
435e56fb VV |
973 | }; |
974 | ||
86c0ec1d VV |
975 | template<typename _Tp> |
976 | using __optional_relop_t = | |
b655b8fc | 977 | enable_if_t<is_convertible<_Tp, bool>::value, bool>; |
86c0ec1d | 978 | |
40f3e913 | 979 | // Comparisons between optional values. |
06272afb | 980 | template<typename _Tp, typename _Up> |
86c0ec1d | 981 | constexpr auto |
06272afb VV |
982 | operator==(const optional<_Tp>& __lhs, const optional<_Up>& __rhs) |
983 | -> __optional_relop_t<decltype(declval<_Tp>() == declval<_Up>())> | |
435e56fb VV |
984 | { |
985 | return static_cast<bool>(__lhs) == static_cast<bool>(__rhs) | |
986 | && (!__lhs || *__lhs == *__rhs); | |
987 | } | |
988 | ||
06272afb | 989 | template<typename _Tp, typename _Up> |
86c0ec1d | 990 | constexpr auto |
06272afb VV |
991 | operator!=(const optional<_Tp>& __lhs, const optional<_Up>& __rhs) |
992 | -> __optional_relop_t<decltype(declval<_Tp>() != declval<_Up>())> | |
86c0ec1d VV |
993 | { |
994 | return static_cast<bool>(__lhs) != static_cast<bool>(__rhs) | |
995 | || (static_cast<bool>(__lhs) && *__lhs != *__rhs); | |
996 | } | |
435e56fb | 997 | |
06272afb | 998 | template<typename _Tp, typename _Up> |
86c0ec1d | 999 | constexpr auto |
06272afb VV |
1000 | operator<(const optional<_Tp>& __lhs, const optional<_Up>& __rhs) |
1001 | -> __optional_relop_t<decltype(declval<_Tp>() < declval<_Up>())> | |
435e56fb VV |
1002 | { |
1003 | return static_cast<bool>(__rhs) && (!__lhs || *__lhs < *__rhs); | |
1004 | } | |
1005 | ||
06272afb | 1006 | template<typename _Tp, typename _Up> |
86c0ec1d | 1007 | constexpr auto |
06272afb VV |
1008 | operator>(const optional<_Tp>& __lhs, const optional<_Up>& __rhs) |
1009 | -> __optional_relop_t<decltype(declval<_Tp>() > declval<_Up>())> | |
86c0ec1d VV |
1010 | { |
1011 | return static_cast<bool>(__lhs) && (!__rhs || *__lhs > *__rhs); | |
1012 | } | |
435e56fb | 1013 | |
06272afb | 1014 | template<typename _Tp, typename _Up> |
86c0ec1d | 1015 | constexpr auto |
06272afb VV |
1016 | operator<=(const optional<_Tp>& __lhs, const optional<_Up>& __rhs) |
1017 | -> __optional_relop_t<decltype(declval<_Tp>() <= declval<_Up>())> | |
86c0ec1d VV |
1018 | { |
1019 | return !__lhs || (static_cast<bool>(__rhs) && *__lhs <= *__rhs); | |
1020 | } | |
435e56fb | 1021 | |
06272afb | 1022 | template<typename _Tp, typename _Up> |
86c0ec1d | 1023 | constexpr auto |
06272afb VV |
1024 | operator>=(const optional<_Tp>& __lhs, const optional<_Up>& __rhs) |
1025 | -> __optional_relop_t<decltype(declval<_Tp>() >= declval<_Up>())> | |
86c0ec1d VV |
1026 | { |
1027 | return !__rhs || (static_cast<bool>(__lhs) && *__lhs >= *__rhs); | |
1028 | } | |
435e56fb | 1029 | |
40f3e913 | 1030 | // Comparisons with nullopt. |
435e56fb VV |
1031 | template<typename _Tp> |
1032 | constexpr bool | |
1033 | operator==(const optional<_Tp>& __lhs, nullopt_t) noexcept | |
1034 | { return !__lhs; } | |
1035 | ||
1036 | template<typename _Tp> | |
1037 | constexpr bool | |
1038 | operator==(nullopt_t, const optional<_Tp>& __rhs) noexcept | |
1039 | { return !__rhs; } | |
1040 | ||
1041 | template<typename _Tp> | |
1042 | constexpr bool | |
1043 | operator!=(const optional<_Tp>& __lhs, nullopt_t) noexcept | |
1044 | { return static_cast<bool>(__lhs); } | |
1045 | ||
1046 | template<typename _Tp> | |
1047 | constexpr bool | |
1048 | operator!=(nullopt_t, const optional<_Tp>& __rhs) noexcept | |
1049 | { return static_cast<bool>(__rhs); } | |
1050 | ||
1051 | template<typename _Tp> | |
1052 | constexpr bool | |
1053 | operator<(const optional<_Tp>& /* __lhs */, nullopt_t) noexcept | |
1054 | { return false; } | |
1055 | ||
1056 | template<typename _Tp> | |
1057 | constexpr bool | |
1058 | operator<(nullopt_t, const optional<_Tp>& __rhs) noexcept | |
1059 | { return static_cast<bool>(__rhs); } | |
1060 | ||
1061 | template<typename _Tp> | |
1062 | constexpr bool | |
1063 | operator>(const optional<_Tp>& __lhs, nullopt_t) noexcept | |
1064 | { return static_cast<bool>(__lhs); } | |
1065 | ||
1066 | template<typename _Tp> | |
1067 | constexpr bool | |
1068 | operator>(nullopt_t, const optional<_Tp>& /* __rhs */) noexcept | |
1069 | { return false; } | |
1070 | ||
1071 | template<typename _Tp> | |
1072 | constexpr bool | |
1073 | operator<=(const optional<_Tp>& __lhs, nullopt_t) noexcept | |
1074 | { return !__lhs; } | |
1075 | ||
1076 | template<typename _Tp> | |
1077 | constexpr bool | |
1078 | operator<=(nullopt_t, const optional<_Tp>& /* __rhs */) noexcept | |
1079 | { return true; } | |
1080 | ||
1081 | template<typename _Tp> | |
1082 | constexpr bool | |
1083 | operator>=(const optional<_Tp>& /* __lhs */, nullopt_t) noexcept | |
1084 | { return true; } | |
1085 | ||
1086 | template<typename _Tp> | |
1087 | constexpr bool | |
1088 | operator>=(nullopt_t, const optional<_Tp>& __rhs) noexcept | |
1089 | { return !__rhs; } | |
1090 | ||
40f3e913 | 1091 | // Comparisons with value type. |
06272afb | 1092 | template<typename _Tp, typename _Up> |
86c0ec1d | 1093 | constexpr auto |
06272afb VV |
1094 | operator==(const optional<_Tp>& __lhs, const _Up& __rhs) |
1095 | -> __optional_relop_t<decltype(declval<_Tp>() == declval<_Up>())> | |
435e56fb VV |
1096 | { return __lhs && *__lhs == __rhs; } |
1097 | ||
06272afb | 1098 | template<typename _Tp, typename _Up> |
86c0ec1d | 1099 | constexpr auto |
06272afb VV |
1100 | operator==(const _Up& __lhs, const optional<_Tp>& __rhs) |
1101 | -> __optional_relop_t<decltype(declval<_Up>() == declval<_Tp>())> | |
435e56fb VV |
1102 | { return __rhs && __lhs == *__rhs; } |
1103 | ||
06272afb | 1104 | template<typename _Tp, typename _Up> |
86c0ec1d | 1105 | constexpr auto |
06272afb VV |
1106 | operator!=(const optional<_Tp>& __lhs, const _Up& __rhs) |
1107 | -> __optional_relop_t<decltype(declval<_Tp>() != declval<_Up>())> | |
86c0ec1d | 1108 | { return !__lhs || *__lhs != __rhs; } |
435e56fb | 1109 | |
06272afb | 1110 | template<typename _Tp, typename _Up> |
86c0ec1d | 1111 | constexpr auto |
06272afb VV |
1112 | operator!=(const _Up& __lhs, const optional<_Tp>& __rhs) |
1113 | -> __optional_relop_t<decltype(declval<_Up>() != declval<_Tp>())> | |
86c0ec1d | 1114 | { return !__rhs || __lhs != *__rhs; } |
435e56fb | 1115 | |
06272afb | 1116 | template<typename _Tp, typename _Up> |
86c0ec1d | 1117 | constexpr auto |
06272afb VV |
1118 | operator<(const optional<_Tp>& __lhs, const _Up& __rhs) |
1119 | -> __optional_relop_t<decltype(declval<_Tp>() < declval<_Up>())> | |
435e56fb VV |
1120 | { return !__lhs || *__lhs < __rhs; } |
1121 | ||
06272afb | 1122 | template<typename _Tp, typename _Up> |
86c0ec1d | 1123 | constexpr auto |
06272afb VV |
1124 | operator<(const _Up& __lhs, const optional<_Tp>& __rhs) |
1125 | -> __optional_relop_t<decltype(declval<_Up>() < declval<_Tp>())> | |
435e56fb VV |
1126 | { return __rhs && __lhs < *__rhs; } |
1127 | ||
06272afb | 1128 | template<typename _Tp, typename _Up> |
86c0ec1d | 1129 | constexpr auto |
06272afb VV |
1130 | operator>(const optional<_Tp>& __lhs, const _Up& __rhs) |
1131 | -> __optional_relop_t<decltype(declval<_Tp>() > declval<_Up>())> | |
86c0ec1d | 1132 | { return __lhs && *__lhs > __rhs; } |
435e56fb | 1133 | |
06272afb | 1134 | template<typename _Tp, typename _Up> |
86c0ec1d | 1135 | constexpr auto |
06272afb VV |
1136 | operator>(const _Up& __lhs, const optional<_Tp>& __rhs) |
1137 | -> __optional_relop_t<decltype(declval<_Up>() > declval<_Tp>())> | |
86c0ec1d | 1138 | { return !__rhs || __lhs > *__rhs; } |
435e56fb | 1139 | |
06272afb | 1140 | template<typename _Tp, typename _Up> |
86c0ec1d | 1141 | constexpr auto |
06272afb VV |
1142 | operator<=(const optional<_Tp>& __lhs, const _Up& __rhs) |
1143 | -> __optional_relop_t<decltype(declval<_Tp>() <= declval<_Up>())> | |
86c0ec1d | 1144 | { return !__lhs || *__lhs <= __rhs; } |
435e56fb | 1145 | |
06272afb | 1146 | template<typename _Tp, typename _Up> |
86c0ec1d | 1147 | constexpr auto |
06272afb VV |
1148 | operator<=(const _Up& __lhs, const optional<_Tp>& __rhs) |
1149 | -> __optional_relop_t<decltype(declval<_Up>() <= declval<_Tp>())> | |
86c0ec1d | 1150 | { return __rhs && __lhs <= *__rhs; } |
435e56fb | 1151 | |
06272afb | 1152 | template<typename _Tp, typename _Up> |
86c0ec1d | 1153 | constexpr auto |
06272afb VV |
1154 | operator>=(const optional<_Tp>& __lhs, const _Up& __rhs) |
1155 | -> __optional_relop_t<decltype(declval<_Tp>() >= declval<_Up>())> | |
86c0ec1d | 1156 | { return __lhs && *__lhs >= __rhs; } |
435e56fb | 1157 | |
06272afb | 1158 | template<typename _Tp, typename _Up> |
86c0ec1d | 1159 | constexpr auto |
06272afb VV |
1160 | operator>=(const _Up& __lhs, const optional<_Tp>& __rhs) |
1161 | -> __optional_relop_t<decltype(declval<_Up>() >= declval<_Tp>())> | |
86c0ec1d | 1162 | { return !__rhs || __lhs >= *__rhs; } |
435e56fb | 1163 | |
40f3e913 | 1164 | // Swap and creation functions. |
8b99f005 JW |
1165 | |
1166 | // _GLIBCXX_RESOLVE_LIB_DEFECTS | |
1167 | // 2748. swappable traits for optionals | |
435e56fb | 1168 | template<typename _Tp> |
8b99f005 | 1169 | inline enable_if_t<is_move_constructible_v<_Tp> && is_swappable_v<_Tp>> |
435e56fb VV |
1170 | swap(optional<_Tp>& __lhs, optional<_Tp>& __rhs) |
1171 | noexcept(noexcept(__lhs.swap(__rhs))) | |
1172 | { __lhs.swap(__rhs); } | |
1173 | ||
a2863bde | 1174 | template<typename _Tp> |
1d752b4f | 1175 | enable_if_t<!(is_move_constructible_v<_Tp> && is_swappable_v<_Tp>)> |
a2863bde VV |
1176 | swap(optional<_Tp>&, optional<_Tp>&) = delete; |
1177 | ||
435e56fb VV |
1178 | template<typename _Tp> |
1179 | constexpr optional<decay_t<_Tp>> | |
1180 | make_optional(_Tp&& __t) | |
1181 | { return optional<decay_t<_Tp>> { std::forward<_Tp>(__t) }; } | |
1182 | ||
25a69162 VV |
1183 | template<typename _Tp, typename ..._Args> |
1184 | constexpr optional<_Tp> | |
1185 | make_optional(_Args&&... __args) | |
1186 | { return optional<_Tp> { in_place, std::forward<_Args>(__args)... }; } | |
1187 | ||
1188 | template<typename _Tp, typename _Up, typename ..._Args> | |
1189 | constexpr optional<_Tp> | |
1190 | make_optional(initializer_list<_Up> __il, _Args&&... __args) | |
1191 | { return optional<_Tp> { in_place, __il, std::forward<_Args>(__args)... }; } | |
1192 | ||
40f3e913 | 1193 | // Hash. |
435e56fb | 1194 | |
f6b05c44 JW |
1195 | template<typename _Tp, typename _Up = remove_const_t<_Tp>, |
1196 | bool = __poison_hash<_Up>::__enable_hash_call> | |
509912a6 VV |
1197 | struct __optional_hash_call_base |
1198 | { | |
435e56fb VV |
1199 | size_t |
1200 | operator()(const optional<_Tp>& __t) const | |
f6b05c44 | 1201 | noexcept(noexcept(hash<_Up>{}(*__t))) |
435e56fb VV |
1202 | { |
1203 | // We pick an arbitrary hash for disengaged optionals which hopefully | |
1204 | // usual values of _Tp won't typically hash to. | |
1205 | constexpr size_t __magic_disengaged_hash = static_cast<size_t>(-3333); | |
f6b05c44 | 1206 | return __t ? hash<_Up>{}(*__t) : __magic_disengaged_hash; |
435e56fb VV |
1207 | } |
1208 | }; | |
1209 | ||
f6b05c44 JW |
1210 | template<typename _Tp, typename _Up> |
1211 | struct __optional_hash_call_base<_Tp, _Up, false> {}; | |
509912a6 VV |
1212 | |
1213 | template<typename _Tp> | |
1214 | struct hash<optional<_Tp>> | |
1215 | : private __poison_hash<remove_const_t<_Tp>>, | |
1216 | public __optional_hash_call_base<_Tp> | |
1217 | { | |
f78958c9 JW |
1218 | using result_type [[__deprecated__]] = size_t; |
1219 | using argument_type [[__deprecated__]] = optional<_Tp>; | |
509912a6 VV |
1220 | }; |
1221 | ||
f78958c9 JW |
1222 | template<typename _Tp> |
1223 | struct __is_fast_hash<hash<optional<_Tp>>> : __is_fast_hash<hash<_Tp>> | |
1224 | { }; | |
1225 | ||
435e56fb VV |
1226 | /// @} |
1227 | ||
8bdbeed1 | 1228 | #if __cpp_deduction_guides >= 201606 |
1dd95239 | 1229 | template <typename _Tp> optional(_Tp) -> optional<_Tp>; |
8bdbeed1 | 1230 | #endif |
1dd95239 | 1231 | |
435e56fb VV |
1232 | _GLIBCXX_END_NAMESPACE_VERSION |
1233 | } // namespace std | |
1234 | ||
1235 | #endif // C++17 | |
1236 | ||
1237 | #endif // _GLIBCXX_OPTIONAL |