diff options
author | NAKAMURA Takumi <geek4civic@gmail.com> | 2017-11-01 05:14:31 +0000 |
---|---|---|
committer | NAKAMURA Takumi <geek4civic@gmail.com> | 2017-11-01 05:14:31 +0000 |
commit | 89f198924daf253cca81e93376531d06e3cb9436 (patch) | |
tree | 9f105f5fed46ad2fd23e0ae2ada651e181efd3d9 /include | |
parent | b1a2e303f233fc22f4d4bc34f78d19c4c600e24d (diff) |
Revert rL317019, "[ADT] Split optional to only include copy mechanics and dtor for non-trivial types."
Seems g++-4.8 (eg. Ubuntu 14.04) doesn't like this.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@317077 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'include')
-rw-r--r-- | include/llvm/ADT/Optional.h | 166 |
1 files changed, 58 insertions, 108 deletions
diff --git a/include/llvm/ADT/Optional.h b/include/llvm/ADT/Optional.h index 3660a0a0e53..b782d9da17a 100644 --- a/include/llvm/ADT/Optional.h +++ b/include/llvm/ADT/Optional.h @@ -27,164 +27,114 @@ namespace llvm { -namespace optional_detail { -/// Storage for any type. -template <typename T, bool IsPodLike> struct OptionalStorage { +template<typename T> +class Optional { AlignedCharArrayUnion<T> storage; bool hasVal = false; - OptionalStorage() = default; +public: + using value_type = T; - OptionalStorage(const T &y) : hasVal(true) { new (storage.buffer) T(y); } - OptionalStorage(const OptionalStorage &O) : hasVal(O.hasVal) { + Optional(NoneType) {} + explicit Optional() {} + + Optional(const T &y) : hasVal(true) { + new (storage.buffer) T(y); + } + + Optional(const Optional &O) : hasVal(O.hasVal) { if (hasVal) - new (storage.buffer) T(*O.getPointer()); + new (storage.buffer) T(*O); } - OptionalStorage(T &&y) : hasVal(true) { + + Optional(T &&y) : hasVal(true) { new (storage.buffer) T(std::forward<T>(y)); } - OptionalStorage(OptionalStorage &&O) : hasVal(O.hasVal) { - if (O.hasVal) { - new (storage.buffer) T(std::move(*O.getPointer())); + + Optional(Optional<T> &&O) : hasVal(O) { + if (O) { + new (storage.buffer) T(std::move(*O)); O.reset(); } } - OptionalStorage &operator=(T &&y) { + ~Optional() { + reset(); + } + + Optional &operator=(T &&y) { if (hasVal) - *getPointer() = std::move(y); + **this = std::move(y); else { new (storage.buffer) T(std::move(y)); hasVal = true; } return *this; } - OptionalStorage &operator=(OptionalStorage &&O) { - if (!O.hasVal) + + Optional &operator=(Optional &&O) { + if (!O) reset(); else { - *this = std::move(*O.getPointer()); + *this = std::move(*O); O.reset(); } return *this; } + /// Create a new object by constructing it in place with the given arguments. + template<typename ...ArgTypes> + void emplace(ArgTypes &&...Args) { + reset(); + hasVal = true; + new (storage.buffer) T(std::forward<ArgTypes>(Args)...); + } + + static inline Optional create(const T* y) { + return y ? Optional(*y) : Optional(); + } + // FIXME: these assignments (& the equivalent const T&/const Optional& ctors) // could be made more efficient by passing by value, possibly unifying them // with the rvalue versions above - but this could place a different set of // 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) { + Optional &operator=(const T &y) { if (hasVal) - *getPointer() = y; + **this = y; else { new (storage.buffer) T(y); hasVal = true; } return *this; } - OptionalStorage &operator=(const OptionalStorage &O) { - if (!O.hasVal) + + Optional &operator=(const Optional &O) { + if (!O) reset(); else - *this = *O.getPointer(); + *this = *O; return *this; } - ~OptionalStorage() { reset(); } - void reset() { if (hasVal) { - (*getPointer()).~T(); + (**this).~T(); hasVal = false; } } - T *getPointer() { - assert(hasVal); - return reinterpret_cast<T *>(storage.buffer); - } - const T *getPointer() const { - assert(hasVal); - return reinterpret_cast<const T *>(storage.buffer); - } -}; - -/// Storage for trivially copyable types only. -template <typename T> struct OptionalStorage<T, true> { - AlignedCharArrayUnion<T> storage; - bool hasVal = false; - - OptionalStorage() = default; - - OptionalStorage(const T &y) : hasVal(true) { new (storage.buffer) T(y); } - OptionalStorage &operator=(const T &y) { - new (storage.buffer) T(y); - hasVal = true; - return *this; - } - - void reset() { hasVal = false; } -}; -} // namespace optional_detail - -template <typename T> class Optional { - optional_detail::OptionalStorage<T, isPodLike<T>::value> Storage; - -public: - using value_type = T; - - constexpr Optional() {} - constexpr Optional(NoneType) {} - - Optional(const T &y) : Storage(y) {} - Optional(const Optional &O) = default; - - Optional(T &&y) : Storage(std::forward<T>(y)) {} - Optional(Optional &&O) = default; - - Optional &operator=(T &&y) { - Storage = std::move(y); - return *this; - } - Optional &operator=(Optional &&O) = default; - - /// Create a new object by constructing it in place with the given arguments. - template <typename... ArgTypes> void emplace(ArgTypes &&... Args) { - reset(); - Storage.hasVal = true; - new (getPointer()) T(std::forward<ArgTypes>(Args)...); - } - - static inline Optional create(const T *y) { - return y ? Optional(*y) : Optional(); - } - - Optional &operator=(const T &y) { - Storage = y; - return *this; - } - Optional &operator=(const Optional &O) = default; - - void reset() { Storage.reset(); } - - const T *getPointer() const { - assert(Storage.hasVal); - return reinterpret_cast<const T *>(Storage.storage.buffer); - } - T *getPointer() { - assert(Storage.hasVal); - return reinterpret_cast<T *>(Storage.storage.buffer); - } - const T &getValue() const LLVM_LVALUE_FUNCTION { return *getPointer(); } - T &getValue() LLVM_LVALUE_FUNCTION { return *getPointer(); } + const T* getPointer() const { assert(hasVal); return reinterpret_cast<const T*>(storage.buffer); } + T* getPointer() { assert(hasVal); return reinterpret_cast<T*>(storage.buffer); } + const T& getValue() const LLVM_LVALUE_FUNCTION { assert(hasVal); return *getPointer(); } + T& getValue() LLVM_LVALUE_FUNCTION { assert(hasVal); return *getPointer(); } - explicit operator bool() const { return Storage.hasVal; } - bool hasValue() const { return Storage.hasVal; } + explicit operator bool() const { return hasVal; } + bool hasValue() const { return hasVal; } const T* operator->() const { return getPointer(); } T* operator->() { return getPointer(); } - const T &operator*() const LLVM_LVALUE_FUNCTION { return *getPointer(); } - T &operator*() LLVM_LVALUE_FUNCTION { return *getPointer(); } + const T& operator*() const LLVM_LVALUE_FUNCTION { assert(hasVal); return *getPointer(); } + T& operator*() LLVM_LVALUE_FUNCTION { assert(hasVal); return *getPointer(); } template <typename U> constexpr T getValueOr(U &&value) const LLVM_LVALUE_FUNCTION { @@ -192,8 +142,8 @@ public: } #if LLVM_HAS_RVALUE_REFERENCE_THIS - T &&getValue() && { return std::move(*getPointer()); } - T &&operator*() && { return std::move(*getPointer()); } + T&& getValue() && { assert(hasVal); return std::move(*getPointer()); } + T&& operator*() && { assert(hasVal); return std::move(*getPointer()); } template <typename U> T getValueOr(U &&value) && { |