Line data Source code
1 : // Copyright (C) 2011 - 2012 Andrzej Krzemienski.
2 : //
3 : // Use, modification, and distribution is subject to the Boost Software
4 : // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
5 : // http://www.boost.org/LICENSE_1_0.txt)
6 : //
7 : // The idea and interface is based on Boost.Optional library
8 : // authored by Fernando Luis Cacciola Carballal
9 : //
10 : // From https://github.com/akrzemi1/Optional
11 : //
12 : // C10
13 : // - Move file to `c10` namespace.
14 : // - Remove macro use in line 478 because the nvcc device compiler cannot handle
15 : // it.
16 : // - Revise constructor logic so that it is 1) consistent with c++ 17 standard
17 : // documented here in (8):
18 : // https://en.cppreference.com/w/cpp/utility/optional/optional, and 2) able to
19 : // support initialization of optionals from convertible type U.
20 : // - Remove the constructors for `optional(const T&)` and `optional(T&&)`, as
21 : // they can be handled by the template<U=T> case with the default template
22 : // argument.
23 : // - Move `constexpr struct in_place_t {} in_place{}` to `c10/util/in_place.h`
24 : // so that it can also be used in `c10/util/variant.h`.
25 : // - Remove special cases for pre-c++14 compilers to make code simpler.
26 :
27 : #ifndef C10_UTIL_OPTIONAL_H_
28 : #define C10_UTIL_OPTIONAL_H_
29 :
30 : #include <c10/macros/Macros.h>
31 : #include <c10/util/ArrayRef.h>
32 : #include <c10/util/in_place.h>
33 :
34 : #include <cassert>
35 : #include <functional>
36 : #include <initializer_list>
37 : #include <stdexcept>
38 : #include <string>
39 : #include <type_traits>
40 : #include <utility>
41 :
42 : #include <c10/util/C++17.h>
43 : #include <c10/util/Metaprogramming.h>
44 :
45 : C10_CLANG_DIAGNOSTIC_PUSH()
46 : #if C10_CLANG_HAS_WARNING("-Wstring-conversion")
47 : C10_CLANG_DIAGNOSTIC_IGNORE("-Wstring-conversion")
48 : #endif
49 : #if C10_CLANG_HAS_WARNING("-Wshorten-64-to-32")
50 : C10_CLANG_DIAGNOSTIC_IGNORE("-Wshorten-64-to-32")
51 : #endif
52 : #if C10_CLANG_HAS_WARNING("-Wimplicit-float-conversion")
53 : C10_CLANG_DIAGNOSTIC_IGNORE("-Wimplicit-float-conversion")
54 : #endif
55 : #if C10_CLANG_HAS_WARNING("-Wimplicit-int-conversion")
56 : C10_CLANG_DIAGNOSTIC_IGNORE("-Wimplicit-int-conversion")
57 : #endif
58 :
59 : #if defined(_MSC_VER) && !defined(__clang__)
60 : #pragma warning(push)
61 : #pragma warning(disable : 4624) // destructor was implicitly defined as deleted
62 : #endif
63 :
64 : #define TR2_OPTIONAL_REQUIRES(...) \
65 : typename std::enable_if<__VA_ARGS__::value, bool>::type = false
66 :
67 : namespace c10 {
68 :
69 : // 20.5.4, optional for object types
70 : template <class T>
71 : class optional;
72 :
73 : // 20.5.5, optional for lvalue reference types
74 : template <class T>
75 : class optional<T&>;
76 :
77 : // workaround: std utility functions aren't constexpr yet
78 : template <class T>
79 199233304 : inline constexpr T&& constexpr_forward(
80 : typename std::remove_reference<T>::type& t) noexcept {
81 199233304 : return static_cast<T&&>(t);
82 : }
83 :
84 : template <class T>
85 : inline constexpr T&& constexpr_forward(
86 : typename std::remove_reference<T>::type&& t) noexcept {
87 : static_assert(!std::is_lvalue_reference<T>::value, "!!");
88 : return static_cast<T&&>(t);
89 : }
90 :
91 : template <class T>
92 196750336 : inline constexpr typename std::remove_reference<T>::type&& constexpr_move(
93 : T&& t) noexcept {
94 196750336 : return static_cast<typename std::remove_reference<T>::type&&>(t);
95 : }
96 :
97 : #if defined NDEBUG
98 : #define TR2_OPTIONAL_ASSERTED_EXPRESSION(CHECK, EXPR) (EXPR)
99 : #else
100 : #define TR2_OPTIONAL_ASSERTED_EXPRESSION(CHECK, EXPR) \
101 : ((CHECK) ? (EXPR) : ([] { assert(!#CHECK); }(), (EXPR)))
102 : #endif
103 :
104 : #if defined(__CUDA_ARCH__)
105 : #define TR2_OPTIONAL_HOST_CONSTEXPR
106 : #else
107 : #define TR2_OPTIONAL_HOST_CONSTEXPR constexpr
108 : #endif
109 :
110 : // Sphinx chokes on static_addressof, so exclude it from Doxygen
111 : // generation. See https://github.com/sphinx-doc/sphinx/issues/7944
112 : // \cond
113 :
114 : namespace detail_ {
115 :
116 : // VS doesn't handle constexpr well, so we need to skip these stuff.
117 : #if (defined _MSC_VER)
118 : template <typename T>
119 : T* static_addressof(T& ref) {
120 : return std::addressof(ref);
121 : }
122 : #else
123 : // static_addressof: a constexpr version of addressof
124 : template <typename T>
125 : struct has_overloaded_addressof {
126 : template <class X>
127 : constexpr static bool has_overload(...) {
128 : return false;
129 : }
130 :
131 : template <class X, size_t S = sizeof(std::declval<X&>().operator&())>
132 : constexpr static bool has_overload(bool) {
133 : return true;
134 : }
135 :
136 : constexpr static bool value = has_overload<T>(true);
137 : };
138 :
139 : template <typename T, TR2_OPTIONAL_REQUIRES(!has_overloaded_addressof<T>)>
140 : constexpr T* static_addressof(T& ref) {
141 : return &ref;
142 : }
143 :
144 : template <typename T, TR2_OPTIONAL_REQUIRES(has_overloaded_addressof<T>)>
145 : T* static_addressof(T& ref) {
146 : return std::addressof(ref);
147 : }
148 : #endif
149 :
150 : // the call to convert<A>(b) has return type A and converts b to type A iff b
151 : // decltype(b) is implicitly convertible to A
152 : template <class U>
153 0 : constexpr U convert(U v) {
154 0 : return v;
155 : }
156 :
157 : } // namespace detail_
158 :
159 : // \endcond
160 :
161 : constexpr struct trivial_init_t {
162 : } trivial_init{};
163 :
164 : // 20.5.7, Disengaged state indicator
165 : struct nullopt_t {
166 : constexpr explicit nullopt_t(int) {}
167 : };
168 : constexpr nullopt_t nullopt{0};
169 :
170 : // 20.5.8, class bad_optional_access
171 : class bad_optional_access : public std::logic_error {
172 : public:
173 : explicit bad_optional_access(const std::string& what_arg)
174 : : logic_error{what_arg} {}
175 0 : explicit bad_optional_access(const char* what_arg) : logic_error{what_arg} {}
176 : };
177 :
178 : template <class T>
179 : union storage_t {
180 : unsigned char dummy_{};
181 : T value_;
182 :
183 : #if __cplusplus >= 202002L
184 : constexpr
185 : #endif
186 216200968 : storage_t(trivial_init_t) noexcept {
187 216200968 : new (&dummy_) unsigned char;
188 216200968 : }
189 :
190 : template <class... Args>
191 105308712 : constexpr storage_t(Args&&... args)
192 105308712 : : value_(constexpr_forward<Args>(args)...) {}
193 :
194 321509680 : ~storage_t() {}
195 : };
196 :
197 : template <class T>
198 : union constexpr_storage_t {
199 : unsigned char dummy_;
200 : T value_;
201 :
202 : #if __cplusplus >= 202002L
203 : // C++20 lifted the requirement to initialize a union member in order to be
204 : // constexpr.
205 : constexpr constexpr_storage_t(trivial_init_t) noexcept {
206 : new (&dummy_) unsigned char;
207 : }
208 : #else
209 2945770 : constexpr constexpr_storage_t(trivial_init_t) noexcept : dummy_() {}
210 : #endif
211 :
212 : template <class... Args>
213 92688986 : constexpr constexpr_storage_t(Args&&... args)
214 92688986 : : value_(constexpr_forward<Args>(args)...) {}
215 :
216 : ~constexpr_storage_t() = default;
217 : };
218 :
219 : template <class T>
220 : struct optional_base {
221 : bool init_;
222 : storage_t<T> storage_;
223 :
224 110924592 : constexpr optional_base() noexcept : init_(false), storage_(trivial_init){};
225 :
226 : explicit constexpr optional_base(const optional_base<T>& v)
227 : : init_(v.init_), storage_(trivial_init) {
228 : if (init_) {
229 : ::new (dataptr()) T(v.storage_.value_);
230 : }
231 : }
232 :
233 31316 : explicit constexpr optional_base(const T& v) : init_(true), storage_(v) {}
234 :
235 105276376 : explicit constexpr optional_base(optional_base<T>&& v) noexcept(
236 : std::is_nothrow_move_constructible<T>::value)
237 105276376 : : init_(v.init_), storage_(trivial_init) {
238 105276376 : if (init_) {
239 105276376 : ::new (dataptr()) T(std::move(v.storage_.value_));
240 : }
241 105276376 : }
242 :
243 105277396 : explicit constexpr optional_base(T&& v)
244 105277396 : : init_(true), storage_(constexpr_move(v)) {}
245 :
246 : template <class... Args>
247 : explicit optional_base(in_place_t, Args&&... args)
248 : : init_(true), storage_(constexpr_forward<Args>(args)...) {}
249 :
250 : template <
251 : class U,
252 : class... Args,
253 : TR2_OPTIONAL_REQUIRES(std::is_constructible<T, std::initializer_list<U>>)>
254 : explicit optional_base(
255 : in_place_t,
256 : std::initializer_list<U> il,
257 : Args&&... args)
258 : : init_(true), storage_(il, std::forward<Args>(args)...) {}
259 :
260 : optional_base& operator=(const optional_base& rhs) {
261 : if (init_ && !rhs.init_) {
262 : clear();
263 : } else if (!init_ && rhs.init_) {
264 : init_ = true;
265 : ::new (dataptr()) T(rhs.storage_.value_);
266 : } else if (init_ && rhs.init_) {
267 : storage_.value_ = rhs.storage_.value_;
268 : }
269 : return *this;
270 : }
271 :
272 : optional_base& operator=(optional_base&& rhs) noexcept(
273 : std::is_nothrow_move_assignable<T>::value&&
274 : std::is_nothrow_move_constructible<T>::value) {
275 : if (init_ && !rhs.init_) {
276 : clear();
277 : } else if (!init_ && rhs.init_) {
278 : init_ = true;
279 : ::new (dataptr()) T(std::move(rhs.storage_.value_));
280 : } else if (init_ && rhs.init_) {
281 : storage_.value_ = std::move(rhs.storage_.value_);
282 : }
283 : return *this;
284 : }
285 :
286 321509680 : ~optional_base() {
287 321509680 : if (init_)
288 210585088 : storage_.value_.T::~T();
289 321509680 : }
290 :
291 321479384 : constexpr bool initialized() const noexcept {
292 321479384 : return init_;
293 : }
294 :
295 : void setInitialized(bool init) noexcept {
296 : init_ = init;
297 : }
298 :
299 : private:
300 105276376 : typename std::remove_const<T>::type* dataptr() {
301 105276376 : return std::addressof(storage_.value_);
302 : }
303 :
304 : constexpr const T* dataptr() const {
305 : return detail_::static_addressof(storage_.value_);
306 : }
307 :
308 : void clear() noexcept {
309 : if (init_) {
310 : dataptr()->~T();
311 : }
312 : init_ = false;
313 : }
314 : };
315 :
316 : template <class T>
317 : struct constexpr_optional_base {
318 : bool init_;
319 : constexpr_storage_t<T> storage_;
320 :
321 : constexpr constexpr_optional_base() noexcept
322 : : init_(false), storage_(trivial_init){};
323 :
324 : explicit constexpr constexpr_optional_base(
325 : const constexpr_optional_base<T>& v)
326 : : init_(v.init_), storage_(trivial_init) {
327 : if (init_) {
328 : ::new (dataptr()) T(v.storage_.value_);
329 : }
330 : }
331 :
332 : explicit constexpr constexpr_optional_base(
333 : constexpr_optional_base<T>&&
334 : v) noexcept(std::is_nothrow_move_constructible<T>::value)
335 : : init_(v.init_), storage_(trivial_init) {
336 : if (init_) {
337 : ::new (dataptr()) T(std::move(v.storage_.value_));
338 : }
339 : }
340 :
341 : explicit constexpr constexpr_optional_base(const T& v)
342 : : init_(true), storage_(v) {}
343 :
344 : explicit constexpr constexpr_optional_base(T&& v)
345 : : init_(true), storage_(constexpr_move(v)) {}
346 :
347 : template <class... Args>
348 : explicit constexpr constexpr_optional_base(in_place_t, Args&&... args)
349 : : init_(true), storage_(constexpr_forward<Args>(args)...) {}
350 :
351 : template <
352 : class U,
353 : class... Args,
354 : TR2_OPTIONAL_REQUIRES(std::is_constructible<T, std::initializer_list<U>>)>
355 : constexpr explicit constexpr_optional_base(
356 : in_place_t,
357 : std::initializer_list<U> il,
358 : Args&&... args)
359 : : init_(true), storage_(il, std::forward<Args>(args)...) {}
360 :
361 : ~constexpr_optional_base() = default;
362 :
363 : constexpr_optional_base& operator=(const constexpr_optional_base& rhs) {
364 : if (init_ && !rhs.init_) {
365 : clear();
366 : } else if (!init_ && rhs.init_) {
367 : init_ = true;
368 : ::new (dataptr()) T(rhs.storage_.value_);
369 : } else if (init_ && rhs.init_) {
370 : storage_.value_ = rhs.storage_.value_;
371 : }
372 : return *this;
373 : }
374 :
375 : constexpr_optional_base& operator=(constexpr_optional_base&& rhs) noexcept(
376 : std::is_nothrow_move_assignable<T>::value&&
377 : std::is_nothrow_move_constructible<T>::value) {
378 : if (init_ && !rhs.init_) {
379 : clear();
380 : } else if (!init_ && rhs.init_) {
381 : init_ = true;
382 : ::new (dataptr()) T(std::move(rhs.storage_.value_));
383 : } else if (init_ && rhs.init_) {
384 : storage_.value_ = std::move(rhs.storage_.value_);
385 : }
386 : return *this;
387 : }
388 :
389 : constexpr bool initialized() const noexcept {
390 : return init_;
391 : }
392 : void setInitialized(bool init) noexcept {
393 : init_ = init;
394 : }
395 :
396 : private:
397 : typename std::remove_const<T>::type* dataptr() {
398 : return std::addressof(storage_.value_);
399 : }
400 :
401 : constexpr const T* dataptr() const {
402 : return detail_::static_addressof(storage_.value_);
403 : }
404 :
405 : void clear() noexcept {
406 : init_ = false;
407 : }
408 : };
409 :
410 : // HACK: Optimization for trivially copyable types. The mainline
411 : // implementation fails to have trivial copy/move operations in these
412 : // cases, and we care about them, so just implement that directly.
413 : template <class T>
414 : struct trivially_copyable_optimization_optional_base {
415 : bool init_;
416 : constexpr_storage_t<T> storage_;
417 :
418 2945770 : constexpr trivially_copyable_optimization_optional_base() noexcept
419 2945770 : : init_(false), storage_(trivial_init) {}
420 :
421 814728 : explicit constexpr trivially_copyable_optimization_optional_base(const T& v)
422 814728 : : init_(true), storage_(v) {}
423 :
424 91472940 : explicit constexpr trivially_copyable_optimization_optional_base(T&& v)
425 91472940 : : init_(true), storage_(constexpr_move(v)) {}
426 :
427 : template <class... Args>
428 401318 : explicit constexpr trivially_copyable_optimization_optional_base(
429 : in_place_t,
430 : Args&&... args)
431 401318 : : init_(true), storage_(constexpr_forward<Args>(args)...) {}
432 :
433 : template <
434 : class U,
435 : class... Args,
436 : TR2_OPTIONAL_REQUIRES(std::is_constructible<T, std::initializer_list<U>>)>
437 : constexpr explicit trivially_copyable_optimization_optional_base(
438 : in_place_t,
439 : std::initializer_list<U> il,
440 : Args&&... args)
441 : : init_(true), storage_(il, std::forward<Args>(args)...) {}
442 :
443 : ~trivially_copyable_optimization_optional_base() = default;
444 :
445 185760028 : constexpr bool initialized() const noexcept {
446 185760028 : return init_;
447 : }
448 : void setInitialized(bool init) noexcept {
449 : init_ = init;
450 : }
451 : };
452 :
453 : // HACK: Optimization for ArrayRef<T>. We take advantage of an unused
454 : // bit pattern in ArrayRef (inspired by Arthur O'Dwyer's
455 : // tombstone_traits -- see https://youtu.be/MWBfmmg8-Yo?t=2466) to
456 : // keep the size of c10::optional::ArrayRef<T> down to 16 bytes, which
457 : // allows it to be passed to functions in registers instead of getting
458 : // passed in memory per item 5c of the classification algorithm in
459 : // section 3.2.3 of the System V ABI document
460 : // (https://www.uclibc.org/docs/psABI-x86_64.pdf).
461 : template <class ArrayRefT>
462 : class arrayref_optional_base {
463 : public:
464 : union storage {
465 : struct raw {
466 : // ArrayRef has the invariant that if Data is nullptr then
467 : // Length must be zero, so this is an unused bit pattern.
468 : const void* p = nullptr;
469 : size_t sz = 1;
470 : } uninitialized_{};
471 : ArrayRefT value_;
472 :
473 16480 : constexpr storage() noexcept : uninitialized_() {
474 16480 : setUninitialized();
475 16480 : }
476 :
477 16480 : constexpr void setUninitialized() noexcept {
478 16480 : uninitialized_.p = nullptr;
479 16480 : uninitialized_.sz = 1;
480 16480 : }
481 :
482 : explicit constexpr storage(ArrayRefT& v) : value_(v) {}
483 :
484 : template <typename T>
485 : explicit constexpr storage(const std::initializer_list<T>& v) : value_(v) {}
486 :
487 : template <class... Args>
488 14194 : explicit constexpr storage(Args&&... args)
489 14194 : : value_(constexpr_forward<Args>(args)...) {}
490 : };
491 :
492 : storage storage_;
493 :
494 16480 : constexpr arrayref_optional_base() noexcept = default;
495 :
496 14194 : explicit constexpr arrayref_optional_base(const ArrayRefT& v) : storage_(v) {}
497 :
498 : template <class... Args>
499 : explicit constexpr arrayref_optional_base(in_place_t, Args&&... args)
500 : : storage_(constexpr_forward<Args>(args)...) {}
501 :
502 : template <typename T>
503 : explicit constexpr arrayref_optional_base(
504 : in_place_t,
505 : const std::initializer_list<T>& v)
506 : : storage_(v) {}
507 :
508 : constexpr bool initialized() const noexcept {
509 : return storage_.uninitialized_.p != nullptr ||
510 : storage_.uninitialized_.sz == 0;
511 : }
512 :
513 : void setInitialized(bool init) noexcept {
514 : if (!init) {
515 : storage_.setUninitialized();
516 : } else {
517 : assert(initialized());
518 : }
519 : }
520 : };
521 :
522 : namespace detail_ {
523 : template <typename T>
524 : struct is_arrayref : std::false_type {};
525 :
526 : template <typename T>
527 : struct is_arrayref<c10::ArrayRef<T>> : std::true_type {};
528 : } // namespace detail_
529 :
530 : template <class T>
531 : using OptionalBase = std::conditional_t<
532 : detail_::is_arrayref<T>::value,
533 : arrayref_optional_base<T>,
534 : std::conditional_t<
535 : std::is_trivially_destructible<T>::value &&
536 : C10_IS_TRIVIALLY_COPYABLE(T) &&
537 : // Avoid using is_trivially_copy_{constructible,assignable}
538 : // because old GCC versions don't support them. Also,
539 : // is_trivially_copyable seems not to do what I expect, so check
540 : // trivially_copyable_optimization_optional_base directly.
541 : std::is_copy_constructible<
542 : trivially_copyable_optimization_optional_base<T>>::value &&
543 : std::is_copy_assignable<
544 : trivially_copyable_optimization_optional_base<T>>::value,
545 : trivially_copyable_optimization_optional_base<T>,
546 : std::conditional_t<
547 : std::is_trivially_destructible<T>::value, // if possible
548 : constexpr_optional_base<std::remove_const_t<T>>, // use base with
549 : // trivial
550 : // destructor
551 : optional_base<std::remove_const_t<T>>>>>;
552 :
553 : template <class T>
554 : class optional : private OptionalBase<T> {
555 : template <class U> // re-declaration for nvcc on Windows.
556 : using OptionalBase = std::conditional_t<
557 : detail_::is_arrayref<U>::value,
558 : arrayref_optional_base<U>,
559 : std::conditional_t<
560 : std::is_trivially_destructible<U>::value &&
561 : C10_IS_TRIVIALLY_COPYABLE(U) &&
562 : // Avoid using is_trivially_copy_{constructible,assignable}
563 : // because old GCC versions don't support them. Also,
564 : // is_trivially_copyable seems not to do what I expect, so
565 : // check trivially_copyable_optimization_optional_base
566 : // directly.
567 : std::is_copy_constructible<
568 : trivially_copyable_optimization_optional_base<U>>::value &&
569 : std::is_copy_assignable<
570 : trivially_copyable_optimization_optional_base<U>>::value,
571 : trivially_copyable_optimization_optional_base<U>,
572 : std::conditional_t<
573 : std::is_trivially_destructible<U>::value, // if possible
574 : constexpr_optional_base<std::remove_const_t<U>>, // use base
575 : // with
576 : // trivial
577 : // destructor
578 : optional_base<std::remove_const_t<U>>>>>;
579 :
580 : static_assert(
581 : !std::is_same<typename std::decay<T>::type, nullopt_t>::value,
582 : "bad T");
583 : static_assert(
584 : !std::is_same<typename std::decay<T>::type, in_place_t>::value,
585 : "bad T");
586 :
587 507239412 : constexpr bool initialized() const noexcept {
588 507239412 : return OptionalBase<T>::initialized();
589 : }
590 418776 : typename std::remove_const<T>::type* dataptr() {
591 418776 : return std::addressof(OptionalBase<T>::storage_.value_);
592 : }
593 : constexpr const T* dataptr() const {
594 : return detail_::static_addressof(OptionalBase<T>::storage_.value_);
595 : }
596 :
597 0 : constexpr const T& contained_val() const& {
598 0 : return OptionalBase<T>::storage_.value_;
599 : }
600 : constexpr T&& contained_val() && {
601 : return std::move(OptionalBase<T>::storage_.value_);
602 : }
603 197127776 : constexpr T& contained_val() & {
604 197127776 : return OptionalBase<T>::storage_.value_;
605 : }
606 :
607 : void clear() noexcept {
608 : if (initialized())
609 : dataptr()->~T();
610 : OptionalBase<T>::setInitialized(false);
611 : }
612 :
613 : template <class... Args>
614 : void initialize(Args&&... args) noexcept(
615 : noexcept(T(std::forward<Args>(args)...))) {
616 : assert(!initialized());
617 : ::new (static_cast<void*>(dataptr())) T(std::forward<Args>(args)...);
618 : OptionalBase<T>::setInitialized(true);
619 : }
620 :
621 : template <class U, class... Args>
622 : void initialize(std::initializer_list<U> il, Args&&... args) noexcept(
623 : noexcept(T(il, std::forward<Args>(args)...))) {
624 : assert(!initialized());
625 : ::new (static_cast<void*>(dataptr())) T(il, std::forward<Args>(args)...);
626 : OptionalBase<T>::setInitialized(true);
627 : }
628 :
629 : public:
630 : typedef T value_type;
631 :
632 : // 20.5.5.1, constructors
633 16480 : constexpr optional() noexcept = default;
634 113870362 : constexpr optional(nullopt_t) noexcept : OptionalBase<T>(){};
635 :
636 : optional(const optional& rhs) = default;
637 105276376 : optional(optional&& rhs) = default;
638 :
639 : // see https://github.com/akrzemi1/Optional/issues/16
640 : // and https://en.cppreference.com/w/cpp/utility/optional/optional,
641 : // in constructor 8, the std::optional spec can allow initialization
642 : // of optionals from convertible type U
643 : //
644 : // 8 - implicit move construct from value
645 : template <
646 : typename U = T,
647 : TR2_OPTIONAL_REQUIRES(
648 : std::is_constructible<T, U&&>::value &&
649 : !std::is_same<typename std::decay<U>::type, in_place_t>::value &&
650 : !std::is_same<typename std::decay<U>::type, optional<T>>::value &&
651 : std::is_convertible<U&&, T>)>
652 197610574 : constexpr optional(U&& u) : OptionalBase<T>(std::forward<U>(u)) {}
653 :
654 : // 8 - explicit move construct from value
655 : template <
656 : typename U = T,
657 : TR2_OPTIONAL_REQUIRES(
658 : std::is_constructible<T, U&&>::value &&
659 : !std::is_same<typename std::decay<U>::type, in_place_t>::value &&
660 : !std::is_same<typename std::decay<U>::type, optional<T>>::value &&
661 : !std::is_convertible<U&&, T>)>
662 : explicit constexpr optional(U&& u) : OptionalBase<T>(std::forward<U>(u)) {}
663 :
664 : template <class... Args>
665 401318 : explicit constexpr optional(in_place_t, Args&&... args)
666 401318 : : OptionalBase<T>(in_place_t{}, constexpr_forward<Args>(args)...) {}
667 :
668 : template <
669 : class U,
670 : class... Args,
671 : TR2_OPTIONAL_REQUIRES(std::is_constructible<T, std::initializer_list<U>>)>
672 : constexpr explicit optional(
673 : in_place_t,
674 : std::initializer_list<U> il,
675 : Args&&... args)
676 : : OptionalBase<T>(in_place_t{}, il, constexpr_forward<Args>(args)...) {}
677 :
678 : // 20.5.4.2, Destructor
679 321509680 : ~optional() = default;
680 :
681 : // 20.5.4.3, assignment
682 : optional& operator=(nullopt_t) noexcept {
683 : clear();
684 : return *this;
685 : }
686 :
687 : optional& operator=(const optional& rhs) = default;
688 :
689 : optional& operator=(optional&& rhs) = default;
690 :
691 : template <class U = T>
692 : auto operator=(U&& v) -> typename std::enable_if<
693 : std::is_constructible<T, U>::value &&
694 : !std::is_same<typename std::decay<U>::type, optional<T>>::value &&
695 : (std::is_scalar<T>::value ||
696 : std::is_same<typename std::decay<U>::type, T>::value) &&
697 : std::is_assignable<T&, U>::value,
698 : optional&>::type {
699 : if (initialized()) {
700 : contained_val() = std::forward<U>(v);
701 : } else {
702 : initialize(std::forward<U>(v));
703 : }
704 : return *this;
705 : }
706 :
707 : template <class... Args>
708 : void emplace(Args&&... args) {
709 : clear();
710 : initialize(std::forward<Args>(args)...);
711 : }
712 :
713 : template <class U, class... Args>
714 : void emplace(std::initializer_list<U> il, Args&&... args) {
715 : clear();
716 : initialize<U, Args...>(il, std::forward<Args>(args)...);
717 : }
718 :
719 : // 20.5.4.4, Swap
720 : void swap(optional<T>& rhs) noexcept(
721 : std::is_nothrow_move_constructible<T>::value&& noexcept(
722 : std::swap(std::declval<T&>(), std::declval<T&>()))) {
723 : if (initialized() == true && rhs.initialized() == false) {
724 : rhs.initialize(std::move(**this));
725 : clear();
726 : } else if (initialized() == false && rhs.initialized() == true) {
727 : initialize(std::move(*rhs));
728 : rhs.clear();
729 : } else if (initialized() == true && rhs.initialized() == true) {
730 : using std::swap;
731 : swap(**this, *rhs);
732 : }
733 : }
734 :
735 : // 20.5.4.5, Observers
736 :
737 92670626 : explicit constexpr operator bool() const noexcept {
738 92670626 : return initialized();
739 : }
740 217022234 : constexpr bool has_value() const noexcept {
741 217022234 : return initialized();
742 : }
743 :
744 : TR2_OPTIONAL_HOST_CONSTEXPR T const* operator->() const {
745 : return TR2_OPTIONAL_ASSERTED_EXPRESSION(initialized(), dataptr());
746 : }
747 :
748 418776 : TR2_OPTIONAL_HOST_CONSTEXPR T* operator->() {
749 418776 : assert(initialized());
750 418776 : return dataptr();
751 : }
752 :
753 0 : TR2_OPTIONAL_HOST_CONSTEXPR T const& operator*() const& {
754 0 : return TR2_OPTIONAL_ASSERTED_EXPRESSION(initialized(), contained_val());
755 : }
756 :
757 197126756 : TR2_OPTIONAL_HOST_CONSTEXPR T& operator*() & {
758 197126756 : assert(initialized());
759 197126756 : return contained_val();
760 : }
761 :
762 : TR2_OPTIONAL_HOST_CONSTEXPR T&& operator*() && {
763 : assert(initialized());
764 : return constexpr_move(contained_val());
765 : }
766 :
767 : TR2_OPTIONAL_HOST_CONSTEXPR T const& value() const& {
768 : return initialized()
769 : ? contained_val()
770 : : (throw bad_optional_access("bad optional access"), contained_val());
771 : }
772 :
773 : TR2_OPTIONAL_HOST_CONSTEXPR T& value() & {
774 : return initialized()
775 : ? contained_val()
776 : : (throw bad_optional_access("bad optional access"), contained_val());
777 : }
778 :
779 1020 : TR2_OPTIONAL_HOST_CONSTEXPR T&& value() && {
780 1020 : if (!initialized())
781 0 : throw bad_optional_access("bad optional access");
782 1020 : return std::move(contained_val());
783 : }
784 :
785 : template <class V>
786 : constexpr T value_or(V&& v) const& {
787 : return *this ? **this : detail_::convert<T>(constexpr_forward<V>(v));
788 : }
789 :
790 : template <class V>
791 : constexpr T value_or(V&& v) && {
792 : return *this
793 : ? constexpr_move(const_cast<optional<T>&>(*this).contained_val())
794 : : detail_::convert<T>(constexpr_forward<V>(v));
795 : }
796 :
797 : // 20.6.3.6, modifiers
798 : void reset() noexcept {
799 : clear();
800 : }
801 : };
802 :
803 : template <class T, class F>
804 0 : constexpr T value_or_else(const optional<T>& v, F&& func) {
805 : static_assert(
806 : std::is_convertible<
807 : typename guts::infer_function_traits_t<F>::return_type,
808 : T>::value,
809 : "func parameters must be a callable that returns a type convertible to the value stored in the optional");
810 0 : return v.has_value() ? *v : detail_::convert<T>(std::forward<F>(func)());
811 : }
812 :
813 : template <class T, class F>
814 : constexpr T value_or_else(optional<T>&& v, F&& func) {
815 : static_assert(
816 : std::is_convertible<
817 : typename guts::infer_function_traits_t<F>::return_type,
818 : T>::value,
819 : "func parameters must be a callable that returns a type convertible to the value stored in the optional");
820 : return v.has_value() ? constexpr_move(std::move(v).contained_val())
821 : : detail_::convert<T>(std::forward<F>(func)());
822 : }
823 :
824 : // XXX: please refrain from using optional<T&>, since it is being against with
825 : // the optional standard in c++ 17, see the debate and the details here:
826 : // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3406#rationale.refs
827 : // if you need it, consider using optional<std::reference_wrapper<T>> or *
828 : // pointer
829 : //
830 : // we leave the implementation here in case we want to reconsider using it in
831 : // the future if it becomes a definitely necessary case.
832 : template <class T>
833 : class optional<T&> {
834 : // add this assert to prevent user from using optional reference as indicated
835 : // above
836 : static_assert(
837 : sizeof(T) == 0,
838 : "optional references is ill-formed, \
839 : consider use optional of a std::reference_wrapper of type T to \
840 : hold a reference if you really need to");
841 :
842 : static_assert(!std::is_same<T, nullopt_t>::value, "bad T");
843 : static_assert(!std::is_same<T, in_place_t>::value, "bad T");
844 : T* ref;
845 :
846 : public:
847 : // 20.5.5.1, construction/destruction
848 : constexpr optional() noexcept : ref(nullptr) {}
849 :
850 : constexpr optional(nullopt_t) noexcept : ref(nullptr) {}
851 :
852 : template <typename U = T>
853 : constexpr optional(U& u) noexcept : ref(detail_::static_addressof(u)) {}
854 :
855 : template <typename U = T>
856 : optional(U&&) = delete;
857 :
858 : constexpr optional(const optional& rhs) noexcept : ref(rhs.ref) {}
859 :
860 : explicit constexpr optional(in_place_t, T& v) noexcept
861 : : ref(detail_::static_addressof(v)) {}
862 :
863 : explicit optional(in_place_t, T&&) = delete;
864 :
865 : ~optional() = default;
866 :
867 : // 20.5.5.2, mutation
868 : optional& operator=(nullopt_t) noexcept {
869 : ref = nullptr;
870 : return *this;
871 : }
872 :
873 : // optional& operator=(const optional& rhs) noexcept {
874 : // ref = rhs.ref;
875 : // return *this;
876 : // }
877 :
878 : // optional& operator=(optional&& rhs) noexcept {
879 : // ref = rhs.ref;
880 : // return *this;
881 : // }
882 :
883 : template <typename U>
884 : auto operator=(U&& rhs) noexcept -> typename std::enable_if<
885 : std::is_same<typename std::decay<U>::type, optional<T&>>::value,
886 : optional&>::type {
887 : ref = rhs.ref;
888 : return *this;
889 : }
890 :
891 : template <typename U>
892 : auto operator=(U&& rhs) noexcept -> typename std::enable_if<
893 : !std::is_same<typename std::decay<U>::type, optional<T&>>::value,
894 : optional&>::type = delete;
895 :
896 : void emplace(T& v) noexcept {
897 : ref = detail_::static_addressof(v);
898 : }
899 :
900 : void emplace(T&&) = delete;
901 :
902 : void swap(optional<T&>& rhs) noexcept {
903 : std::swap(ref, rhs.ref);
904 : }
905 :
906 : // 20.5.5.3, observers
907 : TR2_OPTIONAL_HOST_CONSTEXPR T* operator->() const {
908 : return TR2_OPTIONAL_ASSERTED_EXPRESSION(ref, ref);
909 : }
910 :
911 : TR2_OPTIONAL_HOST_CONSTEXPR T& operator*() const {
912 : return TR2_OPTIONAL_ASSERTED_EXPRESSION(ref, *ref);
913 : }
914 :
915 : constexpr T& value() const {
916 : return ref ? *ref
917 : : (throw bad_optional_access("bad optional access"), *ref);
918 : }
919 :
920 : explicit constexpr operator bool() const noexcept {
921 : return ref != nullptr;
922 : }
923 :
924 : constexpr bool has_value() const noexcept {
925 : return ref != nullptr;
926 : }
927 :
928 : template <class V>
929 : constexpr typename std::decay<T>::type value_or(V&& v) const {
930 : return *this ? **this
931 : : detail_::convert<typename std::decay<T>::type>(
932 : constexpr_forward<V>(v));
933 : }
934 :
935 : // x.x.x.x, modifiers
936 : void reset() noexcept {
937 : ref = nullptr;
938 : }
939 : };
940 :
941 : template <class T>
942 : class optional<T&&> {
943 : static_assert(sizeof(T) == 0, "optional rvalue references disallowed");
944 : };
945 :
946 : // 20.5.8, Relational operators
947 : template <class T>
948 : constexpr bool operator==(const optional<T>& x, const optional<T>& y) {
949 : return bool(x) != bool(y) ? false : bool(x) == false ? true : *x == *y;
950 : }
951 :
952 : template <class T>
953 : constexpr bool operator!=(const optional<T>& x, const optional<T>& y) {
954 : return !(x == y);
955 : }
956 :
957 : template <class T>
958 : constexpr bool operator<(const optional<T>& x, const optional<T>& y) {
959 : return (!y) ? false : (!x) ? true : *x < *y;
960 : }
961 :
962 : template <class T>
963 : constexpr bool operator>(const optional<T>& x, const optional<T>& y) {
964 : return (y < x);
965 : }
966 :
967 : template <class T>
968 : constexpr bool operator<=(const optional<T>& x, const optional<T>& y) {
969 : return !(y < x);
970 : }
971 :
972 : template <class T>
973 : constexpr bool operator>=(const optional<T>& x, const optional<T>& y) {
974 : return !(x < y);
975 : }
976 :
977 : // 20.5.9, Comparison with nullopt
978 : template <class T>
979 401402 : constexpr bool operator==(const optional<T>& x, nullopt_t) noexcept {
980 401402 : return (!x);
981 : }
982 :
983 : template <class T>
984 : constexpr bool operator==(nullopt_t, const optional<T>& x) noexcept {
985 : return (!x);
986 : }
987 :
988 : template <class T>
989 : constexpr bool operator!=(const optional<T>& x, nullopt_t) noexcept {
990 : return bool(x);
991 : }
992 :
993 : template <class T>
994 : constexpr bool operator!=(nullopt_t, const optional<T>& x) noexcept {
995 : return bool(x);
996 : }
997 :
998 : template <class T>
999 : constexpr bool operator<(const optional<T>&, nullopt_t) noexcept {
1000 : return false;
1001 : }
1002 :
1003 : template <class T>
1004 : constexpr bool operator<(nullopt_t, const optional<T>& x) noexcept {
1005 : return bool(x);
1006 : }
1007 :
1008 : template <class T>
1009 : constexpr bool operator<=(const optional<T>& x, nullopt_t) noexcept {
1010 : return (!x);
1011 : }
1012 :
1013 : template <class T>
1014 : constexpr bool operator<=(nullopt_t, const optional<T>&) noexcept {
1015 : return true;
1016 : }
1017 :
1018 : template <class T>
1019 : constexpr bool operator>(const optional<T>& x, nullopt_t) noexcept {
1020 : return bool(x);
1021 : }
1022 :
1023 : template <class T>
1024 : constexpr bool operator>(nullopt_t, const optional<T>&) noexcept {
1025 : return false;
1026 : }
1027 :
1028 : template <class T>
1029 : constexpr bool operator>=(const optional<T>&, nullopt_t) noexcept {
1030 : return true;
1031 : }
1032 :
1033 : template <class T>
1034 : constexpr bool operator>=(nullopt_t, const optional<T>& x) noexcept {
1035 : return (!x);
1036 : }
1037 :
1038 : // 20.5.10, Comparison with T
1039 : template <class T, class U>
1040 : constexpr bool operator==(const optional<T>& x, const U& v) {
1041 : return bool(x) ? *x == v : false;
1042 : }
1043 :
1044 : template <class T, class U>
1045 : constexpr bool operator==(const U& v, const optional<T>& x) {
1046 : return bool(x) ? v == *x : false;
1047 : }
1048 :
1049 : template <class T, class U>
1050 : constexpr bool operator!=(const optional<T>& x, const U& v) {
1051 : return bool(x) ? *x != v : true;
1052 : }
1053 :
1054 : template <class T, class U>
1055 : constexpr bool operator!=(const U& v, const optional<T>& x) {
1056 : return bool(x) ? v != *x : true;
1057 : }
1058 :
1059 : template <class T, class U>
1060 : constexpr bool operator<(const optional<T>& x, const U& v) {
1061 : return bool(x) ? *x < v : true;
1062 : }
1063 :
1064 : template <class T, class U>
1065 : constexpr bool operator>(const U& v, const optional<T>& x) {
1066 : return bool(x) ? v > *x : true;
1067 : }
1068 :
1069 : template <class T, class U>
1070 : constexpr bool operator>(const optional<T>& x, const U& v) {
1071 : return bool(x) ? *x > v : false;
1072 : }
1073 :
1074 : template <class T, class U>
1075 : constexpr bool operator<(const U& v, const optional<T>& x) {
1076 : return bool(x) ? v < *x : false;
1077 : }
1078 :
1079 : template <class T, class U>
1080 : constexpr bool operator>=(const optional<T>& x, const U& v) {
1081 : return bool(x) ? *x >= v : false;
1082 : }
1083 :
1084 : template <class T, class U>
1085 : constexpr bool operator<=(const U& v, const optional<T>& x) {
1086 : return bool(x) ? v <= *x : false;
1087 : }
1088 :
1089 : template <class T, class U>
1090 : constexpr bool operator<=(const optional<T>& x, const U& v) {
1091 : return bool(x) ? *x <= v : true;
1092 : }
1093 :
1094 : template <class T, class U>
1095 : constexpr bool operator>=(const U& v, const optional<T>& x) {
1096 : return bool(x) ? v >= *x : true;
1097 : }
1098 :
1099 : // Comparison of optional<T&> with T
1100 : template <class T>
1101 : constexpr bool operator==(const optional<T&>& x, const T& v) {
1102 : return bool(x) ? *x == v : false;
1103 : }
1104 :
1105 : template <class T>
1106 : constexpr bool operator==(const T& v, const optional<T&>& x) {
1107 : return bool(x) ? v == *x : false;
1108 : }
1109 :
1110 : template <class T>
1111 : constexpr bool operator!=(const optional<T&>& x, const T& v) {
1112 : return bool(x) ? *x != v : true;
1113 : }
1114 :
1115 : template <class T>
1116 : constexpr bool operator!=(const T& v, const optional<T&>& x) {
1117 : return bool(x) ? v != *x : true;
1118 : }
1119 :
1120 : template <class T>
1121 : constexpr bool operator<(const optional<T&>& x, const T& v) {
1122 : return bool(x) ? *x < v : true;
1123 : }
1124 :
1125 : template <class T>
1126 : constexpr bool operator>(const T& v, const optional<T&>& x) {
1127 : return bool(x) ? v > *x : true;
1128 : }
1129 :
1130 : template <class T>
1131 : constexpr bool operator>(const optional<T&>& x, const T& v) {
1132 : return bool(x) ? *x > v : false;
1133 : }
1134 :
1135 : template <class T>
1136 : constexpr bool operator<(const T& v, const optional<T&>& x) {
1137 : return bool(x) ? v < *x : false;
1138 : }
1139 :
1140 : template <class T>
1141 : constexpr bool operator>=(const optional<T&>& x, const T& v) {
1142 : return bool(x) ? *x >= v : false;
1143 : }
1144 :
1145 : template <class T>
1146 : constexpr bool operator<=(const T& v, const optional<T&>& x) {
1147 : return bool(x) ? v <= *x : false;
1148 : }
1149 :
1150 : template <class T>
1151 : constexpr bool operator<=(const optional<T&>& x, const T& v) {
1152 : return bool(x) ? *x <= v : true;
1153 : }
1154 :
1155 : template <class T>
1156 : constexpr bool operator>=(const T& v, const optional<T&>& x) {
1157 : return bool(x) ? v >= *x : true;
1158 : }
1159 :
1160 : // Comparison of optional<T const&> with T
1161 : template <class T>
1162 : constexpr bool operator==(const optional<const T&>& x, const T& v) {
1163 : return bool(x) ? *x == v : false;
1164 : }
1165 :
1166 : template <class T>
1167 : constexpr bool operator==(const T& v, const optional<const T&>& x) {
1168 : return bool(x) ? v == *x : false;
1169 : }
1170 :
1171 : template <class T>
1172 : constexpr bool operator!=(const optional<const T&>& x, const T& v) {
1173 : return bool(x) ? *x != v : true;
1174 : }
1175 :
1176 : template <class T>
1177 : constexpr bool operator!=(const T& v, const optional<const T&>& x) {
1178 : return bool(x) ? v != *x : true;
1179 : }
1180 :
1181 : template <class T>
1182 : constexpr bool operator<(const optional<const T&>& x, const T& v) {
1183 : return bool(x) ? *x < v : true;
1184 : }
1185 :
1186 : template <class T>
1187 : constexpr bool operator>(const T& v, const optional<const T&>& x) {
1188 : return bool(x) ? v > *x : true;
1189 : }
1190 :
1191 : template <class T>
1192 : constexpr bool operator>(const optional<const T&>& x, const T& v) {
1193 : return bool(x) ? *x > v : false;
1194 : }
1195 :
1196 : template <class T>
1197 : constexpr bool operator<(const T& v, const optional<const T&>& x) {
1198 : return bool(x) ? v < *x : false;
1199 : }
1200 :
1201 : template <class T>
1202 : constexpr bool operator>=(const optional<const T&>& x, const T& v) {
1203 : return bool(x) ? *x >= v : false;
1204 : }
1205 :
1206 : template <class T>
1207 : constexpr bool operator<=(const T& v, const optional<const T&>& x) {
1208 : return bool(x) ? v <= *x : false;
1209 : }
1210 :
1211 : template <class T>
1212 : constexpr bool operator<=(const optional<const T&>& x, const T& v) {
1213 : return bool(x) ? *x <= v : true;
1214 : }
1215 :
1216 : template <class T>
1217 : constexpr bool operator>=(const T& v, const optional<const T&>& x) {
1218 : return bool(x) ? v >= *x : true;
1219 : }
1220 :
1221 : // 20.5.12, Specialized algorithms
1222 : template <class T>
1223 : void swap(optional<T>& x, optional<T>& y) noexcept(noexcept(x.swap(y))) {
1224 : x.swap(y);
1225 : }
1226 :
1227 : template <class T>
1228 418776 : constexpr optional<typename std::decay<T>::type> make_optional(T&& v) {
1229 418776 : return optional<typename std::decay<T>::type>(constexpr_forward<T>(v));
1230 : }
1231 :
1232 : template <class X>
1233 : constexpr optional<X&> make_optional(std::reference_wrapper<X> v) {
1234 : return optional<X&>(v.get());
1235 : }
1236 :
1237 : } // namespace c10
1238 :
1239 : namespace std {
1240 : template <typename T>
1241 : struct hash<c10::optional<T>> {
1242 : typedef c10::invoke_result_t<std::hash<T>, T> result_type;
1243 : typedef c10::optional<T> argument_type;
1244 :
1245 : constexpr result_type operator()(argument_type const& arg) const {
1246 : return arg ? std::hash<T>{}(*arg) : result_type{};
1247 : }
1248 : };
1249 :
1250 : template <typename T>
1251 : struct hash<c10::optional<T&>> {
1252 : typedef typename hash<T>::result_type result_type;
1253 : typedef c10::optional<T&> argument_type;
1254 :
1255 : constexpr result_type operator()(argument_type const& arg) const {
1256 : return arg ? std::hash<T>{}(*arg) : result_type{};
1257 : }
1258 : };
1259 : } // namespace std
1260 :
1261 : #undef TR2_OPTIONAL_REQUIRES
1262 : #undef TR2_OPTIONAL_ASSERTED_EXPRESSION
1263 : #undef TR2_OPTIONAL_HOST_CONSTEXPR
1264 :
1265 : C10_CLANG_DIAGNOSTIC_POP()
1266 :
1267 : #if defined(_MSC_VER) && !defined(__clang__)
1268 : #pragma warning(pop)
1269 : #endif
1270 :
1271 : #endif // C10_UTIL_OPTIONAL_H_
|