Revert [NFC] Better encapsulation of llvm::Optional Storage

llvm-svn: 354240
This commit is contained in:
Serge Guelton 2019-02-17 23:01:41 +00:00
parent f54981c567
commit 649e3d01c6
1 changed files with 86 additions and 84 deletions

View File

@ -29,89 +29,83 @@ namespace llvm {
class raw_ostream; class raw_ostream;
namespace optional_detail { namespace optional_detail {
struct in_place_t {};
/// Storage for any type. /// Storage for any type.
template <typename T, bool = is_trivially_copyable<T>::value> template <typename T, bool = is_trivially_copyable<T>::value> struct OptionalStorage {
class OptionalStorage { AlignedCharArrayUnion<T> storage;
union { bool hasVal = false;
char empty;
T value; OptionalStorage() = default;
};
bool hasVal; 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<T>(y));
}
OptionalStorage(OptionalStorage &&O) : hasVal(O.hasVal) {
if (O.hasVal) {
new (storage.buffer) T(std::move(*O.getPointer()));
}
}
OptionalStorage &operator=(T &&y) {
if (hasVal)
*getPointer() = std::move(y);
else {
new (storage.buffer) T(std::move(y));
hasVal = true;
}
return *this;
}
OptionalStorage &operator=(OptionalStorage &&O) {
if (!O.hasVal)
reset();
else {
*this = std::move(*O.getPointer());
}
return *this;
}
// 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;
}
public:
~OptionalStorage() { reset(); } ~OptionalStorage() { reset(); }
OptionalStorage() noexcept : empty(), hasVal(false) {} void reset() {
OptionalStorage(OptionalStorage const &other) : OptionalStorage() {
if (other.hasValue()) {
emplace(other.value);
}
}
OptionalStorage(OptionalStorage &&other) : OptionalStorage() {
if (other.hasValue()) {
emplace(std::move(other.value));
}
}
template <class... Args>
explicit OptionalStorage(in_place_t, Args &&... args)
: value(std::forward<Args>(args)...), hasVal(true) {}
void reset() noexcept {
if (hasVal) { if (hasVal) {
value.~T(); (*getPointer()).~T();
hasVal = false; hasVal = false;
} }
} }
bool hasValue() const noexcept { return hasVal; } T *getPointer() {
T &getValue() LLVM_LVALUE_FUNCTION noexcept {
assert(hasVal); assert(hasVal);
return value; return reinterpret_cast<T *>(storage.buffer);
} }
T const &getValue() const LLVM_LVALUE_FUNCTION noexcept { const T *getPointer() const {
assert(hasVal); assert(hasVal);
return value; return reinterpret_cast<const T *>(storage.buffer);
}
#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) {
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;
} }
}; };
@ -126,10 +120,10 @@ public:
constexpr Optional() {} constexpr Optional() {}
constexpr Optional(NoneType) {} 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(const Optional &O) = default;
Optional(T &&y) : Storage(optional_detail::in_place_t{}, std::move(y)) {} Optional(T &&y) : Storage(std::forward<T>(y)) {}
Optional(Optional &&O) = default; Optional(Optional &&O) = default;
Optional &operator=(T &&y) { Optional &operator=(T &&y) {
@ -140,7 +134,9 @@ public:
/// Create a new object by constructing it in place with the given arguments. /// Create a new object by constructing it in place with the given arguments.
template <typename... ArgTypes> void emplace(ArgTypes &&... Args) { template <typename... ArgTypes> void emplace(ArgTypes &&... Args) {
Storage.emplace(std::forward<ArgTypes>(Args)...); reset();
Storage.hasVal = true;
new (getPointer()) T(std::forward<ArgTypes>(Args)...);
} }
static inline Optional create(const T *y) { static inline Optional create(const T *y) {
@ -155,17 +151,23 @@ public:
void reset() { Storage.reset(); } void reset() { Storage.reset(); }
const T *getPointer() const { return &Storage.getValue(); } const T *getPointer() const {
T *getPointer() { return &Storage.getValue(); } assert(Storage.hasVal);
const T &getValue() const LLVM_LVALUE_FUNCTION { return Storage.getValue(); } return reinterpret_cast<const T *>(Storage.storage.buffer);
T &getValue() LLVM_LVALUE_FUNCTION { return Storage.getValue(); } }
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(); }
explicit operator bool() const { return hasValue(); } explicit operator bool() const { return Storage.hasVal; }
bool hasValue() const { return Storage.hasValue(); } bool hasValue() const { return Storage.hasVal; }
const T *operator->() const { return getPointer(); } const T *operator->() const { return getPointer(); }
T *operator->() { return getPointer(); } T *operator->() { return getPointer(); }
const T &operator*() const LLVM_LVALUE_FUNCTION { return getValue(); } const T &operator*() const LLVM_LVALUE_FUNCTION { return *getPointer(); }
T &operator*() LLVM_LVALUE_FUNCTION { return getValue(); } T &operator*() LLVM_LVALUE_FUNCTION { return *getPointer(); }
template <typename U> template <typename U>
constexpr T getValueOr(U &&value) const LLVM_LVALUE_FUNCTION { constexpr T getValueOr(U &&value) const LLVM_LVALUE_FUNCTION {
@ -173,8 +175,8 @@ public:
} }
#if LLVM_HAS_RVALUE_REFERENCE_THIS #if LLVM_HAS_RVALUE_REFERENCE_THIS
T &&getValue() && { return std::move(Storage.getValue()); } T &&getValue() && { return std::move(*getPointer()); }
T &&operator*() && { return std::move(Storage.getValue()); } T &&operator*() && { return std::move(*getPointer()); }
template <typename U> template <typename U>
T getValueOr(U &&value) && { T getValueOr(U &&value) && {