X-Git-Url: http://plrg.eecs.uci.edu/git/?a=blobdiff_plain;f=folly%2FOptional.h;h=6b49f1ab3b3a7507e3b16ad352e95f75b154e729;hb=d84b1b628d8b723135a34de8dc79cbae3412d8fb;hp=2b12ccc6a310d5a708cf945403bc0d91a2245c01;hpb=4d932ecc53c7a72267179e58eeed7ec56eb7dc53;p=folly.git diff --git a/folly/Optional.h b/folly/Optional.h index 2b12ccc6..6b49f1ab 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(); @@ -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