X-Git-Url: http://plrg.eecs.uci.edu/git/?a=blobdiff_plain;f=folly%2FOptional.h;h=39abcc1c6db900ddc5a4118c0335dec55e115b98;hb=d89c342ab6b905d2a6bfba7317eac41d44077d65;hp=2693423d63e67eb73bfc195c02692b9f0e62f755;hpb=4b351b61294aee1643f4793598dd31381faa8801;p=folly.git diff --git a/folly/Optional.h b/folly/Optional.h index 2693423d..39abcc1c 100644 --- a/folly/Optional.h +++ b/folly/Optional.h @@ -63,6 +63,7 @@ #include #include +#include #include namespace folly { @@ -203,15 +204,41 @@ class Optional { } template - void emplace(Args&&... args) { + Value& emplace(Args&&... args) { clear(); - storage_.construct(std::forward(args)...); + return storage_.construct(std::forward(args)...); + } + + template + typename std::enable_if< + std::is_constructible&, Args&&...>::value, + Value&>::type + emplace(std::initializer_list ilist, Args&&... args) { + clear(); + return storage_.construct(ilist, std::forward(args)...); } - void clear() { + void reset() noexcept { storage_.clear(); } + void clear() noexcept { + reset(); + } + + void swap(Optional& that) noexcept(IsNothrowSwappable::value) { + if (hasValue() && that.hasValue()) { + using std::swap; + swap(value(), that.value()); + } else if (hasValue()) { + that.emplace(std::move(value())); + reset(); + } else if (that.hasValue()) { + emplace(std::move(that.value())); + that.reset(); + } + } + FOLLY_CPP14_CONSTEXPR const Value& value() const & { require_value(); return *storage_.value_pointer(); @@ -240,12 +267,16 @@ class Optional { } Value* get_pointer() && = delete; - FOLLY_CPP14_CONSTEXPR bool hasValue() const noexcept { + FOLLY_CPP14_CONSTEXPR bool has_value() const noexcept { return storage_.hasValue(); } + FOLLY_CPP14_CONSTEXPR bool hasValue() const noexcept { + return has_value(); + } + FOLLY_CPP14_CONSTEXPR explicit operator bool() const noexcept { - return hasValue(); + return has_value(); } FOLLY_CPP14_CONSTEXPR const Value& operator*() const & { @@ -350,9 +381,10 @@ class Optional { } template - void construct(Args&&... args) { + Value& construct(Args&&... args) { new (raw_pointer()) Value(std::forward(args)...); this->hasValue_ = true; + return *launder(reinterpret_cast(this->value_)); } private: @@ -375,14 +407,8 @@ T* get_pointer(Optional& opt) { } template -void swap(Optional& a, Optional& b) { - if (a.hasValue() && b.hasValue()) { - // both full - using std::swap; - swap(a.value(), b.value()); - } else if (a.hasValue() || b.hasValue()) { - std::swap(a, b); // fall back to default implementation if they're mixed. - } +void swap(Optional& a, Optional& b) noexcept(noexcept(a.swap(b))) { + a.swap(b); } template ::type>> @@ -598,13 +624,14 @@ struct OptionalAwaitable { return o_.hasValue(); } Value await_resume() { - return o_.value(); + return std::move(o_.value()); } - template - void await_suspend(CoroHandle h) const { - // make sure the coroutine returns an empty Optional: - h.promise().value_->clear(); - // Abort the rest of the coroutine: + + // Explicitly only allow suspension into an OptionalPromise + template + void await_suspend( + std::experimental::coroutine_handle> h) const { + // Abort the rest of the coroutine. resume() is not going to be called h.destroy(); } }; @@ -617,13 +644,13 @@ detail::OptionalAwaitable } } // namespace folly -// This makes std::optional useable as a coroutine return type.. +// This makes folly::Optional useable as a coroutine return type.. FOLLY_NAMESPACE_STD_BEGIN namespace experimental { template struct coroutine_traits, Args...> { using promise_type = folly::detail::OptionalPromise; }; -} // experimental +} // namespace experimental FOLLY_NAMESPACE_STD_END #endif // FOLLY_HAS_COROUTINES