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