X-Git-Url: http://plrg.eecs.uci.edu/git/?a=blobdiff_plain;f=folly%2FOptional.h;h=16cf86a10090d75575749c34fbad902f4c47d83f;hb=dc2c2837d095c9d3a5407e939a88b982ba37858a;hp=2b12ccc6a310d5a708cf945403bc0d91a2245c01;hpb=4d932ecc53c7a72267179e58eeed7ec56eb7dc53;p=folly.git diff --git a/folly/Optional.h b/folly/Optional.h index 2b12ccc6..16cf86a1 100644 --- a/folly/Optional.h +++ b/folly/Optional.h @@ -1,5 +1,5 @@ /* - * Copyright 2016 Facebook, Inc. + * Copyright 2017 Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -54,30 +54,29 @@ * } */ #include +#include #include #include #include #include +#include + namespace folly { -namespace detail { struct NoneHelper {}; } +namespace detail { +struct NoneHelper {}; + +// Allow each translation unit to control its own -fexceptions setting. +// If exceptions are disabled, std::terminate() will be called instead of +// throwing OptionalEmptyException when the condition fails. +[[noreturn]] void throw_optional_empty_exception(); +} 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 +205,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 +229,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(); } @@ -260,7 +259,7 @@ class Optional { private: void require_value() const { if (!storage_.hasValue) { - throw OptionalEmptyException(); + detail::throw_optional_empty_exception(); } } @@ -273,9 +272,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 uninitialized 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 +293,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 +329,6 @@ class Optional { Storage storage_; }; -#if defined(__GNUC__) && !defined(__clang__) -#pragma GCC diagnostic pop -#endif - template const T* get_pointer(const Optional& opt) { return opt.get_pointer(); @@ -345,57 +359,57 @@ Opt make_optional(T&& v) { /////////////////////////////////////////////////////////////////////////////// // Comparisons. -template -bool operator==(const Optional& a, const V& b) { +template +bool operator==(const Optional& a, const V& b) { return a.hasValue() && a.value() == b; } -template -bool operator!=(const Optional& a, const V& b) { +template +bool operator!=(const Optional& a, const V& b) { return !(a == b); } -template -bool operator==(const V& a, const Optional& b) { +template +bool operator==(const U& a, const Optional& b) { return b.hasValue() && b.value() == a; } -template -bool operator!=(const V& a, const Optional& b) { +template +bool operator!=(const U& a, const Optional& b) { return !(a == b); } -template -bool operator==(const Optional& a, const Optional& b) { +template +bool operator==(const Optional& a, const Optional& b) { if (a.hasValue() != b.hasValue()) { return false; } if (a.hasValue()) { return a.value() == b.value(); } return true; } -template -bool operator!=(const Optional& a, const Optional& b) { +template +bool operator!=(const Optional& a, const Optional& b) { return !(a == b); } -template -bool operator< (const Optional& a, const Optional& b) { +template +bool operator<(const Optional& a, const Optional& b) { if (a.hasValue() != b.hasValue()) { return a.hasValue() < b.hasValue(); } if (a.hasValue()) { return a.value() < b.value(); } return false; } -template -bool operator> (const Optional& a, const Optional& b) { +template +bool operator>(const Optional& a, const Optional& b) { return b < a; } -template -bool operator<=(const Optional& a, const Optional& b) { +template +bool operator<=(const Optional& a, const Optional& b) { return !(b < a); } -template -bool operator>=(const Optional& a, const Optional& b) { +template +bool operator>=(const Optional& a, const Optional& b) { return !(a < b); } @@ -412,3 +426,16 @@ template bool operator> (const V& other, const Optional&) = delete; /////////////////////////////////////////////////////////////////////////////// } // namespace folly + +// Allow usage of Optional in std::unordered_map and std::unordered_set +FOLLY_NAMESPACE_STD_BEGIN +template +struct hash> { + size_t operator()(folly::Optional const& obj) const { + if (!obj.hasValue()) { + return 0; + } + return hash::type>()(*obj); + } +}; +FOLLY_NAMESPACE_STD_END