[llvm] r354240 - Revert [NFC] Better encapsulation of llvm::Optional Storage
Serge Guelton via llvm-commits
llvm-commits at lists.llvm.org
Sun Feb 17 15:01:42 PST 2019
Author: serge_sans_paille
Date: Sun Feb 17 15:01:41 2019
New Revision: 354240
URL: http://llvm.org/viewvc/llvm-project?rev=354240&view=rev
Log:
Revert [NFC] Better encapsulation of llvm::Optional Storage
Modified:
llvm/trunk/include/llvm/ADT/Optional.h
Modified: llvm/trunk/include/llvm/ADT/Optional.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/ADT/Optional.h?rev=354240&r1=354239&r2=354240&view=diff
==============================================================================
--- llvm/trunk/include/llvm/ADT/Optional.h (original)
+++ llvm/trunk/include/llvm/ADT/Optional.h Sun Feb 17 15:01:41 2019
@@ -29,89 +29,83 @@ namespace llvm {
class raw_ostream;
namespace optional_detail {
-
-struct in_place_t {};
-
/// Storage for any type.
-template <typename T, bool = is_trivially_copyable<T>::value>
-class OptionalStorage {
- union {
- char empty;
- T value;
- };
- bool hasVal;
-
-public:
- ~OptionalStorage() { reset(); }
-
- OptionalStorage() noexcept : empty(), hasVal(false) {}
+template <typename T, bool = is_trivially_copyable<T>::value> struct OptionalStorage {
+ AlignedCharArrayUnion<T> storage;
+ bool hasVal = false;
+
+ OptionalStorage() = default;
+
+ 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(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 &operator=(OptionalStorage &&O) {
+ if (!O.hasVal)
+ reset();
+ else {
+ *this = std::move(*O.getPointer());
}
+ return *this;
}
- OptionalStorage(OptionalStorage &&other) : OptionalStorage() {
- if (other.hasValue()) {
- emplace(std::move(other.value));
+
+ // 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;
}
- template <class... Args>
- explicit OptionalStorage(in_place_t, Args &&... args)
- : value(std::forward<Args>(args)...), hasVal(true) {}
+ ~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 {
+ T *getPointer() {
assert(hasVal);
- return value;
+ return reinterpret_cast<T *>(storage.buffer);
}
- T const &getValue() const LLVM_LVALUE_FUNCTION noexcept {
+ const T *getPointer() const {
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) {
- 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<const T *>(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<T>(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 <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) {
@@ -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<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(); }
- 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 <typename U>
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 <typename U>
T getValueOr(U &&value) && {
More information about the llvm-commits
mailing list