libcoro  1.0
Coroutine support library for C++20
frame.h
1 #pragma once
2 
3 #include "function.h"
4 #include "coroutine.h"
5 
6 
7 namespace coro {
8 
9 template<typename T>
10 concept has_co_await_operator = requires(T v){
11  {v.operator co_await()};
12 };
13 
14 //#define LIBCORO_FRAME_COMPATIBILITY_FALLBACK
15 
17 
29 template<typename T>
30 class frame {
31 protected:
32  void do_resume() {
33  auto *content = static_cast<T *>(this);
34  content->resume();
35  }
36 
37  void do_destroy() {
38  auto *content = static_cast<T *>(this);
39  content->destroy();
40  }
41 
42 
43 #ifdef LIBCORO_FRAME_COMPATIBILITY_FALLBACK
44 
45 
46  struct local_coro {
47  struct promise_type;
48  std::coroutine_handle<promise_type> h;
49  struct promise_type {
50  frame *me = nullptr;
51  std::suspend_always initial_suspend() noexcept {return {};}
52  std::suspend_always final_suspend() noexcept {return {};}
53  void unhandled_exception() {}
54  void return_void() {}
55  local_coro get_return_object() {return {
56  std::coroutine_handle<promise_type>::from_promise(*this)
57  };};
58 
59  struct yield_awaiter {
60  bool retval;
61  static constexpr bool await_ready() noexcept {return false;}
62  bool await_suspend(std::coroutine_handle<promise_type> h) {
63  promise_type &p = h.promise();
64  retval = p.me->_finish;
65  if (retval) return false;
66  p.me->do_resume();
67  return true;
68 
69  }
70  bool await_resume() const {
71  return retval;
72  }
73  };
74 
75  yield_awaiter yield_value(std::nullptr_t) {return {};}
76 
77  ~promise_type() {
78  if (me) {
79  me->_this_coro.h = {};
80  me->do_destroy();
81  }
82  }
83  };
84  };
85 
86  local_coro _this_coro;
87  bool _finish = false;
88 
89  static local_coro processing() {
90  while (!(co_yield nullptr));
91  }
92 
93  frame() {
94  _this_coro = processing();
95  _this_coro.h.promise().me = this;
96  }
97  ~frame() {
98  if (_this_coro.h) {
99  _this_coro.h.promise().me = nullptr;
100  _this_coro.h.destroy();
101  }
102  }
103 
104  void set_done() {
105  _finish = true;
106  _this_coro.h.resume();
107  }
108 public:
109 
111  std::coroutine_handle<> get_handle() {
112  return _this_coro.h;
113  }
114 
115 
116 #else
117  void (*_resume_fn)(std::coroutine_handle<>) = [](std::coroutine_handle<> h) {
118  static_assert(requires(T v){{v.resume()};}, "The child class must have T::resume() function");
119  auto *me = reinterpret_cast<frame *>(h.address());
120  me->do_resume();
121  };
122  void (*_destroy_fn)(std::coroutine_handle<>) = [](std::coroutine_handle<> h) {
123  static_assert(requires(T v){{v.resume()};}, "The child class must have T::destroy() function");
124  auto *me = reinterpret_cast<frame *>(h.address());
125  me->do_destroy();
126  };
127  void set_done() {
128  _resume_fn = nullptr;
129  }
130 
131 
133 
136 public:
138  std::coroutine_handle<> get_handle() {
139  return std::coroutine_handle<>::from_address(this);
140  }
141 #endif
142 
144 
150  template<typename Awt>
151  void await(Awt &awt) {
152  if (!try_await(awt)) do_resume();
153  }
154 
156 
161  template<typename Awt>
162  bool try_await(Awt &awt) {
163  if (!awt.await_ready()) {
164  auto h = get_handle();
165  using Ret = decltype(awt.await_suspend(h));
166  if constexpr(std::is_convertible_v<Ret, std::coroutine_handle<> >) {
167  auto g = awt.await_suspend(h);
168  if (g == h) return false;
169  trace::resume(g);
170  } else if constexpr(std::is_convertible_v<Ret, bool>) {
171  if (!awt.await_suspend(h)) {
172  return false;
173  }
174  } else {
175  awt.await_suspend(get_handle());
176  }
177  return true;
178  } else {
179  return false;
180  }
181  }
182 
183 
184 };
185 
186 
187 
188 
189 }
bool try_await(Awt &awt)
Emulates co_await (without await_resume) with no suspend when ready.
Definition: frame.h:162
std::coroutine_handle get_handle()
Sets done flag.
Definition: frame.h:138
void await(Awt &awt)
Emulates co_await (without await_resume)
Definition: frame.h:151
Creates coroutine compatible memory layout, so the object acts as an coroutine.
Definition: frame.h:30
void resume(std::coroutine_handle<> h) noexcept
Record resumption of an coroutine.
Definition: trace.h:382
main namespace
Definition: aggregator.h:8