5 using any_t = std::any;
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>;
23 struct state_when_t :
public state_base_t
25 state_when_t(intptr_t counter_);
27 virtual void resume()
override;
28 virtual bool has_handler() const noexcept override;
30 void on_cancel() noexcept;
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
38 _PromiseT& promise = handler.promise();
39 auto* parent_state = promise.get_state();
40 scheduler_t* sch = parent_state->get_scheduler();
42 this->_scheduler = sch;
43 this->_coro = handler;
48 typedef spinlock lock_type;
50 std::atomic<intptr_t> _counter;
54 struct [[nodiscard]] when_future_t
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;
62 counted_ptr<state_type> _state;
63 std::shared_ptr<value_type> _values;
65 when_future_t(intptr_t count_) noexcept
66 : _state(
new state_type(count_))
67 , _values(std::make_shared<value_type>())
71 bool await_ready() noexcept
73 return _state->_counter.load(std::memory_order_relaxed) == 0;
76 template<
class _PromiseT,
typename = std::enable_if_t<traits::is_promise_v<_PromiseT>>>
77 void await_suspend(coroutine_handle<_PromiseT> handler)
79 _state->on_await_suspend(handler);
82 value_type await_resume() noexcept(std::is_nothrow_move_constructible_v<value_type>)
84 return std::move(*_values);
89 using ignore_type = std::remove_const_t<decltype(std::ignore)>;
92 struct convert_void_2_ignore
94 using type = std::remove_reference_t<_Ty>;
95 using value_type = type;
98 struct convert_void_2_ignore<void>
101 using value_type = ignore_type;
104 template<
class _Ty,
bool = traits::is_callable_v<_Ty>>
105 struct awaitor_result_impl2
107 using value_type =
typename convert_void_2_ignore<
108 typename traits::awaitor_traits<_Ty>::value_type
112 struct awaitor_result_impl2<_Ty, true> : awaitor_result_impl2<decltype(std::declval<_Ty>()()), false> {};
114 template<
class... _Ty>
115 struct awaitor_result_impl{};
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;
124 struct is_when_task : std::bool_constant<traits::is_awaitable_v<_Ty> || traits::is_callable_v<_Ty>> {};
126 constexpr
bool is_when_task_v = is_when_task<_Ty>::value;
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>;
131 template<_WhenTaskT _Awaitable>
132 decltype(
auto) when_real_awaitor(_Awaitable&& awaitor)
134 if constexpr (traits::is_callable_v<_Awaitable>)
137 return std::forward<_Awaitable>(awaitor);
140 template<_WhenTaskT _Awaitable,
class _Ty>
141 future_t<> when_all_connector_1(state_when_t* state, _Awaitable task, _Ty& value)
143 decltype(
auto) awaitor = when_real_awaitor(task);
145 if constexpr (std::is_same_v<_Ty, ignore_type>)
148 value = co_await awaitor;
149 state->on_notify_one();
152 template<class _FuckBoolean>
153 using _FuckBoolVectorReference = typename std::vector<_FuckBoolean>::reference;
155 template<_WhenTaskT _Awaitable, class _Ty>
156 future_t<> when_all_connector_2(state_when_t* state,_Awaitable task, _FuckBoolVectorReference<_Ty> value)
158 auto&& awaitor = when_real_awaitor(task);
160 if constexpr(std::is_same_v<_Ty, ignore_type>)
163 value = co_await awaitor;
164 state->on_notify_one();
167 template<
class _Tup,
size_t _Idx>
168 inline void when_all_one__(scheduler_t& , state_when_t*, _Tup& )
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)
175 sch + when_all_connector_1(state, std::forward<_Awaitable>(awaitable), std::get<_Idx>(values));
177 when_all_one__<_Tup, _Idx + 1, _Rest...>(sch, state, values, std::forward<_Rest>(rest)...);
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)
183 using _Awaitable = std::remove_reference_t<decltype(*begin)>;
186 for (; begin != end; ++begin, ++_Idx)
188 sch + when_all_connector_2<_Awaitable, _Val>(state, *begin, values[_Idx]);
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)
199 auto awaitor = when_real_awaitor(task);
201 using value_type = awaitor_result_t<decltype(awaitor)>;
203 if constexpr (std::is_same_v<value_type, ignore_type>)
207 intptr_t oldValue = -1;
208 if (
reinterpret_cast<std::atomic<intptr_t>&
>(value->first).compare_exchange_strong(oldValue, idx))
210 state->on_notify_one();
215 decltype(
auto) result = co_await awaitor;
217 intptr_t oldValue = -1;
218 if (reinterpret_cast<std::atomic<intptr_t>&>(value->first).compare_exchange_strong(oldValue, idx))
220 value->second = std::move(result);
222 state->on_notify_one();
227 inline void when_any_one__(scheduler_t&, state_when_t*, when_any_pair_ptr, intptr_t)
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)
234 sch + when_any_connector(state, std::forward<_Awaitable>(awaitable), value, _Idx);
236 when_any_one__(sch, state, value, _Idx + 1, std::forward<_Rest>(rest)...);
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)
242 using _Awaitable = std::remove_reference_t<decltype(*begin)>;
245 for (; begin != end; ++begin, ++_Idx)
247 sch + when_any_connector<_Awaitable>(state, *begin, value,
static_cast<intptr_t
>(_Idx));
252 #endif //DOXYGEN_SKIP_PROPERTY
254 #ifndef DOXYGEN_SKIP_PROPERTY
255 inline namespace when_v2
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
277 -> detail::when_future_t<std::tuple<detail::awaitor_result_t<_Awaitable>...> >
279 using tuple_type = std::tuple<detail::awaitor_result_t<_Awaitable>...>;
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)...);
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
300 -> detail::when_future_t<std::vector<detail::awaitor_result_t<decltype(*std::declval<_Iter>())> > >
302 using value_type = detail::awaitor_result_t<decltype(*std::declval<_Iter>())>;
303 using vector_type = std::vector<value_type>;
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);
318 template<_ContainerT _Cont
319 #ifndef DOXYGEN_SKIP_PROPERTY
320 COMMA_RESUMEF_ENABLE_IF(traits::is_container_v<_Cont>)
321 #endif //DOXYGEN_SKIP_PROPERTY
325 return when_all(sch, std::begin(cont), std::end(cont));
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
343 co_return co_await when_all(*sch, std::forward<_Awaitable>(args)...);
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
359 ->
future_t<std::vector<detail::awaitor_result_t<decltype(*begin)>>>
362 co_return co_await when_all(*sch, begin, end);
371 template<_ContainerT _Cont
372 #ifndef DOXYGEN_SKIP_PROPERTY
373 COMMA_RESUMEF_ENABLE_IF(traits::is_container_v<_Cont>)
374 #endif //DOXYGEN_SKIP_PROPERTY
377 ->
future_t<std::vector<detail::awaitor_result_t<decltype(*std::begin(cont))>>>
379 return when_all(std::begin(cont), std::end(cont));
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
396 -> detail::when_future_t<when_any_pair>
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)...);
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
420 -> detail::when_future_t<when_any_pair>
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);
435 template<_ContainerT _Cont
436 #ifndef DOXYGEN_SKIP_PROPERTY
437 COMMA_RESUMEF_ENABLE_IF(traits::is_container_v<_Cont>)
438 #endif //DOXYGEN_SKIP_PROPERTY
441 -> detail::when_future_t<when_any_pair>
443 return when_any(sch, std::begin(cont), std::end(cont));
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
461 co_return co_await when_any(*sch, std::forward<_Awaitable>(args)...);
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
480 co_return co_await when_any(*sch, begin, end);
489 template<_ContainerT _Cont
490 #ifndef DOXYGEN_SKIP_PROPERTY
491 COMMA_RESUMEF_ENABLE_IF(traits::is_container_v<_Cont>)
492 #endif //DOXYGEN_SKIP_PROPERTY
497 return when_any(std::begin(cont), std::end(cont));