Commit bf54ecec authored by Pranav Thulasiram Bhat's avatar Pranav Thulasiram Bhat Committed by Facebook GitHub Bot

Turn await into a CPO

Summary: Implement await as a CPO - Allow customization for user defined types outside of folly.

Reviewed By: yfeldblum

Differential Revision: D22268765

fbshipit-source-id: 4badba9274b7206afc339e9d94f6ca991dc5674e
parent 4d04d3d7
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include <folly/Traits.h> #include <folly/Traits.h>
#include <folly/Unit.h> #include <folly/Unit.h>
#include <folly/functional/Invoke.h> #include <folly/functional/Invoke.h>
#include <folly/lang/CustomizationPoint.h>
#include <glog/logging.h> #include <glog/logging.h>
#include <utility> #include <utility>
...@@ -35,14 +36,23 @@ namespace detail { ...@@ -35,14 +36,23 @@ namespace detail {
* cheap to include * cheap to include
*/ */
bool onFiber(); bool onFiber();
} // namespace detail
struct await_fn { struct await_fn {
template <typename T> template <typename T>
T&& operator()(Async<T>&&) const noexcept; auto operator()(Async<T>&& async) const
noexcept(is_nothrow_tag_invocable<await_fn, Async<T>&&>::value)
void operator()(Async<void>&&) const noexcept {} -> tag_invoke_result_t<await_fn, Async<T>&&> {
return tag_invoke(*this, static_cast<Async<T>&&>(async));
}
}; };
} // namespace detail /**
* Function to retrieve the result from the Async wrapper
* A function calling await must return an Async wrapper itself
* for the wrapper to serve its intended purpose (the best way to enforce this
* is static analysis)
*/
FOLLY_DEFINE_CPO(await_fn, await)
/** /**
* Asynchronous fiber result wrapper * Asynchronous fiber result wrapper
...@@ -88,13 +98,16 @@ class [[nodiscard]] Async { ...@@ -88,13 +98,16 @@ class [[nodiscard]] Async {
Async& operator=(const Async&) = delete; Async& operator=(const Async&) = delete;
Async& operator=(Async&&) = delete; Async& operator=(Async&&) = delete;
friend T&& tag_invoke(await_fn, Async && async) noexcept {
DCHECK(detail::onFiber());
return static_cast<T&&>(async.val_);
}
private: private:
T val_; T val_;
template <typename U> template <typename U>
friend class Async; friend class Async;
friend struct detail::await_fn;
}; };
template <> template <>
...@@ -110,6 +123,10 @@ class [[nodiscard]] Async<void> { ...@@ -110,6 +123,10 @@ class [[nodiscard]] Async<void> {
Async(Async && other) = default; Async(Async && other) = default;
Async& operator=(const Async&) = delete; Async& operator=(const Async&) = delete;
Async operator=(Async&&) = delete; Async operator=(Async&&) = delete;
friend void tag_invoke(await_fn, Async &&) noexcept {
DCHECK(detail::onFiber());
}
}; };
#if __cpp_deduction_guides >= 201703 #if __cpp_deduction_guides >= 201703
...@@ -121,21 +138,6 @@ template <typename T> ...@@ -121,21 +138,6 @@ template <typename T>
explicit Async(T)->Async<T>; explicit Async(T)->Async<T>;
#endif #endif
namespace detail {
template <typename T>
T&& await_fn::operator()(Async<T>&& async) const noexcept {
return static_cast<T&&>(async.val_);
}
} // namespace detail
/**
* Function to retrieve the result from the Async wrapper
* A function calling await must return an Async wrapper itself
* for the wrapper to serve its intended purpose (the best way to enforce this
* is static analysis)
*/
constexpr detail::await_fn await;
/** /**
* A utility to start annotating at top of stack (eg. the task which is added to * A utility to start annotating at top of stack (eg. the task which is added to
* fiber manager) A function must not return an Async wrapper if it uses * fiber manager) A function must not return an Async wrapper if it uses
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment