diff options
Diffstat (limited to 'llvm')
-rw-r--r-- | llvm/include/llvm/ADT/Optional.h | 93 | ||||
-rw-r--r-- | llvm/unittests/ADT/OptionalTest.cpp | 20 |
2 files changed, 85 insertions, 28 deletions
diff --git a/llvm/include/llvm/ADT/Optional.h b/llvm/include/llvm/ADT/Optional.h index 25a3185064f..d7b9d5cddc2 100644 --- a/llvm/include/llvm/ADT/Optional.h +++ b/llvm/include/llvm/ADT/Optional.h @@ -29,33 +29,61 @@ namespace llvm { class raw_ostream; namespace optional_detail { -/// Storage for any type. -template <typename T, bool = is_trivially_copyable<T>::value> struct OptionalStorage { +template <typename T> struct OptionalStorageBase { AlignedCharArrayUnion<T> storage; bool hasVal = false; - OptionalStorage() = default; + OptionalStorageBase() = default; + OptionalStorageBase(const T &y) : hasVal(true) { new (storage.buffer) T(y); } + OptionalStorageBase(T &&y) : hasVal(true) { + new (storage.buffer) T(std::move(y)); + } - OptionalStorage(const T &y) : hasVal(true) { new (storage.buffer) T(y); } - OptionalStorage(const OptionalStorage &O) : hasVal(O.hasVal) { - if (hasVal) - new (storage.buffer) T(*O.getPointer()); + T *getPointer() { + assert(hasVal); + return reinterpret_cast<T *>(storage.buffer); + } + const T *getPointer() const { + assert(hasVal); + return reinterpret_cast<const T *>(storage.buffer); + } + OptionalStorageBase &operator=(T &&y) { + hasVal = true; + new (this->storage.buffer) T(std::move(y)); + return *this; } - OptionalStorage(T &&y) : hasVal(true) { - new (storage.buffer) T(std::forward<T>(y)); + OptionalStorageBase &operator=(const T &y) { + hasVal = true; + new (this->storage.buffer) T(y); + return *this; } - OptionalStorage(OptionalStorage &&O) : hasVal(O.hasVal) { + void reset() { this->hasVal = false; } +}; + +/// Storage for any type. +template <typename T, bool = is_trivially_copyable<T>::value> +struct OptionalStorage : OptionalStorageBase<T> { + OptionalStorage() = default; + + OptionalStorage(const T &y) : OptionalStorageBase<T>(y) {} + OptionalStorage(const OptionalStorage &O) : OptionalStorageBase<T>() { + this->hasVal = O.hasVal; + if (this->hasVal) + new (this->storage.buffer) T(*O.getPointer()); + } + OptionalStorage(T &&y) : OptionalStorageBase<T>(std::move(y)) {} + OptionalStorage(OptionalStorage &&O) : OptionalStorageBase<T>() { + this->hasVal = O.hasVal; if (O.hasVal) { - new (storage.buffer) T(std::move(*O.getPointer())); + new (this->storage.buffer) T(std::move(*O.getPointer())); } } OptionalStorage &operator=(T &&y) { - if (hasVal) - *getPointer() = std::move(y); + if (this->hasVal) + *this->getPointer() = std::move(y); else { - new (storage.buffer) T(std::move(y)); - hasVal = true; + OptionalStorageBase<T>::operator=(std::move(y)); } return *this; } @@ -74,11 +102,10 @@ template <typename T, bool = is_trivially_copyable<T>::value> struct OptionalSto // requirements (notably: the existence of a default ctor) when implemented // in that way. Careful SFINAE to avoid such pitfalls would be required. OptionalStorage &operator=(const T &y) { - if (hasVal) - *getPointer() = y; + if (this->hasVal) + *this->getPointer() = y; else { - new (storage.buffer) T(y); - hasVal = true; + OptionalStorageBase<T>::operator=(y); } return *this; } @@ -93,20 +120,30 @@ template <typename T, bool = is_trivially_copyable<T>::value> struct OptionalSto ~OptionalStorage() { reset(); } void reset() { - if (hasVal) { - (*getPointer()).~T(); - hasVal = false; + if (this->hasVal) { + (*this->getPointer()).~T(); } + OptionalStorageBase<T>::reset(); } +}; - T *getPointer() { - assert(hasVal); - return reinterpret_cast<T *>(storage.buffer); +template <typename T> struct OptionalStorage<T, true> : OptionalStorageBase<T> { + OptionalStorage() = default; + OptionalStorage(const T &y) : OptionalStorageBase<T>(y) {} + OptionalStorage(const OptionalStorage &O) = default; + OptionalStorage(T &&y) : OptionalStorageBase<T>(std::move(y)) {} + OptionalStorage(OptionalStorage &&O) = default; + OptionalStorage &operator=(T &&y) { + OptionalStorageBase<T>::operator=(std::move(y)); + return *this; } - const T *getPointer() const { - assert(hasVal); - return reinterpret_cast<const T *>(storage.buffer); + OptionalStorage &operator=(OptionalStorage &&O) = default; + OptionalStorage &operator=(const T &y) { + OptionalStorageBase<T>::operator=(y); + return *this; } + OptionalStorage &operator=(const OptionalStorage &O) = default; + ~OptionalStorage() = default; }; } // namespace optional_detail diff --git a/llvm/unittests/ADT/OptionalTest.cpp b/llvm/unittests/ADT/OptionalTest.cpp index 98adaccca96..c39b6727cd5 100644 --- a/llvm/unittests/ADT/OptionalTest.cpp +++ b/llvm/unittests/ADT/OptionalTest.cpp @@ -18,6 +18,12 @@ using namespace llvm; namespace { +static_assert(llvm::is_trivially_copyable<Optional<int>>::value, + "trivially copyable"); + +static_assert(llvm::is_trivially_copyable<Optional<std::array<int, 3>>>::value, + "trivially copyable"); + struct NonDefaultConstructible { static unsigned CopyConstructions; static unsigned Destructions; @@ -45,6 +51,10 @@ unsigned NonDefaultConstructible::CopyConstructions = 0; unsigned NonDefaultConstructible::Destructions = 0; unsigned NonDefaultConstructible::CopyAssignments = 0; +static_assert( + !llvm::is_trivially_copyable<Optional<NonDefaultConstructible>>::value, + "not trivially copyable"); + // Test fixture class OptionalTest : public testing::Test { }; @@ -203,6 +213,10 @@ struct MultiArgConstructor { }; unsigned MultiArgConstructor::Destructions = 0; +static_assert( + !llvm::is_trivially_copyable<Optional<MultiArgConstructor>>::value, + "not trivially copyable"); + TEST_F(OptionalTest, Emplace) { MultiArgConstructor::ResetCounts(); Optional<MultiArgConstructor> A; @@ -250,6 +264,9 @@ unsigned MoveOnly::MoveConstructions = 0; unsigned MoveOnly::Destructions = 0; unsigned MoveOnly::MoveAssignments = 0; +static_assert(!llvm::is_trivially_copyable<Optional<MoveOnly>>::value, + "not trivially copyable"); + TEST_F(OptionalTest, MoveOnlyNull) { MoveOnly::ResetCounts(); Optional<MoveOnly> O; @@ -351,6 +368,9 @@ private: unsigned Immovable::Constructions = 0; unsigned Immovable::Destructions = 0; +static_assert(!llvm::is_trivially_copyable<Optional<Immovable>>::value, + "not trivially copyable"); + TEST_F(OptionalTest, ImmovableEmplace) { Optional<Immovable> A; Immovable::ResetCounts(); |