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)
340 -> future_t<std::tuple<detail::awaitor_result_t<_Awaitable>...>>
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)
458 -> future_t<when_any_pair>
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)
477 -> future_t<when_any_pair>
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)
495 -> future_t<when_any_pair>
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