Compile RangeSse42.cpp with -msse4.2
[folly.git] / folly / Optional.h
index 2b12ccc6a310d5a708cf945403bc0d91a2245c01..ed601ee7623c2c3ac6a67496332ac6cb494a9f0e 100644 (file)
@@ -59,6 +59,8 @@
 #include <type_traits>
 #include <utility>
 
+#include <folly/Portability.h>
+
 namespace folly {
 
 namespace detail { struct NoneHelper {}; }
@@ -67,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()
@@ -206,10 +197,12 @@ class Optional {
     return storage_.value;
   }
 
-  // TODO: This should return Value&& instead of Value. Like with
-  // std::move, the calling code should decide whether it wants the move
-  // to happen or not. See std::optional.
-  Value value() && {
+  Value&& value() && {
+    require_value();
+    return std::move(storage_.value);
+  }
+
+  const Value&& value() const&& {
     require_value();
     return std::move(storage_.value);
   }
@@ -228,12 +221,10 @@ class Optional {
     return hasValue();
   }
 
-  const Value& operator*() const&  { return value(); }
-        Value& operator*()      &  { return value(); }
-        // TODO: This should return Value&& instead of Value. Like with
-        // std::move, the calling code should decide whether it wants the move
-        // to happen or not. See std::optional.
-        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(); }
@@ -273,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} {}
 
@@ -285,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) {
@@ -311,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();