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();  | 

