13 #if __cplusplus <= 199711L
16 #define CONSTEXPR constexpr
17 #endif // __cplusplus <= 199711L
38 const nullopt_t nullopt(0);
52 template <
class... Args>
54 : is_populated_(
true), value_(std::forward<Args>(args)...) {}
72 template <
class... Args>
73 void Init(Args&&... args) {
74 ::new (&value_) T(std::forward<Args>(args)...);
110 template <
class... Args>
119 if (other.is_populated_)
124 std::is_nothrow_move_constructible<T>::value) {
125 if (other.is_populated_)
126 Init(std::move(other.value_));
132 template <
typename T>
142 template <
class... Args>
144 : storage_(in_place, std::forward<Args>(args)...) {}
147 template <
typename U>
149 if (other.storage_.is_populated_)
150 storage_.Init(other.storage_.value_);
153 template <
typename U>
155 if (other.storage_.is_populated_)
156 storage_.Init(std::move(other.storage_.value_));
167 std::is_nothrow_move_assignable<T>::value&&
168 std::is_nothrow_move_constructible<T>::value) {
169 MoveAssign(std::move(other));
173 template <
typename U>
175 if (other.storage_.is_populated_)
176 InitOrAssign(other.storage_.value_);
181 template <
typename U>
183 if (other.storage_.is_populated_)
184 InitOrAssign(std::move(other.storage_.value_));
189 template <
typename U>
190 void InitOrAssign(U&& value) {
191 if (storage_.is_populated_)
192 storage_.value_ = std::forward<U>(value);
194 storage_.Init(std::forward<U>(value));
197 void FreeIfNeeded() {
198 if (!storage_.is_populated_)
200 storage_.value_.~T();
201 storage_.is_populated_ =
false;
206 template <
typename U>
216 template <
bool is_copy_constructible>
230 template <
bool is_move_constructible>
244 template <
bool is_copy_assignable>
258 template <
bool is_move_assignable>
273 template <
typename T,
typename U>
275 : std::integral_constant<
277 std::is_constructible<T, Optional<U>&>::value ||
278 std::is_constructible<T, const Optional<U>&>::value ||
279 std::is_constructible<T, Optional<U>&&>::value ||
280 std::is_constructible<T, const Optional<U>&&>::value ||
281 std::is_convertible<Optional<U>&, T>::value ||
282 std::is_convertible<const Optional<U>&, T>::value ||
283 std::is_convertible<Optional<U>&&, T>::value ||
284 std::is_convertible<const Optional<U>&&, T>::value> {};
286 template <
typename T,
typename U>
288 : std::integral_constant<
290 IsConvertibleFromOptional<T, U>::value ||
291 std::is_assignable<T&, Optional<U>&>::value ||
292 std::is_assignable<T&, const Optional<U>&>::value ||
293 std::is_assignable<T&, Optional<U>&&>::value ||
294 std::is_assignable<T&, const Optional<U>&&>::value> {};
298 namespace swappable_impl {
305 template <
typename T>
306 static auto Check(
int)
307 -> decltype(swap(std::declval<T>(), std::declval<T>()), std::true_type());
309 template <
typename T>
310 static std::false_type Check(...);
314 template <
typename T>
315 struct IsSwappable : decltype(swappable_impl::IsSwappableImpl::Check<T&>(0)) {};
325 #define OPTIONAL_DECLSPEC_EMPTY_BASES __declspec(empty_bases)
327 #define OPTIONAL_DECLSPEC_EMPTY_BASES
349 template <
typename T>
350 class OPTIONAL_DECLSPEC_EMPTY_BASES
Optional
355 std::is_copy_assignable<T>::value>,
357 std::is_move_assignable<T>::value> {
359 #undef OPTIONAL_DECLSPEC_EMPTY_BASES
361 typedef T value_type;
365 CONSTEXPR Optional(
const Optional& other) : internal::OptionalBase<T>(other) {}
367 CONSTEXPR Optional(nullopt_t) {}
373 template <
typename U>
374 Optional(
const Optional<U>& other) : internal::OptionalBase<T>(other) {}
378 template <
typename U>
379 Optional(Optional<U>&& other) : internal::OptionalBase<T>(std::move(other)) {}
381 template <
class... Args>
382 CONSTEXPR
explicit Optional(in_place_t, Args&&... args)
383 : internal::OptionalBase<T>(in_place, std::forward<Args>(args)...) {}
385 template <
class U,
class... Args>
386 CONSTEXPR
explicit Optional(in_place_t,
387 std::initializer_list<U> il,
389 : internal::OptionalBase<T>(in_place, il, std::forward<Args>(args)...) {}
393 template <
typename U = value_type>
394 CONSTEXPR Optional(U&& value)
395 : internal::OptionalBase<T>(in_place, std::forward<U>(value)) {}
400 Optional& operator=(
const Optional& other) {
401 if (&other ==
this) {
405 internal::OptionalBase<T>::operator=(other);
409 Optional& operator=(nullopt_t) {
415 template <
typename U>
416 Optional& operator=(U&& value) {
417 InitOrAssign(std::forward<U>(value));
422 template <
typename U>
423 Optional& operator=(
const Optional<U>& other) {
429 template <
typename U>
430 Optional& operator=(Optional<U>&& other) {
431 MoveAssign(std::move(other));
435 const T* operator->()
const {
436 return &storage_.value_;
439 const T& operator*()
const {
440 return storage_.value_;
444 return storage_.value_;
447 CONSTEXPR
explicit operator bool()
const {
return storage_.is_populated_; }
449 CONSTEXPR
bool has_value()
const {
return storage_.is_populated_; }
452 const T& value()
const {
453 return storage_.value_;
457 CONSTEXPR T value_or(U&& default_value)
const {
461 static_assert(std::is_convertible<U, T>::value,
462 "U must be convertible to T");
463 return storage_.is_populated_
465 : static_cast<T>(std::forward<U>(default_value));
468 const T& value() const & {
469 return storage_.value_;
472 const T&& value() const && {
473 return std::move(storage_.value_);
477 CONSTEXPR T value_or(U&& default_value)
const & {
481 static_assert(std::is_convertible<U, T>::value,
482 "U must be convertible to T");
483 return storage_.is_populated_
485 : static_cast<T>(std::forward<U>(default_value));
489 CONSTEXPR T value_or(U&& default_value)
const && {
493 static_assert(std::is_convertible<U, T>::value,
494 "U must be convertible to T");
495 return storage_.is_populated_
497 : static_cast<T>(std::forward<U>(default_value));
501 void swap(Optional& other) {
502 if (!storage_.is_populated_ && !other.storage_.is_populated_)
505 if (storage_.is_populated_ != other.storage_.is_populated_) {
506 if (storage_.is_populated_) {
507 other.storage_.Init(std::move(storage_.value_));
510 storage_.Init(std::move(other.storage_.value_));
511 other.FreeIfNeeded();
516 swap(**
this, *other);
519 void reset() { FreeIfNeeded(); }
521 template <
class... Args>
522 T& emplace(Args&&... args) {
524 storage_.Init(std::forward<Args>(args)...);
525 return storage_.value_;
528 template <
class U,
class... Args>
529 T& emplace(std::initializer_list<U> il, Args&&... args) {
531 storage_.Init(il, std::forward<Args>(args)...);
532 return storage_.value_;
538 using internal::OptionalBase<T>::CopyAssign;
539 using internal::OptionalBase<T>::FreeIfNeeded;
540 using internal::OptionalBase<T>::InitOrAssign;
541 using internal::OptionalBase<T>::MoveAssign;
542 using internal::OptionalBase<T>::storage_;
549 template <
class T,
class U>
550 bool operator==(
const Optional<T>& lhs,
const Optional<U>& rhs) {
551 if (lhs.has_value() != rhs.has_value())
553 if (!lhs.has_value())
558 template <
class T,
class U>
559 bool operator!=(
const Optional<T>& lhs,
const Optional<U>& rhs) {
560 if (lhs.has_value() != rhs.has_value())
562 if (!lhs.has_value())
567 template <
class T,
class U>
568 bool operator<(
const Optional<T>& lhs,
const Optional<U>& rhs) {
569 if (!rhs.has_value())
571 if (!lhs.has_value())
576 template <
class T,
class U>
577 bool operator<=(
const Optional<T>& lhs,
const Optional<U>& rhs) {
578 if (!lhs.has_value())
580 if (!rhs.has_value())
585 template <
class T,
class U>
586 bool operator>(
const Optional<T>& lhs,
const Optional<U>& rhs) {
587 if (!lhs.has_value())
589 if (!rhs.has_value())
594 template <
class T,
class U>
595 bool operator>=(
const Optional<T>& lhs,
const Optional<U>& rhs) {
596 if (!rhs.has_value())
598 if (!lhs.has_value())
604 CONSTEXPR
bool operator==(
const Optional<T>& opt, nullopt_t) {
609 CONSTEXPR
bool operator==(nullopt_t,
const Optional<T>& opt) {
614 CONSTEXPR
bool operator!=(
const Optional<T>& opt, nullopt_t) {
615 return opt.has_value();
619 CONSTEXPR
bool operator!=(nullopt_t,
const Optional<T>& opt) {
620 return opt.has_value();
624 CONSTEXPR
bool operator<(
const Optional<T>& opt, nullopt_t) {
629 CONSTEXPR
bool operator<(nullopt_t,
const Optional<T>& opt) {
630 return opt.has_value();
634 CONSTEXPR
bool operator<=(
const Optional<T>& opt, nullopt_t) {
639 CONSTEXPR
bool operator<=(nullopt_t,
const Optional<T>& opt) {
644 CONSTEXPR
bool operator>(
const Optional<T>& opt, nullopt_t) {
645 return opt.has_value();
649 CONSTEXPR
bool operator>(nullopt_t,
const Optional<T>& opt) {
654 CONSTEXPR
bool operator>=(
const Optional<T>& opt, nullopt_t) {
659 CONSTEXPR
bool operator>=(nullopt_t,
const Optional<T>& opt) {
663 template <
class T,
class U>
664 CONSTEXPR
bool operator==(
const Optional<T>& opt,
const U& value) {
665 return opt.has_value() ? *opt == value :
false;
668 template <
class T,
class U>
669 CONSTEXPR
bool operator==(
const U& value,
const Optional<T>& opt) {
670 return opt.has_value() ? value == *opt :
false;
673 template <
class T,
class U>
674 CONSTEXPR
bool operator!=(
const Optional<T>& opt,
const U& value) {
675 return opt.has_value() ? *opt != value :
true;
678 template <
class T,
class U>
679 CONSTEXPR
bool operator!=(
const U& value,
const Optional<T>& opt) {
680 return opt.has_value() ? value != *opt :
true;
683 template <
class T,
class U>
684 CONSTEXPR
bool operator<(
const Optional<T>& opt,
const U& value) {
685 return opt.has_value() ? *opt < value :
true;
688 template <
class T,
class U>
689 CONSTEXPR
bool operator<(
const U& value,
const Optional<T>& opt) {
690 return opt.has_value() ? value < *opt :
false;
693 template <
class T,
class U>
694 CONSTEXPR
bool operator<=(
const Optional<T>& opt,
const U& value) {
695 return opt.has_value() ? *opt <= value :
true;
698 template <
class T,
class U>
699 CONSTEXPR
bool operator<=(
const U& value,
const Optional<T>& opt) {
700 return opt.has_value() ? value <= *opt :
false;
703 template <
class T,
class U>
704 CONSTEXPR
bool operator>(
const Optional<T>& opt,
const U& value) {
705 return opt.has_value() ? *opt > value :
false;
708 template <
class T,
class U>
709 CONSTEXPR
bool operator>(
const U& value,
const Optional<T>& opt) {
710 return opt.has_value() ? value > *opt :
true;
713 template <
class T,
class U>
714 CONSTEXPR
bool operator>=(
const Optional<T>& opt,
const U& value) {
715 return opt.has_value() ? *opt >= value :
false;
718 template <
class T,
class U>
719 CONSTEXPR
bool operator>=(
const U& value,
const Optional<T>& opt) {
720 return opt.has_value() ? value >= *opt :
true;
723 template <
class T,
class... Args>
724 CONSTEXPR Optional<T> make_optional(Args&&... args) {
725 return Optional<T>(in_place, std::forward<Args>(args)...);
728 template <
class T,
class U,
class... Args>
729 CONSTEXPR Optional<T> make_optional(std::initializer_list<U> il,
731 return Optional<T>(in_place, il, std::forward<Args>(args)...);
739 void swap(Optional<T>& lhs, Optional<T>& rhs) {
748 struct hash<agora::Optional<T>> {
750 return opt == agora::nullopt ? 0 : std::hash<T>()(*opt);