9 #ifndef V8_BASE_OPTIONAL_H_ 10 #define V8_BASE_OPTIONAL_H_ 12 #include <type_traits> 15 #include "src/base/logging.h" 36 constexpr nullopt_t nullopt(0);
44 template <typename T, bool = std::is_trivially_destructible<T>::value>
50 template <
class... Args>
52 : is_populated_(
true), value_(std::forward<Args>(args)...) {}
66 if (is_populated_) value_.~T();
69 template <
class... Args>
70 void Init(Args&&... args) {
71 DCHECK(!is_populated_);
72 ::new (&value_)
T(std::forward<Args>(args)...);
76 bool is_populated_ =
false;
92 template <
class... Args>
94 : is_populated_(
true), value_(std::forward<Args>(args)...) {}
110 template <
class... Args>
111 void Init(Args&&... args) {
112 DCHECK(!is_populated_);
113 ::new (&value_) T(std::forward<Args>(args)...);
114 is_populated_ =
true;
117 bool is_populated_ =
false;
134 #if defined(__GNUC__) && __GNUC__ < 5 138 #define TRIVIALLY_COPY_CONSTRUCTIBLE(T) false 139 #define TRIVIALLY_MOVE_CONSTRUCTIBLE(T) false 141 #define TRIVIALLY_COPY_CONSTRUCTIBLE(T) \ 142 std::is_trivially_copy_constructible<T>::value 143 #define TRIVIALLY_MOVE_CONSTRUCTIBLE(T) \ 144 std::is_trivially_move_constructible<T>::value 146 template <
typename T,
bool = TRIVIALLY_COPY_CONSTRUCTIBLE(
T),
147 bool = TRIVIALLY_MOVE_CONSTRUCTIBLE(
T)>
148 #undef TRIVIALLY_COPY_CONSTRUCTIBLE 167 if (other.is_populated_) Init(other.value_);
171 std::is_nothrow_move_constructible<T>::value) {
172 if (other.is_populated_) Init(std::move(other.value_));
176 template <
typename T>
189 std::is_nothrow_move_constructible<T>::value) {
190 if (other.is_populated_) Init(std::move(other.value_));
194 template <
typename T>
207 if (other.is_populated_) Init(other.value_);
211 template <
typename T>
223 template <
typename T>
233 template <
class... Args>
235 : storage_(in_place, std::forward<Args>(args)...) {}
238 template <
typename U>
240 if (other.storage_.is_populated_) storage_.Init(other.storage_.value_);
243 template <
typename U>
245 if (other.storage_.is_populated_)
246 storage_.Init(std::move(other.storage_.value_));
257 std::is_nothrow_move_assignable<T>::value&&
258 std::is_nothrow_move_constructible<T>::value) {
259 MoveAssign(std::move(other));
263 template <
typename U>
265 if (other.storage_.is_populated_)
266 InitOrAssign(other.storage_.value_);
271 template <
typename U>
273 if (other.storage_.is_populated_)
274 InitOrAssign(std::move(other.storage_.value_));
279 template <
typename U>
280 void InitOrAssign(U&& value) {
281 if (storage_.is_populated_)
282 storage_.value_ = std::forward<U>(value);
284 storage_.Init(std::forward<U>(value));
287 void FreeIfNeeded() {
288 if (!storage_.is_populated_)
return;
289 storage_.value_.~T();
290 storage_.is_populated_ =
false;
295 template <
typename U>
305 template <
bool is_copy_constructible>
317 template <
bool is_move_constructible>
329 template <
bool is_copy_assignable>
341 template <
bool is_move_assignable>
354 template <
typename T,
typename U>
356 : std::integral_constant<
357 bool, std::is_constructible<T, Optional<U>&>::value ||
358 std::is_constructible<T, const Optional<U>&>::value ||
359 std::is_constructible<T, Optional<U>&&>::value ||
360 std::is_constructible<T, const Optional<U>&&>::value ||
361 std::is_convertible<Optional<U>&, T>::value ||
362 std::is_convertible<const Optional<U>&, T>::value ||
363 std::is_convertible<Optional<U>&&, T>::value ||
364 std::is_convertible<const Optional<U>&&, T>::value> {};
366 template <
typename T,
typename U>
368 : std::integral_constant<
369 bool, IsConvertibleFromOptional<T, U>::value ||
370 std::is_assignable<T&, Optional<U>&>::value ||
371 std::is_assignable<T&, const Optional<U>&>::value ||
372 std::is_assignable<T&, Optional<U>&&>::value ||
373 std::is_assignable<T&, const Optional<U>&&>::value> {};
377 namespace swappable_impl {
384 template <
typename T>
385 static auto Check(
int i)
386 -> decltype(swap(std::declval<T>(), std::declval<T>()), std::true_type());
388 template <
typename T>
389 static std::false_type Check(...);
393 template <
typename T>
394 struct IsSwappable : decltype(swappable_impl::IsSwappableImpl::Check<T&>(0)) {};
397 template <
typename T>
399 typename std::remove_cv<typename std::remove_reference<T>::type>
::type;
409 #define OPTIONAL_DECLSPEC_EMPTY_BASES __declspec(empty_bases) 411 #define OPTIONAL_DECLSPEC_EMPTY_BASES 433 template <
typename T>
434 class OPTIONAL_DECLSPEC_EMPTY_BASES
Optional 439 std::is_copy_assignable<T>::value>,
441 std::is_move_assignable<T>::value> {
443 #undef OPTIONAL_DECLSPEC_EMPTY_BASES 444 using value_type = T;
457 template <
typename U,
458 typename std::enable_if<
459 std::is_constructible<T, const U&>::value &&
460 !internal::IsConvertibleFromOptional<T, U>::value &&
461 std::is_convertible<const U&, T>::value,
463 Optional(
const Optional<U>& other) : internal::OptionalBase<
T>(other) {}
465 template <
typename U,
466 typename std::enable_if<
467 std::is_constructible<T, const U&>::value &&
468 !internal::IsConvertibleFromOptional<T, U>::value &&
469 !std::is_convertible<const U&, T>::value,
471 explicit Optional(
const Optional<U>& other)
472 : internal::OptionalBase<T>(other) {}
476 template <
typename U,
477 typename std::enable_if<
478 std::is_constructible<T, U&&>::value &&
479 !internal::IsConvertibleFromOptional<T, U>::value &&
480 std::is_convertible<U&&, T>::value,
482 Optional(Optional<U>&& other) : internal::OptionalBase<T>(
std::move(other)) {}
484 template <
typename U,
485 typename std::enable_if<
486 std::is_constructible<T, U&&>::value &&
487 !internal::IsConvertibleFromOptional<T, U>::value &&
488 !std::is_convertible<U&&, T>::value,
490 explicit Optional(Optional<U>&& other)
491 : internal::OptionalBase<T>(
std::move(other)) {}
493 template <
class... Args>
494 constexpr
explicit Optional(in_place_t, Args&&... args)
495 : internal::OptionalBase<T>(in_place,
std::forward<Args>(args)...) {}
497 template <
class U,
class... Args,
498 class =
typename std::enable_if<std::is_constructible<
499 value_type, std::initializer_list<U>&, Args...>::value>::type>
500 constexpr
explicit Optional(in_place_t, std::initializer_list<U> il,
502 : internal::OptionalBase<T>(in_place, il,
std::forward<Args>(args)...) {}
507 typename U = value_type,
508 typename std::enable_if<
509 std::is_constructible<T, U&&>::value &&
510 !std::is_same<internal::RemoveCvRefT<U>, in_place_t>::value &&
511 !std::is_same<internal::RemoveCvRefT<U>, Optional<T>>::value &&
512 std::is_convertible<U&&, T>::value,
514 constexpr Optional(U&& value)
515 : internal::OptionalBase<T>(in_place,
std::forward<U>(value)) {}
518 typename U = value_type,
519 typename std::enable_if<
520 std::is_constructible<T, U&&>::value &&
521 !std::is_same<internal::RemoveCvRefT<U>, in_place_t>::value &&
522 !std::is_same<internal::RemoveCvRefT<U>, Optional<T>>::value &&
523 !std::is_convertible<U&&, T>::value,
525 constexpr
explicit Optional(U&& value)
526 : internal::OptionalBase<T>(in_place,
std::forward<U>(value)) {}
528 ~Optional() =
default;
531 Optional& operator=(
const Optional& other) =
default;
532 Optional& operator=(Optional&& other) =
default;
534 Optional& operator=(nullopt_t) {
540 template <
typename U>
541 typename std::enable_if<
542 !std::is_same<internal::RemoveCvRefT<U>, Optional<T>>::value &&
543 std::is_constructible<T, U>::value &&
544 std::is_assignable<T&, U>::value &&
545 (!std::is_scalar<T>::value ||
546 !std::is_same<typename std::decay<U>::type, T>::value),
548 operator=(U&& value) {
549 InitOrAssign(std::forward<U>(value));
554 template <
typename U>
555 typename std::enable_if<!internal::IsAssignableFromOptional<T, U>::value &&
556 std::is_constructible<T, const U&>::value &&
557 std::is_assignable<T&, const U&>::value,
559 operator=(
const Optional<U>& other) {
565 template <
typename U>
566 typename std::enable_if<!internal::IsAssignableFromOptional<T, U>::value &&
567 std::is_constructible<T, U>::value &&
568 std::is_assignable<T&, U>::value,
570 operator=(Optional<U>&& other) {
571 MoveAssign(std::move(other));
575 const T* operator->()
const {
576 DCHECK(storage_.is_populated_);
577 return &storage_.value_;
581 DCHECK(storage_.is_populated_);
582 return &storage_.value_;
585 const T& operator*() const & {
586 DCHECK(storage_.is_populated_);
587 return storage_.value_;
591 DCHECK(storage_.is_populated_);
592 return storage_.value_;
595 const T&& operator*() const && {
596 DCHECK(storage_.is_populated_);
597 return std::move(storage_.value_);
601 DCHECK(storage_.is_populated_);
602 return std::move(storage_.value_);
605 constexpr
explicit operator bool()
const {
return storage_.is_populated_; }
607 constexpr
bool has_value()
const {
return storage_.is_populated_; }
610 CHECK(storage_.is_populated_);
611 return storage_.value_;
614 const T& value() const & {
615 CHECK(storage_.is_populated_);
616 return storage_.value_;
620 CHECK(storage_.is_populated_);
621 return std::move(storage_.value_);
624 const T&& value() const && {
625 CHECK(storage_.is_populated_);
626 return std::move(storage_.value_);
630 constexpr T value_or(U&& default_value)
const & {
634 static_assert(std::is_convertible<U, T>::value,
635 "U must be convertible to T");
636 return storage_.is_populated_
638 :
static_cast<T
>(std::forward<U>(default_value));
642 T value_or(U&& default_value) && {
646 static_assert(std::is_convertible<U, T>::value,
647 "U must be convertible to T");
648 return storage_.is_populated_
649 ? std::move(storage_.value_)
650 : static_cast<T>(
std::forward<U>(default_value));
653 void swap(Optional& other) {
654 if (!storage_.is_populated_ && !other.storage_.is_populated_)
return;
656 if (storage_.is_populated_ != other.storage_.is_populated_) {
657 if (storage_.is_populated_) {
658 other.storage_.Init(std::move(storage_.value_));
661 storage_.Init(std::move(other.storage_.value_));
662 other.FreeIfNeeded();
667 DCHECK(storage_.is_populated_ && other.storage_.is_populated_);
669 swap(**
this, *other);
672 void reset() { FreeIfNeeded(); }
674 template <
class... Args>
675 T& emplace(Args&&... args) {
677 storage_.Init(std::forward<Args>(args)...);
678 return storage_.value_;
681 template <
class U,
class... Args>
682 typename std::enable_if<
683 std::is_constructible<T, std::initializer_list<U>&, Args&&...>::value,
685 emplace(std::initializer_list<U> il, Args&&... args) {
687 storage_.Init(il, std::forward<Args>(args)...);
688 return storage_.value_;
694 using internal::OptionalBase<T>::CopyAssign;
695 using internal::OptionalBase<T>::FreeIfNeeded;
696 using internal::OptionalBase<T>::InitOrAssign;
697 using internal::OptionalBase<T>::MoveAssign;
698 using internal::OptionalBase<T>::storage_;
705 template <
class T,
class U>
706 bool operator==(
const Optional<T>& lhs,
const Optional<U>& rhs) {
707 if (lhs.has_value() != rhs.has_value())
return false;
708 if (!lhs.has_value())
return true;
712 template <
class T,
class U>
713 bool operator!=(
const Optional<T>& lhs,
const Optional<U>& rhs) {
714 if (lhs.has_value() != rhs.has_value())
return true;
715 if (!lhs.has_value())
return false;
719 template <
class T,
class U>
720 bool operator<(const Optional<T>& lhs,
const Optional<U>& rhs) {
721 if (!rhs.has_value())
return false;
722 if (!lhs.has_value())
return true;
726 template <
class T,
class U>
727 bool operator<=(const Optional<T>& lhs,
const Optional<U>& rhs) {
728 if (!lhs.has_value())
return true;
729 if (!rhs.has_value())
return false;
733 template <
class T,
class U>
734 bool operator>(
const Optional<T>& lhs,
const Optional<U>& rhs) {
735 if (!lhs.has_value())
return false;
736 if (!rhs.has_value())
return true;
740 template <
class T,
class U>
741 bool operator>=(
const Optional<T>& lhs,
const Optional<U>& rhs) {
742 if (!rhs.has_value())
return true;
743 if (!lhs.has_value())
return false;
748 constexpr
bool operator==(
const Optional<T>& opt, nullopt_t) {
753 constexpr
bool operator==(nullopt_t,
const Optional<T>& opt) {
758 constexpr
bool operator!=(
const Optional<T>& opt, nullopt_t) {
759 return opt.has_value();
763 constexpr
bool operator!=(nullopt_t,
const Optional<T>& opt) {
764 return opt.has_value();
768 constexpr
bool operator<(const Optional<T>& opt, nullopt_t) {
773 constexpr
bool operator<(nullopt_t, const Optional<T>& opt) {
774 return opt.has_value();
778 constexpr
bool operator<=(const Optional<T>& opt, nullopt_t) {
783 constexpr
bool operator<=(nullopt_t, const Optional<T>& opt) {
788 constexpr
bool operator>(
const Optional<T>& opt, nullopt_t) {
789 return opt.has_value();
793 constexpr
bool operator>(nullopt_t,
const Optional<T>& opt) {
798 constexpr
bool operator>=(
const Optional<T>& opt, nullopt_t) {
803 constexpr
bool operator>=(nullopt_t,
const Optional<T>& opt) {
807 template <
class T,
class U>
808 constexpr
bool operator==(
const Optional<T>& opt,
const U& value) {
809 return opt.has_value() ? *opt == value :
false;
812 template <
class T,
class U>
813 constexpr
bool operator==(
const U& value,
const Optional<T>& opt) {
814 return opt.has_value() ? value == *opt :
false;
817 template <
class T,
class U>
818 constexpr
bool operator!=(
const Optional<T>& opt,
const U& value) {
819 return opt.has_value() ? *opt != value :
true;
822 template <
class T,
class U>
823 constexpr
bool operator!=(
const U& value,
const Optional<T>& opt) {
824 return opt.has_value() ? value != *opt :
true;
827 template <
class T,
class U>
828 constexpr
bool operator<(const Optional<T>& opt,
const U& value) {
829 return opt.has_value() ? *opt < value :
true;
832 template <
class T,
class U>
833 constexpr
bool operator<(const U& value, const Optional<T>& opt) {
834 return opt.has_value() ? value < *opt :
false;
837 template <
class T,
class U>
838 constexpr
bool operator<=(const Optional<T>& opt,
const U& value) {
839 return opt.has_value() ? *opt <= value :
true;
842 template <
class T,
class U>
843 constexpr
bool operator<=(const U& value, const Optional<T>& opt) {
844 return opt.has_value() ? value <= *opt :
false;
847 template <
class T,
class U>
848 constexpr
bool operator>(
const Optional<T>& opt,
const U& value) {
849 return opt.has_value() ? *opt > value :
false;
852 template <
class T,
class U>
853 constexpr
bool operator>(
const U& value,
const Optional<T>& opt) {
854 return opt.has_value() ? value > *opt :
true;
857 template <
class T,
class U>
858 constexpr
bool operator>=(
const Optional<T>& opt,
const U& value) {
859 return opt.has_value() ? *opt >= value :
false;
862 template <
class T,
class U>
863 constexpr
bool operator>=(
const U& value,
const Optional<T>& opt) {
864 return opt.has_value() ? value >= *opt :
true;
868 constexpr Optional<typename std::decay<T>::type> make_optional(T&& value) {
869 return Optional<typename std::decay<T>::type>(std::forward<T>(value));
872 template <
class T,
class... Args>
873 constexpr Optional<T> make_optional(Args&&... args) {
874 return Optional<T>(in_place, std::forward<Args>(args)...);
877 template <
class T,
class U,
class... Args>
878 constexpr Optional<T> make_optional(std::initializer_list<U> il,
880 return Optional<T>(in_place, il, std::forward<Args>(args)...);
888 typename std::enable_if<std::is_move_constructible<T>::value &&
889 internal::IsSwappable<T>::value>::type
890 swap(Optional<T>& lhs, Optional<T>& rhs) {
897 #endif // V8_BASE_OPTIONAL_H_