]> granicus.if.org Git - llvm/commitdiff
OptionalStorage implementation for trivial type, take III
authorSerge Guelton <sguelton@redhat.com>
Fri, 15 Feb 2019 15:17:29 +0000 (15:17 +0000)
committerSerge Guelton <sguelton@redhat.com>
Fri, 15 Feb 2019 15:17:29 +0000 (15:17 +0000)
This is another attempt at implementating optional storage
for trivially copyable type, using an union instead of a
raw buffer to hold the actual storage. This make it possible
to get rid of the reinterpret_cast, and hopefully to fix the UB
of the previous attempts.

This validates fine on my laptop for gcc 8.2 and gcc 4.8, I'll
revert if it breaks the validation.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@354137 91177308-0d34-0410-b5e6-96231b3b80d8

include/llvm/ADT/Optional.h

index 25a3185064f413225f0c63db53ea87114657dd75..55bbfc5f100a7f4f2d54ce687ab90f21362fa2d2 100644 (file)
@@ -109,6 +109,54 @@ template <typename T, bool = is_trivially_copyable<T>::value> struct OptionalSto
   }
 };
 
+template <typename T> struct OptionalStorage<T, true> {
+  struct empty_type {};
+  union {
+    empty_type empty;
+    T value;
+  };
+  bool hasVal = false;
+
+  OptionalStorage() : empty{} {}
+
+  OptionalStorage(const T &y) : hasVal(true) {
+    new ((void*)std::addressof(value)) T(y);
+  }
+  OptionalStorage(const OptionalStorage &O) = default;
+  OptionalStorage(T &&y) : hasVal(true) {
+    new ((void*)std::addressof(value)) T(std::move(y));
+  }
+
+  OptionalStorage(OptionalStorage &&O) = default;
+
+  OptionalStorage &operator=(T &&y) {
+    hasVal = true;
+    new ((void*)std::addressof(value)) T(std::move(y));
+    return *this;
+  }
+  OptionalStorage &operator=(OptionalStorage &&O) = default;
+
+  OptionalStorage &operator=(const T &y) {
+    hasVal = true;
+    new ((void*)std::addressof(value)) T(y);
+    return *this;
+  }
+  OptionalStorage &operator=(const OptionalStorage &O) = default;
+
+  ~OptionalStorage() = default;
+
+  T *getPointer() {
+    assert(hasVal);
+    return &value;
+  }
+  const T *getPointer() const {
+    assert(hasVal);
+    return &value;
+  }
+
+  void reset() { hasVal = false; }
+};
+
 } // namespace optional_detail
 
 template <typename T> class Optional {
@@ -153,11 +201,11 @@ public:
 
   const T *getPointer() const {
     assert(Storage.hasVal);
-    return reinterpret_cast<const T *>(Storage.storage.buffer);
+    return Storage.getPointer();
   }
   T *getPointer() {
     assert(Storage.hasVal);
-    return reinterpret_cast<T *>(Storage.storage.buffer);
+    return Storage.getPointer();
   }
   const T &getValue() const LLVM_LVALUE_FUNCTION { return *getPointer(); }
   T &getValue() LLVM_LVALUE_FUNCTION { return *getPointer(); }