]>
Commit | Line | Data |
---|---|---|
11fdf7f2 TL |
1 | // |
2 | // experimental/co_spawn.hpp | |
3 | // ~~~~~~~~~~~~~~~~~~~~~~~~~ | |
4 | // | |
5 | // Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) | |
6 | // | |
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) | |
9 | // | |
10 | ||
11 | #ifndef BOOST_ASIO_EXPERIMENTAL_CO_SPAWN_HPP | |
12 | #define BOOST_ASIO_EXPERIMENTAL_CO_SPAWN_HPP | |
13 | ||
14 | #if defined(_MSC_VER) && (_MSC_VER >= 1200) | |
15 | # pragma once | |
16 | #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) | |
17 | ||
18 | #include <boost/asio/detail/config.hpp> | |
19 | ||
20 | #if defined(BOOST_ASIO_HAS_CO_AWAIT) || defined(GENERATING_DOCUMENTATION) | |
21 | ||
22 | #include <experimental/coroutine> | |
23 | #include <boost/asio/executor.hpp> | |
24 | #include <boost/asio/strand.hpp> | |
25 | ||
26 | #include <boost/asio/detail/push_options.hpp> | |
27 | ||
28 | namespace boost { | |
29 | namespace asio { | |
30 | namespace experimental { | |
31 | namespace detail { | |
32 | ||
33 | using std::experimental::coroutine_handle; | |
34 | ||
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); | |
41 | ||
42 | } // namespace detail | |
43 | ||
44 | namespace this_coro { | |
45 | ||
46 | /// Awaitable type that returns a completion token for the current coroutine. | |
47 | struct token_t {}; | |
48 | ||
49 | /// Awaitable object that returns a completion token for the current coroutine. | |
50 | constexpr inline token_t token() { return {}; } | |
51 | ||
52 | /// Awaitable type that returns the executor of the current coroutine. | |
53 | struct executor_t {}; | |
54 | ||
55 | /// Awaitable object that returns the executor of the current coroutine. | |
56 | constexpr inline executor_t executor() { return {}; } | |
57 | ||
58 | } // namespace this_coro | |
59 | ||
60 | /// A completion token that represents the currently executing coroutine. | |
61 | /** | |
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: | |
65 | * | |
66 | * @code awaitable<void> my_coroutine() | |
67 | * { | |
68 | * await_token token = co_await this_coro::token(); | |
69 | * ... | |
70 | * std::size_t n = co_await my_socket.async_read_some(buffer, token); | |
71 | * ... | |
72 | * } @endcode | |
73 | * | |
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. | |
77 | */ | |
78 | template <typename Executor> | |
79 | class await_token | |
80 | { | |
81 | public: | |
82 | /// The associated executor type. | |
83 | typedef Executor executor_type; | |
84 | ||
85 | /// Copy constructor. | |
86 | await_token(const await_token& other) noexcept | |
87 | : awaiter_(other.awaiter_) | |
88 | { | |
89 | } | |
90 | ||
91 | /// Move constructor. | |
92 | await_token(await_token&& other) noexcept | |
93 | : awaiter_(std::exchange(other.awaiter_, nullptr)) | |
94 | { | |
95 | } | |
96 | ||
97 | /// Get the associated executor. | |
98 | executor_type get_executor() const noexcept | |
99 | { | |
100 | return awaiter_->get_executor(); | |
101 | } | |
102 | ||
103 | private: | |
104 | // No assignment allowed. | |
105 | await_token& operator=(const await_token&) = delete; | |
106 | ||
107 | template <typename> friend class detail::awaitee_base; | |
108 | template <typename, typename> friend class detail::await_handler_base; | |
109 | ||
110 | // Private constructor used by awaitee_base. | |
111 | explicit await_token(detail::awaiter<Executor>* a) | |
112 | : awaiter_(a) | |
113 | { | |
114 | } | |
115 | ||
116 | detail::awaiter<Executor>* awaiter_; | |
117 | }; | |
118 | ||
119 | /// The return type of a coroutine or asynchronous operation. | |
120 | template <typename T, typename Executor = strand<executor>> | |
121 | class awaitable | |
122 | { | |
123 | public: | |
124 | /// The type of the awaited value. | |
125 | typedef T value_type; | |
126 | ||
127 | /// The executor type that will be used for the coroutine. | |
128 | typedef Executor executor_type; | |
129 | ||
130 | /// Move constructor. | |
131 | awaitable(awaitable&& other) noexcept | |
132 | : awaitee_(std::exchange(other.awaitee_, nullptr)) | |
133 | { | |
134 | } | |
135 | ||
136 | /// Destructor | |
137 | ~awaitable() | |
138 | { | |
139 | if (awaitee_) | |
140 | { | |
141 | detail::coroutine_handle< | |
142 | detail::awaitee<T, Executor>>::from_promise( | |
143 | *awaitee_).destroy(); | |
144 | } | |
145 | } | |
146 | ||
147 | #if !defined(GENERATING_DOCUMENTATION) | |
148 | ||
149 | // Support for co_await keyword. | |
150 | bool await_ready() const noexcept | |
151 | { | |
152 | return awaitee_->ready(); | |
153 | } | |
154 | ||
155 | // Support for co_await keyword. | |
156 | void await_suspend(detail::coroutine_handle<detail::awaiter<Executor>> h) | |
157 | { | |
158 | awaitee_->attach_caller(h); | |
159 | } | |
160 | ||
161 | // Support for co_await keyword. | |
162 | template <class U> | |
163 | void await_suspend(detail::coroutine_handle<detail::awaitee<U, Executor>> h) | |
164 | { | |
165 | awaitee_->attach_caller(h); | |
166 | } | |
167 | ||
168 | // Support for co_await keyword. | |
169 | T await_resume() | |
170 | { | |
171 | return awaitee_->get(); | |
172 | } | |
173 | ||
174 | #endif // !defined(GENERATING_DOCUMENTATION) | |
175 | ||
176 | private: | |
177 | template <typename, typename> friend class detail::awaitee; | |
178 | template <typename, typename> friend class detail::await_handler_base; | |
179 | ||
180 | // Not copy constructible or copy assignable. | |
181 | awaitable(const awaitable&) = delete; | |
182 | awaitable& operator=(const awaitable&) = delete; | |
183 | ||
184 | // Construct the awaitable from a coroutine's promise object. | |
185 | explicit awaitable(detail::awaitee<T, Executor>* a) : awaitee_(a) {} | |
186 | ||
187 | detail::awaitee<T, Executor>* awaitee_; | |
188 | }; | |
189 | ||
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) | |
194 | { | |
195 | return detail::co_spawn(ex, std::forward<F>(f), | |
196 | std::forward<CompletionToken>(token)); | |
197 | } | |
198 | ||
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) | |
204 | { | |
205 | return detail::co_spawn(ctx.get_executor(), std::forward<F>(f), | |
206 | std::forward<CompletionToken>(token)); | |
207 | } | |
208 | ||
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) | |
213 | { | |
214 | return detail::co_spawn(parent.get_executor(), std::forward<F>(f), | |
215 | std::forward<CompletionToken>(token)); | |
216 | } | |
217 | ||
218 | } // namespace experimental | |
219 | } // namespace asio | |
220 | } // namespace boost | |
221 | ||
222 | #include <boost/asio/detail/pop_options.hpp> | |
223 | ||
224 | #include <boost/asio/experimental/impl/co_spawn.hpp> | |
225 | ||
226 | #endif // defined(BOOST_ASIO_HAS_CO_AWAIT) || defined(GENERATING_DOCUMENTATION) | |
227 | ||
228 | #endif // BOOST_ASIO_EXPERIMENTAL_CO_SPAWN_HPP |