2 // experimental/co_spawn.hpp
3 // ~~~~~~~~~~~~~~~~~~~~~~~~~
5 // Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
7 // Distributed under the Boost Software License, Version 1.0. (See accompanying
8 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
11 #ifndef BOOST_ASIO_EXPERIMENTAL_CO_SPAWN_HPP
12 #define BOOST_ASIO_EXPERIMENTAL_CO_SPAWN_HPP
14 #if defined(_MSC_VER) && (_MSC_VER >= 1200)
16 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
18 #include <boost/asio/detail/config.hpp>
20 #if defined(BOOST_ASIO_HAS_CO_AWAIT) || defined(GENERATING_DOCUMENTATION)
22 #include <experimental/coroutine>
23 #include <boost/asio/executor.hpp>
24 #include <boost/asio/strand.hpp>
26 #include <boost/asio/detail/push_options.hpp>
30 namespace experimental {
33 using std::experimental::coroutine_handle;
35 template <typename> class awaiter;
36 template <typename> class awaitee_base;
37 template <typename, typename> class awaitee;
38 template <typename, typename> class await_handler_base;
39 template <typename Executor, typename F, typename CompletionToken>
40 auto co_spawn(const Executor& ex, F&& f, CompletionToken&& token);
46 /// Awaitable type that returns a completion token for the current coroutine.
49 /// Awaitable object that returns a completion token for the current coroutine.
50 constexpr inline token_t token() { return {}; }
52 /// Awaitable type that returns the executor of the current coroutine.
55 /// Awaitable object that returns the executor of the current coroutine.
56 constexpr inline executor_t executor() { return {}; }
58 } // namespace this_coro
60 /// A completion token that represents the currently executing coroutine.
62 * The await_token class is used to represent the currently executing
63 * coroutine. An await_token may be passed as a handler to an asynchronous
64 * operation. For example:
66 * @code awaitable<void> my_coroutine()
68 * await_token token = co_await this_coro::token();
70 * std::size_t n = co_await my_socket.async_read_some(buffer, token);
74 * The initiating function (async_read_some in the above example) suspends the
75 * current coroutine. The coroutine is resumed when the asynchronous operation
76 * completes, and the result of the operation is returned.
78 template <typename Executor>
82 /// The associated executor type.
83 typedef Executor executor_type;
86 await_token(const await_token& other) noexcept
87 : awaiter_(other.awaiter_)
92 await_token(await_token&& other) noexcept
93 : awaiter_(std::exchange(other.awaiter_, nullptr))
97 /// Get the associated executor.
98 executor_type get_executor() const noexcept
100 return awaiter_->get_executor();
104 // No assignment allowed.
105 await_token& operator=(const await_token&) = delete;
107 template <typename> friend class detail::awaitee_base;
108 template <typename, typename> friend class detail::await_handler_base;
110 // Private constructor used by awaitee_base.
111 explicit await_token(detail::awaiter<Executor>* a)
116 detail::awaiter<Executor>* awaiter_;
119 /// The return type of a coroutine or asynchronous operation.
120 template <typename T, typename Executor = strand<executor>>
124 /// The type of the awaited value.
125 typedef T value_type;
127 /// The executor type that will be used for the coroutine.
128 typedef Executor executor_type;
130 /// Move constructor.
131 awaitable(awaitable&& other) noexcept
132 : awaitee_(std::exchange(other.awaitee_, nullptr))
141 detail::coroutine_handle<
142 detail::awaitee<T, Executor>>::from_promise(
143 *awaitee_).destroy();
147 #if !defined(GENERATING_DOCUMENTATION)
149 // Support for co_await keyword.
150 bool await_ready() const noexcept
152 return awaitee_->ready();
155 // Support for co_await keyword.
156 void await_suspend(detail::coroutine_handle<detail::awaiter<Executor>> h)
158 awaitee_->attach_caller(h);
161 // Support for co_await keyword.
163 void await_suspend(detail::coroutine_handle<detail::awaitee<U, Executor>> h)
165 awaitee_->attach_caller(h);
168 // Support for co_await keyword.
171 return awaitee_->get();
174 #endif // !defined(GENERATING_DOCUMENTATION)
177 template <typename, typename> friend class detail::awaitee;
178 template <typename, typename> friend class detail::await_handler_base;
180 // Not copy constructible or copy assignable.
181 awaitable(const awaitable&) = delete;
182 awaitable& operator=(const awaitable&) = delete;
184 // Construct the awaitable from a coroutine's promise object.
185 explicit awaitable(detail::awaitee<T, Executor>* a) : awaitee_(a) {}
187 detail::awaitee<T, Executor>* awaitee_;
190 /// Spawn a new thread of execution.
191 template <typename Executor, typename F, typename CompletionToken,
192 typename = typename enable_if<is_executor<Executor>::value>::type>
193 inline auto co_spawn(const Executor& ex, F&& f, CompletionToken&& token)
195 return detail::co_spawn(ex, std::forward<F>(f),
196 std::forward<CompletionToken>(token));
199 /// Spawn a new thread of execution.
200 template <typename ExecutionContext, typename F, typename CompletionToken,
201 typename = typename enable_if<
202 is_convertible<ExecutionContext&, execution_context&>::value>::type>
203 inline auto co_spawn(ExecutionContext& ctx, F&& f, CompletionToken&& token)
205 return detail::co_spawn(ctx.get_executor(), std::forward<F>(f),
206 std::forward<CompletionToken>(token));
209 /// Spawn a new thread of execution.
210 template <typename Executor, typename F, typename CompletionToken>
211 inline auto co_spawn(const await_token<Executor>& parent,
212 F&& f, CompletionToken&& token)
214 return detail::co_spawn(parent.get_executor(), std::forward<F>(f),
215 std::forward<CompletionToken>(token));
218 } // namespace experimental
222 #include <boost/asio/detail/pop_options.hpp>
224 #include <boost/asio/experimental/impl/co_spawn.hpp>
226 #endif // defined(BOOST_ASIO_HAS_CO_AWAIT) || defined(GENERATING_DOCUMENTATION)
228 #endif // BOOST_ASIO_EXPERIMENTAL_CO_SPAWN_HPP