From 83d23097a6d958e7f69732ff6ed31d4efbacc2dd Mon Sep 17 00:00:00 2001 From: Serge Guelton Date: Sun, 17 Feb 2019 23:01:41 +0000 Subject: [PATCH] Revert [NFC] Better encapsulation of llvm::Optional Storage git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@354240 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/llvm/ADT/Optional.h | 158 ++++++++++++++++++++++---------------------- 1 file changed, 80 insertions(+), 78 deletions(-) diff --git a/include/llvm/ADT/Optional.h b/include/llvm/ADT/Optional.h index b4093215bcf..25a3185064f 100644 --- a/include/llvm/ADT/Optional.h +++ b/include/llvm/ADT/Optional.h @@ -29,89 +29,83 @@ namespace llvm { class raw_ostream; namespace optional_detail { - -struct in_place_t {}; - /// Storage for any type. -template ::value> -class OptionalStorage { - union { - char empty; - T value; - }; - bool hasVal; +template ::value> struct OptionalStorage { + AlignedCharArrayUnion storage; + bool hasVal = false; -public: - ~OptionalStorage() { reset(); } + OptionalStorage() = default; - OptionalStorage() noexcept : empty(), hasVal(false) {} + 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()); + } + OptionalStorage(T &&y) : hasVal(true) { + new (storage.buffer) T(std::forward(y)); + } + OptionalStorage(OptionalStorage &&O) : hasVal(O.hasVal) { + if (O.hasVal) { + new (storage.buffer) T(std::move(*O.getPointer())); + } + } - OptionalStorage(OptionalStorage const &other) : OptionalStorage() { - if (other.hasValue()) { - emplace(other.value); + OptionalStorage &operator=(T &&y) { + if (hasVal) + *getPointer() = std::move(y); + else { + new (storage.buffer) T(std::move(y)); + hasVal = true; } + return *this; } - OptionalStorage(OptionalStorage &&other) : OptionalStorage() { - if (other.hasValue()) { - emplace(std::move(other.value)); + OptionalStorage &operator=(OptionalStorage &&O) { + if (!O.hasVal) + reset(); + else { + *this = std::move(*O.getPointer()); } + return *this; } - template - explicit OptionalStorage(in_place_t, Args &&... args) - : value(std::forward(args)...), hasVal(true) {} + // 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) { + if (hasVal) + *getPointer() = y; + else { + new (storage.buffer) T(y); + hasVal = true; + } + return *this; + } + OptionalStorage &operator=(const OptionalStorage &O) { + if (!O.hasVal) + reset(); + else + *this = *O.getPointer(); + return *this; + } + + ~OptionalStorage() { reset(); } - void reset() noexcept { + void reset() { if (hasVal) { - value.~T(); + (*getPointer()).~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 { + T *getPointer() { assert(hasVal); - return value; + return reinterpret_cast(storage.buffer); } -#if LLVM_HAS_RVALUE_REFERENCE_THIS - T &&getValue() && noexcept { + const T *getPointer() const { assert(hasVal); - return std::move(value); - } -#endif - - template void emplace(Args &&... args) { - reset(); - ::new ((void *)std::addressof(value)) T(std::forward(args)...); - hasVal = true; - } - - OptionalStorage &operator=(T const &y) { - return (*this) = OptionalStorage(in_place_t{}, y); - } - OptionalStorage &operator=(T &&y) { - return (*this) = OptionalStorage(in_place_t{}, std::move(y)); - } - - OptionalStorage &operator=(OptionalStorage const &other) { - if (other.hasValue()) - emplace(other.getValue()); - else - reset(); - return *this; - } - - OptionalStorage &operator=(OptionalStorage &&other) { - if (other.hasValue()) - emplace(std::move(other.getValue())); - else - reset(); - return *this; + return reinterpret_cast(storage.buffer); } }; @@ -126,10 +120,10 @@ public: constexpr Optional() {} constexpr Optional(NoneType) {} - Optional(const T &y) : Storage(optional_detail::in_place_t{}, y) {} + Optional(const T &y) : Storage(y) {} Optional(const Optional &O) = default; - Optional(T &&y) : Storage(optional_detail::in_place_t{}, std::move(y)) {} + Optional(T &&y) : Storage(std::forward(y)) {} Optional(Optional &&O) = default; Optional &operator=(T &&y) { @@ -140,7 +134,9 @@ public: /// Create a new object by constructing it in place with the given arguments. template void emplace(ArgTypes &&... Args) { - Storage.emplace(std::forward(Args)...); + reset(); + Storage.hasVal = true; + new (getPointer()) T(std::forward(Args)...); } static inline Optional create(const T *y) { @@ -155,17 +151,23 @@ public: void reset() { Storage.reset(); } - const T *getPointer() const { return &Storage.getValue(); } - T *getPointer() { return &Storage.getValue(); } - const T &getValue() const LLVM_LVALUE_FUNCTION { return Storage.getValue(); } - T &getValue() LLVM_LVALUE_FUNCTION { return Storage.getValue(); } + const T *getPointer() const { + assert(Storage.hasVal); + return reinterpret_cast(Storage.storage.buffer); + } + T *getPointer() { + assert(Storage.hasVal); + return reinterpret_cast(Storage.storage.buffer); + } + const T &getValue() const LLVM_LVALUE_FUNCTION { return *getPointer(); } + T &getValue() LLVM_LVALUE_FUNCTION { return *getPointer(); } - explicit operator bool() const { return hasValue(); } - bool hasValue() const { return Storage.hasValue(); } + explicit operator bool() const { return Storage.hasVal; } + bool hasValue() const { return Storage.hasVal; } const T *operator->() const { return getPointer(); } T *operator->() { return getPointer(); } - const T &operator*() const LLVM_LVALUE_FUNCTION { return getValue(); } - T &operator*() LLVM_LVALUE_FUNCTION { return getValue(); } + const T &operator*() const LLVM_LVALUE_FUNCTION { return *getPointer(); } + T &operator*() LLVM_LVALUE_FUNCTION { return *getPointer(); } template constexpr T getValueOr(U &&value) const LLVM_LVALUE_FUNCTION { @@ -173,8 +175,8 @@ public: } #if LLVM_HAS_RVALUE_REFERENCE_THIS - T &&getValue() && { return std::move(Storage.getValue()); } - T &&operator*() && { return std::move(Storage.getValue()); } + T &&getValue() && { return std::move(*getPointer()); } + T &&operator*() && { return std::move(*getPointer()); } template T getValueOr(U &&value) && { -- 2.11.0