diff options
Diffstat (limited to 'llvm')
-rw-r--r-- | llvm/include/llvm/ADT/Optional.h | 72 | ||||
-rw-r--r-- | llvm/unittests/ADT/OptionalTest.cpp | 21 |
2 files changed, 93 insertions, 0 deletions
diff --git a/llvm/include/llvm/ADT/Optional.h b/llvm/include/llvm/ADT/Optional.h index f135bb8f36a..1eb84c735d2 100644 --- a/llvm/include/llvm/ADT/Optional.h +++ b/llvm/include/llvm/ADT/Optional.h @@ -139,6 +139,78 @@ public: } }; +template <typename T> class OptionalStorage<T, true> { + union { + char empty; + T value; + }; + bool hasVal = false; + +public: + ~OptionalStorage() = default; + + OptionalStorage() noexcept : empty{} {} + + OptionalStorage(OptionalStorage const &other) = default; + OptionalStorage(OptionalStorage &&other) = default; + + OptionalStorage &operator=(OptionalStorage const &other) = default; + OptionalStorage &operator=(OptionalStorage &&other) = default; + + template <class... Args> + explicit OptionalStorage(in_place_t, Args &&... args) + : value(std::forward<Args>(args)...), hasVal(true) {} + + void reset() noexcept { + if (hasVal) { + value.~T(); + hasVal = false; + } + } + + bool hasValue() const noexcept { return hasVal; } + + T &getValue() LLVM_LVALUE_FUNCTION noexcept { + assert(hasVal); + return value; + } + T const &getValue() const LLVM_LVALUE_FUNCTION noexcept { + assert(hasVal); + return value; + } +#if LLVM_HAS_RVALUE_REFERENCE_THIS + T &&getValue() && noexcept { + assert(hasVal); + return std::move(value); + } +#endif + + template <class... Args> void emplace(Args &&... args) { + reset(); + ::new ((void *)std::addressof(value)) T(std::forward<Args>(args)...); + hasVal = true; + } + + OptionalStorage &operator=(T const &y) { + if (hasValue()) { + value = y; + } else { + ::new ((void *)std::addressof(value)) T(y); + hasVal = true; + } + return *this; + } + OptionalStorage &operator=(T &&y) { + if (hasValue()) { + value = std::move(y); + } else { + ::new ((void *)std::addressof(value)) T(std::move(y)); + hasVal = true; + } + return *this; + } +}; + } // namespace optional_detail template <typename T> class Optional { diff --git a/llvm/unittests/ADT/OptionalTest.cpp b/llvm/unittests/ADT/OptionalTest.cpp index 98adaccca96..1f26c101183 100644 --- a/llvm/unittests/ADT/OptionalTest.cpp +++ b/llvm/unittests/ADT/OptionalTest.cpp @@ -14,8 +14,15 @@ #include <array> + using namespace llvm; +static_assert(is_trivially_copyable<Optional<int>>::value, + "trivially copyable"); + +static_assert(is_trivially_copyable<Optional<std::array<int, 3>>>::value, + "trivially copyable"); + namespace { struct NonDefaultConstructible { @@ -45,6 +52,10 @@ unsigned NonDefaultConstructible::CopyConstructions = 0; unsigned NonDefaultConstructible::Destructions = 0; unsigned NonDefaultConstructible::CopyAssignments = 0; +static_assert( + !is_trivially_copyable<Optional<NonDefaultConstructible>>::value, + "not trivially copyable"); + // Test fixture class OptionalTest : public testing::Test { }; @@ -203,6 +214,10 @@ struct MultiArgConstructor { }; unsigned MultiArgConstructor::Destructions = 0; +static_assert( + !is_trivially_copyable<Optional<MultiArgConstructor>>::value, + "not trivially copyable"); + TEST_F(OptionalTest, Emplace) { MultiArgConstructor::ResetCounts(); Optional<MultiArgConstructor> A; @@ -250,6 +265,9 @@ unsigned MoveOnly::MoveConstructions = 0; unsigned MoveOnly::Destructions = 0; unsigned MoveOnly::MoveAssignments = 0; +static_assert(!is_trivially_copyable<Optional<MoveOnly>>::value, + "not trivially copyable"); + TEST_F(OptionalTest, MoveOnlyNull) { MoveOnly::ResetCounts(); Optional<MoveOnly> O; @@ -351,6 +369,9 @@ private: unsigned Immovable::Constructions = 0; unsigned Immovable::Destructions = 0; +static_assert(!is_trivially_copyable<Optional<Immovable>>::value, + "not trivially copyable"); + TEST_F(OptionalTest, ImmovableEmplace) { Optional<Immovable> A; Immovable::ResetCounts(); |