librf
when_v2.h
1 #pragma once
2 
3 namespace resumef
4 {
5  using any_t = std::any;
6  using std::any_cast;
7 }
8 
9 //纠结过when_any的返回值,是选用index + std::any,还是选用std::variant<>。最终选择了std::any。
10 //std::variant<>存在第一个元素不能默认构造的问题,需要使用std::monostate来占位,导致下标不是从0开始。
11 //而且,std::variant<>里面存在类型重复的问题,好几个操作都是病态的
12 //最最重要的,要统一ranged when_any的返回值,还得做一个运行时通过下标设置std::variant<>的东西
13 //std::any除了内存布局不太理想,其他方面几乎没缺点(在此应用下)
14 
15 namespace resumef
16 {
17 #ifndef DOXYGEN_SKIP_PROPERTY
18  using when_any_pair = std::pair<intptr_t, any_t>;
19  using when_any_pair_ptr = std::shared_ptr<when_any_pair>;
20 
21  namespace detail
22  {
23  struct state_when_t : public state_base_t
24  {
25  state_when_t(intptr_t counter_);
26 
27  virtual void resume() override;
28  virtual bool has_handler() const noexcept override;
29 
30  void on_cancel() noexcept;
31  bool on_notify_one();
32  bool on_timeout();
33 
34  //将自己加入到通知链表里
35  template<class _PromiseT, typename = std::enable_if_t<traits::is_promise_v<_PromiseT>>>
36  scheduler_t* on_await_suspend(coroutine_handle<_PromiseT> handler) noexcept
37  {
38  _PromiseT& promise = handler.promise();
39  auto* parent_state = promise.get_state();
40  scheduler_t* sch = parent_state->get_scheduler();
41 
42  this->_scheduler = sch;
43  this->_coro = handler;
44 
45  return sch;
46  }
47 
48  typedef spinlock lock_type;
49  lock_type _lock;
50  std::atomic<intptr_t> _counter;
51  };
52 
53  template<class _Ty>
54  struct [[nodiscard]] when_future_t
55  {
56  using value_type = _Ty;
57  using state_type = detail::state_when_t;
58  using promise_type = promise_t<value_type>;
59  using future_type = when_future_t<value_type>;
60  using lock_type = typename state_type::lock_type;
61 
62  counted_ptr<state_type> _state;
63  std::shared_ptr<value_type> _values;
64 
65  when_future_t(intptr_t count_) noexcept
66  : _state(new state_type(count_))
67  , _values(std::make_shared<value_type>())
68  {
69  }
70 
71  bool await_ready() noexcept
72  {
73  return _state->_counter.load(std::memory_order_relaxed) == 0;
74  }
75 
76  template<class _PromiseT, typename = std::enable_if_t<traits::is_promise_v<_PromiseT>>>
77  void await_suspend(coroutine_handle<_PromiseT> handler)
78  {
79  _state->on_await_suspend(handler);
80  }
81 
82  value_type await_resume() noexcept(std::is_nothrow_move_constructible_v<value_type>)
83  {
84  return std::move(*_values);
85  }
86  };
87 
88 
89  using ignore_type = std::remove_const_t<decltype(std::ignore)>;
90 
91  template<class _Ty>
92  struct convert_void_2_ignore
93  {
94  using type = std::remove_reference_t<_Ty>;
95  using value_type = type;
96  };
97  template<>
98  struct convert_void_2_ignore<void>
99  {
100  using type = void;
101  using value_type = ignore_type;
102  };
103 
104  template<class _Ty, bool = traits::is_callable_v<_Ty>>
105  struct awaitor_result_impl2
106  {
107  using value_type = typename convert_void_2_ignore<
108  typename traits::awaitor_traits<_Ty>::value_type
109  >::value_type;
110  };
111  template<class _Ty>
112  struct awaitor_result_impl2<_Ty, true> : awaitor_result_impl2<decltype(std::declval<_Ty>()()), false> {};
113 
114  template<class... _Ty>
115  struct awaitor_result_impl{};
116 
117  template<class _Ty>
118  struct awaitor_result_impl<_Ty> : public awaitor_result_impl2<_Ty> {};
119  template<_WhenTaskT _Ty>
120  using awaitor_result_t = typename awaitor_result_impl<std::remove_reference_t<_Ty>>::value_type;
121 
122 
123  template<class _Ty>
124  struct is_when_task : std::bool_constant<traits::is_awaitable_v<_Ty> || traits::is_callable_v<_Ty>> {};
125  template<class _Ty>
126  constexpr bool is_when_task_v = is_when_task<_Ty>::value;
127 
128  template<class _Ty, class _Task = decltype(*std::declval<_Ty>())>
129  constexpr bool is_when_task_iter_v = traits::is_iterator_v<_Ty> && is_when_task_v<_Task>;
130 
131  template<_WhenTaskT _Awaitable>
132  decltype(auto) when_real_awaitor(_Awaitable&& awaitor)
133  {
134  if constexpr (traits::is_callable_v<_Awaitable>)
135  return awaitor();
136  else
137  return std::forward<_Awaitable>(awaitor);
138  }
139 
140  template<_WhenTaskT _Awaitable, class _Ty>
141  future_t<> when_all_connector_1(state_when_t* state, _Awaitable task, _Ty& value)
142  {
143  decltype(auto) awaitor = when_real_awaitor(task);
144 
145  if constexpr (std::is_same_v<_Ty, ignore_type>)
146  co_await awaitor;
147  else
148  value = co_await awaitor;
149  state->on_notify_one();
150  };
151 
152  template<class _FuckBoolean>
153  using _FuckBoolVectorReference = typename std::vector<_FuckBoolean>::reference;
154 
155  template<_WhenTaskT _Awaitable, class _Ty>
156  future_t<> when_all_connector_2(state_when_t* state,_Awaitable task, _FuckBoolVectorReference<_Ty> value)
157  {
158  auto&& awaitor = when_real_awaitor(task);
159 
160  if constexpr(std::is_same_v<_Ty, ignore_type>)
161  co_await awaitor;
162  else
163  value = co_await awaitor;
164  state->on_notify_one();
165  };
166 
167  template<class _Tup, size_t _Idx>
168  inline void when_all_one__(scheduler_t& , state_when_t*, _Tup& )
169  {
170  }
171 
172  template<class _Tup, size_t _Idx, _WhenTaskT _Awaitable, _WhenTaskT... _Rest>
173  inline void when_all_one__(scheduler_t& sch, state_when_t* state, _Tup& values, _Awaitable&& awaitable, _Rest&&... rest)
174  {
175  sch + when_all_connector_1(state, std::forward<_Awaitable>(awaitable), std::get<_Idx>(values));
176 
177  when_all_one__<_Tup, _Idx + 1, _Rest...>(sch, state, values, std::forward<_Rest>(rest)...);
178  }
179 
180  template<class _Val, _WhenIterT _Iter>
181  inline void when_all_range__(scheduler_t& sch, state_when_t* state, std::vector<_Val> & values, _Iter begin, _Iter end)
182  {
183  using _Awaitable = std::remove_reference_t<decltype(*begin)>;
184 
185  intptr_t _Idx = 0;
186  for (; begin != end; ++begin, ++_Idx)
187  {
188  sch + when_all_connector_2<_Awaitable, _Val>(state, *begin, values[_Idx]);
189  }
190  }
191 
192 //-----------------------------------------------------------------------------------------------------------------------------------------
193 
194  template<_WhenTaskT _Awaitable>
195  future_t<> when_any_connector(counted_ptr<state_when_t> state, _Awaitable task, when_any_pair_ptr value, intptr_t idx)
196  {
197  assert(idx >= 0);
198 
199  auto awaitor = when_real_awaitor(task);
200 
201  using value_type = awaitor_result_t<decltype(awaitor)>;
202 
203  if constexpr (std::is_same_v<value_type, ignore_type>)
204  {
205  co_await awaitor;
206 
207  intptr_t oldValue = -1;
208  if (reinterpret_cast<std::atomic<intptr_t>&>(value->first).compare_exchange_strong(oldValue, idx))
209  {
210  state->on_notify_one();
211  }
212  }
213  else
214  {
215  decltype(auto) result = co_await awaitor;
216 
217  intptr_t oldValue = -1;
218  if (reinterpret_cast<std::atomic<intptr_t>&>(value->first).compare_exchange_strong(oldValue, idx))
219  {
220  value->second = std::move(result);
221 
222  state->on_notify_one();
223  }
224  }
225  };
226 
227  inline void when_any_one__(scheduler_t&, state_when_t*, when_any_pair_ptr, intptr_t)
228  {
229  }
230 
231  template<_WhenTaskT _Awaitable, _WhenTaskT... _Rest>
232  inline void when_any_one__(scheduler_t& sch, state_when_t* state, when_any_pair_ptr value, intptr_t _Idx, _Awaitable&& awaitable, _Rest&&... rest)
233  {
234  sch + when_any_connector(state, std::forward<_Awaitable>(awaitable), value, _Idx);
235 
236  when_any_one__(sch, state, value, _Idx + 1, std::forward<_Rest>(rest)...);
237  }
238 
239  template<_WhenIterT _Iter>
240  inline void when_any_range__(scheduler_t& sch, state_when_t* state, when_any_pair_ptr value, _Iter begin, _Iter end)
241  {
242  using _Awaitable = std::remove_reference_t<decltype(*begin)>;
243 
244  intptr_t _Idx = 0;
245  for (; begin != end; ++begin, ++_Idx)
246  {
247  sch + when_any_connector<_Awaitable>(state, *begin, value, static_cast<intptr_t>(_Idx));
248  }
249  }
250  }
251 
252 #endif //DOXYGEN_SKIP_PROPERTY
253 
254 #ifndef DOXYGEN_SKIP_PROPERTY
255 inline namespace when_v2
256 {
257 #else
258 
262  struct when_{
263 #endif
264 
271  template<_WhenTaskT... _Awaitable
272 #ifndef DOXYGEN_SKIP_PROPERTY
273  COMMA_RESUMEF_ENABLE_IF(std::conjunction_v<detail::is_when_task<_Awaitable>...>)
274 #endif //DOXYGEN_SKIP_PROPERTY
275  >
276  auto when_all(scheduler_t& sch, _Awaitable&&... args)
277  -> detail::when_future_t<std::tuple<detail::awaitor_result_t<_Awaitable>...> >
278  {
279  using tuple_type = std::tuple<detail::awaitor_result_t<_Awaitable>...>;
280 
281  detail::when_future_t<tuple_type> awaitor{ sizeof...(_Awaitable) };
282  detail::when_all_one__<tuple_type, 0u, _Awaitable...>(sch, awaitor._state.get(), *awaitor._values, std::forward<_Awaitable>(args)...);
283 
284  return awaitor;
285  }
286 
294  template<_WhenIterT _Iter
295 #ifndef DOXYGEN_SKIP_PROPERTY
296  COMMA_RESUMEF_ENABLE_IF(detail::is_when_task_iter_v<_Iter>)
297 #endif //DOXYGEN_SKIP_PROPERTY
298  >
299  auto when_all(scheduler_t& sch, _Iter begin, _Iter end)
300  -> detail::when_future_t<std::vector<detail::awaitor_result_t<decltype(*std::declval<_Iter>())> > >
301  {
302  using value_type = detail::awaitor_result_t<decltype(*std::declval<_Iter>())>;
303  using vector_type = std::vector<value_type>;
304 
305  detail::when_future_t<vector_type> awaitor{ std::distance(begin, end) };
306  awaitor._values->resize(end - begin);
307  when_all_range__(sch, awaitor._state.get(), *awaitor._values, begin, end);
308 
309  return awaitor;
310  }
311 
318  template<_ContainerT _Cont
319 #ifndef DOXYGEN_SKIP_PROPERTY
320  COMMA_RESUMEF_ENABLE_IF(traits::is_container_v<_Cont>)
321 #endif //DOXYGEN_SKIP_PROPERTY
322  >
323  decltype(auto) when_all(scheduler_t& sch, _Cont& cont)
324  {
325  return when_all(sch, std::begin(cont), std::end(cont));
326  }
327 
334  template<_WhenTaskT... _Awaitable
335 #ifndef DOXYGEN_SKIP_PROPERTY
336  COMMA_RESUMEF_ENABLE_IF(std::conjunction_v<detail::is_when_task<_Awaitable>...>)
337 #endif //DOXYGEN_SKIP_PROPERTY
338  >
339  auto when_all(_Awaitable&&... args)
341  {
342  scheduler_t* sch = current_scheduler();
343  co_return co_await when_all(*sch, std::forward<_Awaitable>(args)...);
344  }
345 
353  template<_WhenIterT _Iter
354 #ifndef DOXYGEN_SKIP_PROPERTY
355  COMMA_RESUMEF_ENABLE_IF(detail::is_when_task_iter_v<_Iter>)
356 #endif //DOXYGEN_SKIP_PROPERTY
357  >
358  auto when_all(_Iter begin, _Iter end)
359  -> future_t<std::vector<detail::awaitor_result_t<decltype(*begin)>>>
360  {
361  scheduler_t* sch = current_scheduler();
362  co_return co_await when_all(*sch, begin, end);
363  }
364 
371  template<_ContainerT _Cont
372 #ifndef DOXYGEN_SKIP_PROPERTY
373  COMMA_RESUMEF_ENABLE_IF(traits::is_container_v<_Cont>)
374 #endif //DOXYGEN_SKIP_PROPERTY
375  >
376  auto when_all(_Cont&& cont)
377  -> future_t<std::vector<detail::awaitor_result_t<decltype(*std::begin(cont))>>>
378  {
379  return when_all(std::begin(cont), std::end(cont));
380  }
381 
382 
383 
390  template<_WhenTaskT... _Awaitable
391 #ifndef DOXYGEN_SKIP_PROPERTY
392  COMMA_RESUMEF_ENABLE_IF(std::conjunction_v<detail::is_when_task<_Awaitable>...>)
393 #endif //DOXYGEN_SKIP_PROPERTY
394  >
395  auto when_any(scheduler_t& sch, _Awaitable&&... args)
396  -> detail::when_future_t<when_any_pair>
397  {
398 #pragma warning(disable : 6326) //warning C6326: Potential comparison of a constant with another constant.
399  detail::when_future_t<when_any_pair> awaitor{ sizeof...(_Awaitable) > 0 ? 1 : 0 };
400 #pragma warning(default : 6326)
401  awaitor._values->first = -1;
402  detail::when_any_one__(sch, awaitor._state.get(), awaitor._values, 0, std::forward<_Awaitable>(args)...);
403 
404  return awaitor;
405  }
406 
414  template<_WhenIterT _Iter
415 #ifndef DOXYGEN_SKIP_PROPERTY
416  COMMA_RESUMEF_ENABLE_IF(detail::is_when_task_iter_v<_Iter>)
417 #endif //DOXYGEN_SKIP_PROPERTY
418  >
419  auto when_any(scheduler_t& sch, _Iter begin, _Iter end)
420  -> detail::when_future_t<when_any_pair>
421  {
422  detail::when_future_t<when_any_pair> awaitor{ begin == end ? 0 : 1 };
423  awaitor._values->first = -1;
424  detail::when_any_range__<_Iter>(sch, awaitor._state.get(), awaitor._values, begin, end);
425 
426  return awaitor;
427  }
428 
435  template<_ContainerT _Cont
436 #ifndef DOXYGEN_SKIP_PROPERTY
437  COMMA_RESUMEF_ENABLE_IF(traits::is_container_v<_Cont>)
438 #endif //DOXYGEN_SKIP_PROPERTY
439  >
440  auto when_any(scheduler_t& sch, _Cont& cont)
441  -> detail::when_future_t<when_any_pair>
442  {
443  return when_any(sch, std::begin(cont), std::end(cont));
444  }
445 
452  template<_WhenTaskT... _Awaitable
453 #ifndef DOXYGEN_SKIP_PROPERTY
454  COMMA_RESUMEF_ENABLE_IF(std::conjunction_v<detail::is_when_task<_Awaitable>...>)
455 #endif //DOXYGEN_SKIP_PROPERTY
456  >
457  auto when_any(_Awaitable&&... args)
459  {
460  scheduler_t* sch = current_scheduler();
461  co_return co_await when_any(*sch, std::forward<_Awaitable>(args)...);
462  }
463 
471  template<_WhenIterT _Iter
472 #ifndef DOXYGEN_SKIP_PROPERTY
473  COMMA_RESUMEF_ENABLE_IF(detail::is_when_task_iter_v<_Iter>)
474 #endif //DOXYGEN_SKIP_PROPERTY
475  >
476  auto when_any(_Iter begin, _Iter end)
478  {
479  scheduler_t* sch = current_scheduler();
480  co_return co_await when_any(*sch, begin, end);
481  }
482 
489  template<_ContainerT _Cont
490 #ifndef DOXYGEN_SKIP_PROPERTY
491  COMMA_RESUMEF_ENABLE_IF(traits::is_container_v<_Cont>)
492 #endif //DOXYGEN_SKIP_PROPERTY
493  >
494  auto when_any(_Cont&& cont)
496  {
497  return when_any(std::begin(cont), std::end(cont));
498  }
499 
500 }
501 }
resumef::scheduler_t
协程调度器。
Definition: scheduler.h:10
resumef::when_::when_any
auto when_any(_Iter begin, _Iter end) -> future_t< when_any_pair >
等待任一的可等待对象完成,迭代器版。
Definition: when_v2.h:476
resumef::when_::when_all
auto when_all(_Awaitable &&... args) -> future_t< std::tuple< detail::awaitor_result_t< _Awaitable >... >>
等待所有的可等待对象完成,不定参数版。
Definition: when_v2.h:339
resumef::when_
目前不知道怎么在doxygen里面能搜集到全局函数的文档。故用一个结构体来欺骗doxygen。
Definition: when_v2.h:262
resumef::when_::when_any
auto when_any(_Awaitable &&... args) -> future_t< when_any_pair >
等待任一的可等待对象完成,不定参数版。
Definition: when_v2.h:457
resumef::when_::when_any
auto when_any(scheduler_t &sch, _Awaitable &&... args) -> detail::when_future_t< when_any_pair >
等待任一的可等待对象完成,不定参数版。
Definition: when_v2.h:395
resumef::future_t
用于resumef协程的返回值。
Definition: future.h:14
resumef::when_::when_all
auto when_all(scheduler_t &sch, _Iter begin, _Iter end) -> detail::when_future_t< std::vector< detail::awaitor_result_t< decltype(*std::declval< _Iter >())> > >
等待所有的可等待对象完成,迭代器版。
Definition: when_v2.h:299
resumef::when_::when_any
auto when_any(scheduler_t &sch, _Iter begin, _Iter end) -> detail::when_future_t< when_any_pair >
等待任一的可等待对象完成,迭代器版。
Definition: when_v2.h:419
resumef::when_::when_any
auto when_any(scheduler_t &sch, _Cont &cont) -> detail::when_future_t< when_any_pair >
等待任一的可等待对象完成,容器版。
Definition: when_v2.h:440
resumef::when_::when_any
auto when_any(_Cont &&cont) -> future_t< when_any_pair >
等待任一的可等待对象完成,容器版。
Definition: when_v2.h:494
resumef::when_::when_all
auto when_all(_Iter begin, _Iter end) -> future_t< std::vector< detail::awaitor_result_t< decltype(*begin)>>>
等待所有的可等待对象完成,迭代器版。
Definition: when_v2.h:358
resumef::when_::when_all
auto when_all(scheduler_t &sch, _Awaitable &&... args) -> detail::when_future_t< std::tuple< detail::awaitor_result_t< _Awaitable >... > >
等待所有的可等待对象完成,不定参数版。
Definition: when_v2.h:276
resumef::when_::when_all
auto when_all(_Cont &&cont) -> future_t< std::vector< detail::awaitor_result_t< decltype(*std::begin(cont))>>>
等待所有的可等待对象完成,容器版。
Definition: when_v2.h:376