libcoro  1.0
Coroutine support library for C++20
async.h
1 #pragma once
2 
3 #include "common.h"
4 #include "allocator.h"
5 #include "future.h"
6 
7 #include <cstdint>
8 namespace coro {
9 
10 #ifdef _MSC_VER
11 #ifdef _DEBUG
13 #define LIBCORO_MSC_FAILED_SYMMETRIC_TRANSFER
14 #endif
15 #endif
16 
18 
54 template<typename T, coro_allocator Alloc = std_allocator>
55 class async {
56 public:
57 
58 
59  class promise_type: public _details::coro_promise<T>, public coro_allocator_helper<Alloc> {
60  public:
61 
78  static future<T> *invalid_value() {
79  return reinterpret_cast<future<T> *>(std::uintptr_t(-1));
80  }
81 
82  promise_type() {
83  this->fut = invalid_value();
84  trace::set_class(std::coroutine_handle<promise_type>::from_promise(*this), typeid(async).name());
85  }
86 
87  struct initial_awaiter {
88  promise_type *me;
89  bool await_ready() const noexcept {return me->fut != invalid_value();}
90  void await_suspend([[maybe_unused]] std::coroutine_handle<> h) noexcept {
91  //initialization is finished, reset the pointer
92  me->fut = nullptr;
93  trace::on_suspend(h, {});
94  }
95  static constexpr void await_resume() noexcept {};
96  };
97 
98  struct final_awaiter {
99  bool detached;
100  bool await_ready() const noexcept {return detached;}
101  #ifdef LIBCORO_MSC_FAILED_SYMMETRIC_TRANSFER
102  void await_suspend(std::coroutine_handle<promise_type> h) const noexcept {
103  promise_type &self = h.promise();
104  std::coroutine_handle<> retval = trace::on_switch(h,self.set_resolved().symmetric_transfer(),{});
105  h.destroy();
106  retval.resume();
107  }
108  #else
109  std::coroutine_handle<> await_suspend(std::coroutine_handle<promise_type> h) const noexcept {
110  promise_type &self = h.promise();
111  std::coroutine_handle<> retval = trace::on_switch(h,self.set_resolved().symmetric_transfer(),{});
112  h.destroy();
113  return retval; //MSC RELEASE BUILD: Handle is passed by a register
114  }
115  #endif
116 
117  void await_resume() const noexcept {}
118  };
119 
120  initial_awaiter initial_suspend() noexcept {return {this};}
121  final_awaiter final_suspend() const noexcept {return {this->fut == nullptr};}
122  async get_return_object() {return {this};}
123 
124  prepared_coro attach(promise<T> &prom) {
125  auto fut = prom.release();
126  auto h = std::coroutine_handle<promise_type>::from_promise(*this);
127  trace::awaiting_ref(h, fut);
128  if (std::exchange(this->fut, fut) == nullptr) {
129  return h;
130  }
131  return {};
132  }
134  if (std::exchange(this->fut, nullptr) == nullptr) {
135  return std::coroutine_handle<promise_type>::from_promise(*this);
136  }
137  return {};
138  }
139  };
140 
142  async() = default;
143 
145  template<typename A>
146  async(async<T, A> &&other):_promise_ptr(cast_promise(other._promise_ptr.release())) {}
147 
148 
150 
154  void detach() {
155  _promise_ptr.release()->detach();
156  }
157 
159 
163  std::coroutine_handle<> detach_on_await_suspend() {
164  return _promise_ptr.release()->detach().symmetric_transfer();
165  }
166 
169  return future<T>([me = std::move(*this)](auto promise) mutable {
170  me._promise_ptr.release()->attach(promise);
171  });
172  }
173 
175  void start(promise<T> prom) {
176  _promise_ptr.release()->attach(prom);
177  }
178 
181  return [me = std::move(*this)](auto promise) mutable {
182  return me._promise_ptr.release()->attach(promise);
183  };
184  }
185 
188  return [me = std::move(*this)](auto promise) mutable {
189  me._promise_ptr.release()->attach(promise);
190  };
191  }
192 
194  future<T> operator co_await() {
195  return *this;
196  }
197 
199  operator future<T>() {
200  return future<T>([me = std::move(*this)](auto promise) mutable {
201  me._promise_ptr.release()->attach(promise);
202  });
203  }
204 
206  operator deferred_future<T>() {
207  return defer_start();
208  }
209 
211  operator shared_future<T>() {
212  return shared_start();
213  }
214 
215 
217  template<std::constructible_from<T> U>
218  operator U () {
219  return U(start().get());
220  }
221 
223  auto run() {
224  return start().get();
225  }
226 
227  operator ident_t() const {return std::coroutine_handle<promise_type>::from_promise(*_promise_ptr);}
228 
229 protected:
230 
231  struct Deleter {
232  void operator()(promise_type *p) {
233  auto h = std::coroutine_handle<promise_type>::from_promise(*p);
234  h.destroy();
235  }
236  };
237 
238  async(promise_type *p): _promise_ptr(p) {}
239 
240  std::unique_ptr<promise_type, Deleter> _promise_ptr;
241 
242  template<typename X>
243  static promise_type *cast_promise(X *other) {
244  return static_cast<promise_type *>(static_cast<_details::coro_promise<T> *>(other));
245  }
246 
247 
248 };
249 
250 
251 }
252 
253 
254 template<typename T, typename ... Args>
255 struct std::coroutine_traits<coro::future<T>, Args...> {
256  using promise_type = typename coro::async<T>::promise_type;
257 
258 };
259 
260 template<typename T, typename ... Args>
261 struct std::coroutine_traits<coro::deferred_future<T>, Args...> {
262  using promise_type = typename coro::async<T>::promise_type;
263 
264 };
265 
266 template<typename T, typename ... Args>
267 struct std::coroutine_traits<coro::shared_future<T>, Args...> {
268  using promise_type = typename coro::async<T>::promise_type;
269 
270 };
271 
272 
273 
void start(promise< T > prom)
Start coroutine and pass return value to promise.
Definition: async.h:175
async(async< T, A > &&other)
convert from different allocator (because the allocator is only used during creation)
Definition: async.h:146
auto run()
run synchronously
Definition: async.h:223
void detach()
Run coroutine detached.
Definition: async.h:154
std::coroutine_handle detach_on_await_suspend()
detach coroutine using symmetric transfer
Definition: async.h:163
deferred_future< T > defer_start()
Defer start of coroutine.
Definition: async.h:180
async()=default
construct uninitialized object
shared_future< T > shared_start()
Start coroutine and return shared future.
Definition: async.h:187
future< T > start()
Start coroutine and return future.
Definition: async.h:168
COROUTINE: Coroutine for asynchronous operation.
Definition: async.h:55
inherit this class to include coro_allocator into your promise_type
Definition: allocator.h:77
Contains future value of T, where evaluation is deferred until the value is needed.
Definition: future.h:1245
Contains future value of T, can be co_awaited in coroutine.
Definition: future.h:417
contains prepared coroutine (prepared to run)
Definition: prepared_coro.h:15
FutureType * release()
Release the future pointer from the promise object.
Definition: future.h:273
Carries reference to future<T>, callable, sets value of an associated future<T>
Definition: future.h:73
Future which can be shared (by copying - like shared_ptr)
Definition: future.h:1406
std::coroutine_handle on_switch(std::coroutine_handle<>, std::coroutine_handle<> to, const void *)
Record switch (symmetric transfer) from one coroutine to other.
Definition: trace.h:393
main namespace
Definition: aggregator.h:8