+
+// Allow usage of Optional<T> in std::unordered_map and std::unordered_set
+FOLLY_NAMESPACE_STD_BEGIN
+template <class T>
+struct hash<folly::Optional<T>> {
+ size_t operator()(folly::Optional<T> const& obj) const {
+ if (!obj.hasValue()) {
+ return 0;
+ }
+ return hash<typename remove_const<T>::type>()(*obj);
+ }
+};
+FOLLY_NAMESPACE_STD_END
+
+// Enable the use of folly::Optional with `co_await`
+// Inspired by https://github.com/toby-allsopp/coroutine_monad
+#if FOLLY_HAS_COROUTINES
+#include <experimental/coroutine>
+
+namespace folly {
+namespace detail {
+template <typename Value>
+struct OptionalPromise;
+
+template <typename Value>
+struct OptionalPromiseReturn {
+ Optional<Value> storage_;
+ OptionalPromise<Value>* promise_;
+ /* implicit */ OptionalPromiseReturn(OptionalPromise<Value>& promise) noexcept
+ : promise_(&promise) {
+ promise.value_ = &storage_;
+ }
+ OptionalPromiseReturn(OptionalPromiseReturn&& that) noexcept
+ : OptionalPromiseReturn{*that.promise_} {}
+ ~OptionalPromiseReturn() {}
+ /* implicit */ operator Optional<Value>() & {
+ return std::move(storage_);
+ }
+};
+
+template <typename Value>
+struct OptionalPromise {
+ Optional<Value>* value_ = nullptr;
+ OptionalPromise() = default;
+ OptionalPromise(OptionalPromise const&) = delete;
+ // This should work regardless of whether the compiler generates:
+ // folly::Optional<Value> retobj{ p.get_return_object(); } // MSVC
+ // or:
+ // auto retobj = p.get_return_object(); // clang
+ OptionalPromiseReturn<Value> get_return_object() noexcept {
+ return *this;
+ }
+ std::experimental::suspend_never initial_suspend() const noexcept {
+ return {};
+ }
+ std::experimental::suspend_never final_suspend() const {
+ return {};
+ }
+ template <typename U>
+ void return_value(U&& u) {
+ *value_ = static_cast<U&&>(u);
+ }
+ void unhandled_exception() {
+ // Technically, throwing from unhandled_exception is underspecified:
+ // https://github.com/GorNishanov/CoroutineWording/issues/17
+ throw;
+ }
+};
+
+template <typename Value>
+struct OptionalAwaitable {
+ Optional<Value> o_;
+ bool await_ready() const noexcept {
+ return o_.hasValue();
+ }
+ Value await_resume() {
+ return std::move(o_.value());
+ }
+
+ // Explicitly only allow suspension into an OptionalPromise
+ template <typename U>
+ void await_suspend(
+ std::experimental::coroutine_handle<OptionalPromise<U>> h) const {
+ // Abort the rest of the coroutine. resume() is not going to be called
+ h.destroy();
+ }
+};
+} // namespace detail
+
+template <typename Value>
+detail::OptionalAwaitable<Value>
+/* implicit */ operator co_await(Optional<Value> o) {
+ return {std::move(o)};
+}
+} // namespace folly
+
+// This makes folly::Optional<Value> useable as a coroutine return type..
+FOLLY_NAMESPACE_STD_BEGIN
+namespace experimental {
+template <typename Value, typename... Args>
+struct coroutine_traits<folly::Optional<Value>, Args...> {
+ using promise_type = folly::detail::OptionalPromise<Value>;
+};
+} // namespace experimental
+FOLLY_NAMESPACE_STD_END
+#endif // FOLLY_HAS_COROUTINES