Thread-safe version of loopKeepAlive()
[folly.git] / folly / Optional.h
index 6fc07b98f47e204f2f5501cca717087b7c5608a1..ed601ee7623c2c3ac6a67496332ac6cb494a9f0e 100644 (file)
  *  }
  */
 #include <cstddef>
+#include <new>
 #include <stdexcept>
 #include <type_traits>
 #include <utility>
 
+#include <folly/Portability.h>
+
 namespace folly {
 
 namespace detail { struct NoneHelper {}; }
@@ -66,17 +69,6 @@ typedef int detail::NoneHelper::*None;
 
 const None none = nullptr;
 
-/**
- * gcc-4.7 warns about use of uninitialized memory around the use of storage_
- * even though this is explicitly initialized at each point.
- */
-#if defined(__GNUC__) && !defined(__clang__)
-# pragma GCC diagnostic push
-# pragma GCC diagnostic ignored "-Wuninitialized"
-# pragma GCC diagnostic ignored "-Wpragmas"
-# pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
-#endif // __GNUC__
-
 class OptionalEmptyException : public std::runtime_error {
  public:
   OptionalEmptyException()
@@ -205,7 +197,12 @@ class Optional {
     return storage_.value;
   }
 
-  Value value() && {
+  Value&& value() && {
+    require_value();
+    return std::move(storage_.value);
+  }
+
+  const Value&& value() const&& {
     require_value();
     return std::move(storage_.value);
   }
@@ -224,9 +221,10 @@ class Optional {
     return hasValue();
   }
 
-  const Value& operator*() const&  { return value(); }
-        Value& operator*()      &  { return value(); }
-        Value  operator*()      && { return std::move(value()); }
+  const Value& operator*()  const&  { return value(); }
+        Value& operator*()       &  { return value(); }
+  const Value&& operator*() const&& { return std::move(value()); }
+        Value&& operator*()      && { return std::move(value()); }
 
   const Value* operator->() const { return &value(); }
         Value* operator->()       { return &value(); }
@@ -266,9 +264,18 @@ class Optional {
   }
 
   struct StorageTriviallyDestructible {
-    // uninitialized
-    union { Value value; };
-    bool hasValue;
+    // The union trick allows to initialize the Optional's memory,
+    // so that compiler/tools don't complain about unitialized memory,
+    // without actually calling Value's default constructor.
+    // The rest of the implementation enforces that hasValue/value are
+    // synchronized.
+    union {
+      bool hasValue;
+      struct {
+        bool paddingForHasValue_[1];
+        Value value;
+      };
+    };
 
     StorageTriviallyDestructible() : hasValue{false} {}
 
@@ -278,15 +285,25 @@ class Optional {
   };
 
   struct StorageNonTriviallyDestructible {
-    // uninitialized
-    union { Value value; };
-    bool hasValue;
-
+    // See StorageTriviallyDestructible's union
+    union {
+      bool hasValue;
+      struct {
+        bool paddingForHasValue_[1];
+        Value value;
+      };
+    };
+
+    FOLLY_PUSH_WARNING
+    // These are both informational warnings, but they trigger rare enough
+    // that we've left them enabled.
+    FOLLY_MSVC_DISABLE_WARNING(4587) // constructor of .value is not called
+    FOLLY_MSVC_DISABLE_WARNING(4588) // destructor of .value is not called
     StorageNonTriviallyDestructible() : hasValue{false} {}
-
     ~StorageNonTriviallyDestructible() {
       clear();
     }
+    FOLLY_POP_WARNING
 
     void clear() {
       if (hasValue) {
@@ -304,10 +321,6 @@ class Optional {
   Storage storage_;
 };
 
-#if defined(__GNUC__) && !defined(__clang__)
-#pragma GCC diagnostic pop
-#endif
-
 template<class T>
 const T* get_pointer(const Optional<T>& opt) {
   return opt.get_pointer();