| Index: base/optional.h
|
| diff --git a/base/optional.h b/base/optional.h
|
| index 5ae427f8a9cc2d79b65665fb6f103b15b2230295..988767cfe32cf4916bf5aa3272ebd271f1dc73c1 100644
|
| --- a/base/optional.h
|
| +++ b/base/optional.h
|
| @@ -9,6 +9,7 @@
|
|
|
| #include "base/logging.h"
|
| #include "base/memory/aligned_memory.h"
|
| +#include "base/template_util.h"
|
|
|
| namespace base {
|
|
|
| @@ -30,6 +31,36 @@ constexpr in_place_t in_place = {};
|
| // http://en.cppreference.com/w/cpp/utility/optional/nullopt
|
| constexpr nullopt_t nullopt(0);
|
|
|
| +namespace internal {
|
| +
|
| +template <typename T, bool = base::is_trivially_destructible<T>::value>
|
| +struct OptionalStorage {
|
| + // When T is not trivially destructible we must call its
|
| + // destructor before deallocating its memory.
|
| + ~OptionalStorage() {
|
| + if (!is_null_)
|
| + buffer_.template data_as<T>()->~T();
|
| + }
|
| +
|
| + bool is_null_ = true;
|
| + base::AlignedMemory<sizeof(T), ALIGNOF(T)> buffer_;
|
| +};
|
| +
|
| +template <typename T>
|
| +struct OptionalStorage<T, true> {
|
| + // When T is trivially destructible (i.e. its destructor does nothing)
|
| + // there is no need to call it.
|
| + // Since |base::AlignedMemory| is just an array its destructor
|
| + // is trivial. Explicitly defaulting the destructor means it's not
|
| + // user-provided. All of this together make this destructor trivial.
|
| + ~OptionalStorage() = default;
|
| +
|
| + bool is_null_ = true;
|
| + base::AlignedMemory<sizeof(T), ALIGNOF(T)> buffer_;
|
| +};
|
| +
|
| +} // namespace internal
|
| +
|
| // base::Optional is a Chromium version of the C++17 optional class:
|
| // std::optional documentation:
|
| // http://en.cppreference.com/w/cpp/utility/optional
|
| @@ -46,16 +77,18 @@ constexpr nullopt_t nullopt(0);
|
| template <typename T>
|
| class Optional {
|
| public:
|
| + using value_type = T;
|
| +
|
| constexpr Optional() = default;
|
| Optional(base::nullopt_t) : Optional() {}
|
|
|
| Optional(const Optional& other) {
|
| - if (!other.is_null_)
|
| + if (!other.storage_.is_null_)
|
| Init(other.value());
|
| }
|
|
|
| Optional(Optional&& other) {
|
| - if (!other.is_null_)
|
| + if (!other.storage_.is_null_)
|
| Init(std::move(other.value()));
|
| }
|
|
|
| @@ -68,10 +101,7 @@ class Optional {
|
| emplace(std::forward<Args>(args)...);
|
| }
|
|
|
| - ~Optional() {
|
| - // TODO(mlamouri): use is_trivially_destructible<T>::value when possible.
|
| - FreeIfNeeded();
|
| - }
|
| + ~Optional() = default;
|
|
|
| Optional& operator=(base::nullopt_t) {
|
| FreeIfNeeded();
|
| @@ -79,7 +109,7 @@ class Optional {
|
| }
|
|
|
| Optional& operator=(const Optional& other) {
|
| - if (other.is_null_) {
|
| + if (other.storage_.is_null_) {
|
| FreeIfNeeded();
|
| return *this;
|
| }
|
| @@ -89,7 +119,7 @@ class Optional {
|
| }
|
|
|
| Optional& operator=(Optional&& other) {
|
| - if (other.is_null_) {
|
| + if (other.storage_.is_null_) {
|
| FreeIfNeeded();
|
| return *this;
|
| }
|
| @@ -108,14 +138,14 @@ class Optional {
|
|
|
| // TODO(mlamouri): can't use 'constexpr' with DCHECK.
|
| const T* operator->() const {
|
| - DCHECK(!is_null_);
|
| + DCHECK(!storage_.is_null_);
|
| return &value();
|
| }
|
|
|
| // TODO(mlamouri): using 'constexpr' here breaks compiler that assume it was
|
| // meant to be 'constexpr const'.
|
| T* operator->() {
|
| - DCHECK(!is_null_);
|
| + DCHECK(!storage_.is_null_);
|
| return &value();
|
| }
|
|
|
| @@ -131,32 +161,32 @@ class Optional {
|
| // meant to be 'constexpr const'.
|
| T&& operator*() && { return std::move(value()); }
|
|
|
| - constexpr explicit operator bool() const { return !is_null_; }
|
| + constexpr explicit operator bool() const { return !storage_.is_null_; }
|
|
|
| // TODO(mlamouri): using 'constexpr' here breaks compiler that assume it was
|
| // meant to be 'constexpr const'.
|
| T& value() & {
|
| - DCHECK(!is_null_);
|
| - return *buffer_.template data_as<T>();
|
| + DCHECK(!storage_.is_null_);
|
| + return *storage_.buffer_.template data_as<T>();
|
| }
|
|
|
| // TODO(mlamouri): can't use 'constexpr' with DCHECK.
|
| const T& value() const& {
|
| - DCHECK(!is_null_);
|
| - return *buffer_.template data_as<T>();
|
| + DCHECK(!storage_.is_null_);
|
| + return *storage_.buffer_.template data_as<T>();
|
| }
|
|
|
| // TODO(mlamouri): using 'constexpr' here breaks compiler that assume it was
|
| // meant to be 'constexpr const'.
|
| T&& value() && {
|
| - DCHECK(!is_null_);
|
| - return std::move(*buffer_.template data_as<T>());
|
| + DCHECK(!storage_.is_null_);
|
| + return std::move(*storage_.buffer_.template data_as<T>());
|
| }
|
|
|
| // TODO(mlamouri): can't use 'constexpr' with DCHECK.
|
| const T&& value() const&& {
|
| - DCHECK(!is_null_);
|
| - return std::move(*buffer_.template data_as<T>());
|
| + DCHECK(!storage_.is_null_);
|
| + return std::move(*storage_.buffer_.template data_as<T>());
|
| }
|
|
|
| template <class U>
|
| @@ -166,7 +196,8 @@ class Optional {
|
| // "T must be copy constructible");
|
| static_assert(std::is_convertible<U, T>::value,
|
| "U must be convertible to T");
|
| - return is_null_ ? static_cast<T>(std::forward<U>(default_value)) : value();
|
| + return storage_.is_null_ ? static_cast<T>(std::forward<U>(default_value))
|
| + : value();
|
| }
|
|
|
| template <class U>
|
| @@ -176,26 +207,26 @@ class Optional {
|
| // "T must be move constructible");
|
| static_assert(std::is_convertible<U, T>::value,
|
| "U must be convertible to T");
|
| - return is_null_ ? static_cast<T>(std::forward<U>(default_value))
|
| - : std::move(value());
|
| + return storage_.is_null_ ? static_cast<T>(std::forward<U>(default_value))
|
| + : std::move(value());
|
| }
|
|
|
| void swap(Optional& other) {
|
| - if (is_null_ && other.is_null_)
|
| + if (storage_.is_null_ && other.storage_.is_null_)
|
| return;
|
|
|
| - if (is_null_ != other.is_null_) {
|
| - if (is_null_) {
|
| - Init(std::move(*other.buffer_.template data_as<T>()));
|
| + if (storage_.is_null_ != other.storage_.is_null_) {
|
| + if (storage_.is_null_) {
|
| + Init(std::move(*other.storage_.buffer_.template data_as<T>()));
|
| other.FreeIfNeeded();
|
| } else {
|
| - other.Init(std::move(*buffer_.template data_as<T>()));
|
| + other.Init(std::move(*storage_.buffer_.template data_as<T>()));
|
| FreeIfNeeded();
|
| }
|
| return;
|
| }
|
|
|
| - DCHECK(!is_null_ && !other.is_null_);
|
| + DCHECK(!storage_.is_null_ && !other.storage_.is_null_);
|
| using std::swap;
|
| swap(**this, *other);
|
| }
|
| @@ -208,47 +239,46 @@ class Optional {
|
|
|
| private:
|
| void Init(const T& value) {
|
| - DCHECK(is_null_);
|
| - new (buffer_.template data_as<T>()) T(value);
|
| - is_null_ = false;
|
| + DCHECK(storage_.is_null_);
|
| + new (storage_.buffer_.template data_as<T>()) T(value);
|
| + storage_.is_null_ = false;
|
| }
|
|
|
| void Init(T&& value) {
|
| - DCHECK(is_null_);
|
| - new (buffer_.template data_as<T>()) T(std::move(value));
|
| - is_null_ = false;
|
| + DCHECK(storage_.is_null_);
|
| + new (storage_.buffer_.template data_as<T>()) T(std::move(value));
|
| + storage_.is_null_ = false;
|
| }
|
|
|
| template <class... Args>
|
| void Init(Args&&... args) {
|
| - DCHECK(is_null_);
|
| - new (buffer_.template data_as<T>()) T(std::forward<Args>(args)...);
|
| - is_null_ = false;
|
| + DCHECK(storage_.is_null_);
|
| + new (storage_.buffer_.template data_as<T>()) T(std::forward<Args>(args)...);
|
| + storage_.is_null_ = false;
|
| }
|
|
|
| void InitOrAssign(const T& value) {
|
| - if (is_null_)
|
| + if (storage_.is_null_)
|
| Init(value);
|
| else
|
| - *buffer_.template data_as<T>() = value;
|
| + *storage_.buffer_.template data_as<T>() = value;
|
| }
|
|
|
| void InitOrAssign(T&& value) {
|
| - if (is_null_)
|
| + if (storage_.is_null_)
|
| Init(std::move(value));
|
| else
|
| - *buffer_.template data_as<T>() = std::move(value);
|
| + *storage_.buffer_.template data_as<T>() = std::move(value);
|
| }
|
|
|
| void FreeIfNeeded() {
|
| - if (is_null_)
|
| + if (storage_.is_null_)
|
| return;
|
| - buffer_.template data_as<T>()->~T();
|
| - is_null_ = true;
|
| + storage_.buffer_.template data_as<T>()->~T();
|
| + storage_.is_null_ = true;
|
| }
|
|
|
| - bool is_null_ = true;
|
| - base::AlignedMemory<sizeof(T), ALIGNOF(T)> buffer_;
|
| + internal::OptionalStorage<T> storage_;
|
| };
|
|
|
| template <class T>
|
|
|