@@ -1,6 +1,6 @@ | |||
#pragma once | |||
#define LIB_RESUMEF_VERSION 20600 // 2.6.0 | |||
#define LIB_RESUMEF_VERSION 20700 // 2.7.0 | |||
#if defined(RESUMEF_MODULE_EXPORT) | |||
#define RESUMEF_NS export namespace resumef |
@@ -59,7 +59,7 @@ RESUMEF_NS | |||
} | |||
inline namespace event_v1 | |||
namespace event_v1 | |||
{ | |||
event_t::event_t(intptr_t initial_counter_) | |||
: _event(std::make_shared<detail::event_impl>(initial_counter_)) |
@@ -40,7 +40,7 @@ RESUMEF_NS | |||
}; | |||
} | |||
inline namespace event_v1 | |||
namespace event_v1 | |||
{ | |||
//提供一种在协程和非协程之间同步的手段。 |
@@ -104,7 +104,7 @@ RESUMEF_NS | |||
} | |||
} | |||
namespace event_v2 | |||
inline namespace event_v2 | |||
{ | |||
event_t::event_t(bool initially) | |||
:_event(std::make_shared<detail::event_v2_impl>(initially)) |
@@ -7,7 +7,7 @@ RESUMEF_NS | |||
struct event_v2_impl; | |||
} | |||
namespace event_v2 | |||
inline namespace event_v2 | |||
{ | |||
struct event_t | |||
{ | |||
@@ -22,6 +22,7 @@ RESUMEF_NS | |||
void reset() const noexcept; | |||
struct [[nodiscard]] awaiter; | |||
awaiter operator co_await() const noexcept; | |||
awaiter wait() const noexcept; | |||
@@ -31,25 +32,113 @@ RESUMEF_NS | |||
timeout_awaiter wait_for(const std::chrono::duration<_Rep, _Period>& dt) const noexcept; | |||
template<class _Clock, class _Duration> | |||
timeout_awaiter wait_until(const std::chrono::time_point<_Clock, _Duration>& tp) const noexcept; | |||
template<_IteratorT _Iter | |||
COMMA_RESUMEF_ENABLE_IF(traits::is_iterator_v<_Iter> && std::is_same_v<event_t&, decltype(*std::declval<_Iter>())>) | |||
> | |||
static future_t<intptr_t> | |||
wait_any(_Iter begin_, _Iter end_) | |||
{ | |||
when_any_pair idx = co_await when_any(begin_, end_); | |||
co_return idx.first; | |||
} | |||
template<class _Cont | |||
COMMA_RESUMEF_ENABLE_IF(traits::is_container_v<_Cont>) | |||
> | |||
static future_t<intptr_t> | |||
wait_any(_Cont& cnt_) | |||
{ | |||
when_any_pair idx = co_await when_any(std::begin(cnt_), std::end(cnt_)); | |||
co_return idx.first; | |||
} | |||
template<class _Rep, class _Period, _IteratorT _Iter | |||
COMMA_RESUMEF_ENABLE_IF(traits::is_iterator_v<_Iter> && std::is_same_v<event_t&, decltype(*std::declval<_Iter>())>) | |||
> | |||
static future_t<intptr_t> | |||
wait_any_for(const std::chrono::duration<_Rep, _Period>& dt, _Iter begin_, _Iter end_) | |||
{ | |||
auto tidx = co_await when_any(sleep_for(dt), when_any(begin_, end_)); | |||
if (tidx.first == 0) co_return -1; | |||
when_any_pair idx = any_cast<when_any_pair>(tidx.second); | |||
co_return idx.first; | |||
} | |||
template<class _Rep, class _Period, _ContainerT _Cont | |||
COMMA_RESUMEF_ENABLE_IF(traits::is_container_v<_Cont>) | |||
> | |||
static future_t<intptr_t> | |||
wait_any_for(const std::chrono::duration<_Rep, _Period>& dt, _Cont& cont) | |||
{ | |||
return wait_any_for(dt, std::begin(cont), std::end(cont)); | |||
} | |||
template<_IteratorT _Iter | |||
COMMA_RESUMEF_ENABLE_IF(traits::is_iterator_v<_Iter> && std::is_same_v<event_t&, decltype(*std::declval<_Iter>())>) | |||
> | |||
static future_t<bool> | |||
wait_all(_Iter begin_, _Iter end_) | |||
{ | |||
auto vb = co_await when_all(begin_, end_); | |||
co_return is_all_succeeded(vb); | |||
} | |||
template<class _Cont | |||
COMMA_RESUMEF_ENABLE_IF(traits::is_container_v<_Cont>) | |||
> | |||
static future_t<bool> | |||
wait_all(_Cont& cnt_) | |||
{ | |||
auto vb = co_await when_all(std::begin(cnt_), std::end(cnt_)); | |||
co_return is_all_succeeded(vb); | |||
} | |||
template<class _Rep, class _Period, _IteratorT _Iter | |||
COMMA_RESUMEF_ENABLE_IF(traits::is_iterator_v<_Iter> && std::is_same_v<event_t&, decltype(*std::declval<_Iter>())>) | |||
> | |||
static future_t<bool> | |||
wait_all_for(const std::chrono::duration<_Rep, _Period>& dt, _Iter begin_, _Iter end_) | |||
{ | |||
auto tidx = co_await when_any(sleep_for(dt), when_all(begin_, end_)); | |||
if (tidx.first == 0) co_return false; | |||
std::vector<bool>& vb = any_cast<std::vector<bool>&>(tidx.second); | |||
co_return is_all_succeeded(vb); | |||
} | |||
template<class _Rep, class _Period, _ContainerT _Cont | |||
COMMA_RESUMEF_ENABLE_IF(traits::is_container_v<_Cont>) | |||
> | |||
static future_t<bool> | |||
wait_all_for(const std::chrono::duration<_Rep, _Period>& dt, _Cont& cont) | |||
{ | |||
return wait_all_for(dt, std::begin(cont), std::end(cont)); | |||
} | |||
event_t(const event_t&) = default; | |||
event_t(event_t&&) = default; | |||
event_t& operator = (const event_t&) = default; | |||
event_t& operator = (event_t&&) = default; | |||
private: | |||
event_impl_ptr _event; | |||
timeout_awaiter wait_until_(const clock_type::time_point& tp) const noexcept; | |||
inline static bool is_all_succeeded(const std::vector<bool>& v) | |||
{ | |||
return std::none_of(std::begin(v), std::end(v), [](auto v) | |||
{ | |||
return v == false; | |||
}); | |||
} | |||
}; | |||
} | |||
template<class _Rep, class _Period> | |||
auto wait_for(event_v2::event_t& e, const std::chrono::duration<_Rep, _Period>& dt) | |||
{ | |||
return e.wait_for(dt); | |||
} | |||
template<class _Clock, class _Duration> | |||
auto wait_until(event_v2::event_t& e, const std::chrono::time_point<_Clock, _Duration>& tp) | |||
{ | |||
return e.wait_until(tp); | |||
} | |||
//when_all_for(dt, args...) -> when_all(wait_for(args, dt)...) | |||
//就不再单独为每个支持超时的类提供when_all_for实现了。借助when_all和非成员的wait_for实现 | |||
} |
@@ -101,7 +101,7 @@ RESUMEF_NS | |||
}; | |||
} | |||
namespace event_v2 | |||
inline namespace event_v2 | |||
{ | |||
inline void event_t::signal_all() const noexcept | |||
{ |
@@ -30,6 +30,10 @@ RESUMEF_NS | |||
//is_generator_v<T> | |||
//判断是不是一个librf的generator_t类 | |||
// | |||
//is_state_pointer<T> | |||
//is_state_pointer_v<T> | |||
//判断是不是一个librf的state_t类的指针或智能指针 | |||
// | |||
//has_state<T> | |||
//has_state_v<T> | |||
//判断是否具有_state的成员变量 | |||
@@ -42,13 +46,21 @@ RESUMEF_NS | |||
// type:awaitor的类型 | |||
// value_type:awaitor::await_resume()的返回值类型 | |||
// | |||
//is_awaitable<T> | |||
//is_awaitable_v<T> | |||
//判断是否可以被co_await操作。可以是一个awaitor,也可以是重载了成员变量的T::operator co_await(),或者被重载了全局的operator co_awaitor(T) | |||
// | |||
//is_callable<T> | |||
//is_callable_v<T> | |||
//判断是不是一个可被调用的类型,如函数,仿函数,lambda等 | |||
// | |||
//is_scheduler_task<T> | |||
//is_scheduler_task_v<T> | |||
//判断是不是可以被调度器调度的任务。调度器支持future和callable | |||
//is_iterator<T> | |||
//is_iterator_v<T> | |||
//判断是不是一个支持向后迭代的迭代器 | |||
// | |||
//is_container<T> | |||
//is_container_v<T> | |||
//判断是不是一个封闭区间的容器,或者数组。 | |||
template<class _Ty> | |||
struct is_coroutine_handle : std::false_type {}; | |||
@@ -163,7 +175,6 @@ RESUMEF_NS | |||
template<class _Ty, class = std::void_t<>> | |||
struct awaitor_traits{}; | |||
template<class _Ty> | |||
struct awaitor_traits<_Ty, | |||
std::void_t<decltype(get_awaitor(std::declval<_Ty>()))> | |||
@@ -173,6 +184,16 @@ RESUMEF_NS | |||
using value_type = decltype(std::declval<type>().await_resume()); | |||
}; | |||
template<class _Ty, class = std::void_t<>> | |||
struct is_awaitable : std::false_type {}; | |||
template<class _Ty> | |||
struct is_awaitable<_Ty, | |||
std::void_t<typename awaitor_traits<_Ty>::value_type> | |||
> : std::true_type {}; | |||
template<typename _Ty> | |||
constexpr bool is_awaitable_v = is_awaitable<_Ty>::value; | |||
template<typename _Ty, class = std::void_t<>> | |||
struct is_callable : std::false_type{}; | |||
template<typename _Ty> | |||
@@ -186,14 +207,14 @@ RESUMEF_NS | |||
struct is_iterator | |||
<_Ty, | |||
std::void_t< | |||
decltype(++std::declval<_Ty>()) | |||
decltype(std::declval<_Ty>() + 1) | |||
, decltype(std::declval<_Ty>() != std::declval<_Ty>()) | |||
, decltype(*std::declval<_Ty>()) | |||
> | |||
> | |||
: std::true_type{}; | |||
template<class _Ty> | |||
constexpr bool is_iterator_v = is_iterator<remove_cvref_t<_Ty>>::value; | |||
constexpr bool is_iterator_v = is_iterator<_Ty>::value; | |||
template<class _Ty, class = std::void_t<>> | |||
struct is_container : std::false_type {}; | |||
@@ -201,11 +222,20 @@ RESUMEF_NS | |||
struct is_container | |||
<_Ty, | |||
std::void_t< | |||
decltype(std::begin(std::declval<_Ty>())) | |||
, decltype(std::end(std::declval<_Ty>())) | |||
decltype(std::declval<_Ty>().begin()) | |||
, decltype(std::declval<_Ty>().end()) | |||
> | |||
> | |||
: is_iterator<decltype(std::begin(std::declval<_Ty>()))> {}; | |||
: std::true_type {}; | |||
//: is_iterator<decltype(std::declval<_Ty>().begin())> {}; | |||
template<class _Ty, size_t _Size> | |||
struct is_container<_Ty[_Size]> : std::true_type {}; | |||
template<class _Ty, size_t _Size> | |||
struct is_container<_Ty(&)[_Size]> : std::true_type {}; | |||
template<class _Ty, size_t _Size> | |||
struct is_container<_Ty(&&)[_Size]> : std::true_type {}; | |||
template<class _Ty> | |||
constexpr bool is_container_v = is_container<remove_cvref_t<_Ty>>::value; | |||
} |
@@ -14,6 +14,9 @@ RESUMEF_NS | |||
RESUMEF_NS | |||
{ | |||
using when_any_pair = std::pair<intptr_t, any_t>; | |||
using when_any_pair_ptr = std::shared_ptr<when_any_pair>; | |||
namespace detail | |||
{ | |||
struct state_when_t : public state_base_t | |||
@@ -111,7 +114,7 @@ RESUMEF_NS | |||
template<class _Ty> | |||
struct is_when_task : std::bool_constant<traits::is_awaitor_v<_Ty> || traits::is_callable_v<_Ty>> {}; | |||
struct is_when_task : std::bool_constant<traits::is_awaitable_v<_Ty> || traits::is_callable_v<_Ty>> {}; | |||
template<class _Ty> | |||
constexpr bool is_when_task_v = is_when_task<_Ty>::value; | |||
@@ -128,10 +131,25 @@ RESUMEF_NS | |||
} | |||
template<_WhenTaskT _Awaitable, class _Ty> | |||
future_t<> when_all_connector(state_when_t* state, _Awaitable task, _Ty& value) | |||
future_t<> when_all_connector_1(state_when_t* state, _Awaitable task, _Ty& value) | |||
{ | |||
decltype(auto) awaitor = when_real_awaitor(task); | |||
if constexpr (std::is_same_v<_Ty, ignore_type>) | |||
co_await awaitor; | |||
else | |||
value = co_await awaitor; | |||
state->on_notify_one(); | |||
}; | |||
template<class _FuckBoolean> | |||
using _FuckBoolVectorReference = typename std::vector<_FuckBoolean>::reference; | |||
template<_WhenTaskT _Awaitable, class _Ty> | |||
future_t<> when_all_connector_2(state_when_t* state,_Awaitable task, _FuckBoolVectorReference<_Ty> value) | |||
{ | |||
auto&& awaitor = when_real_awaitor(task); | |||
if constexpr(std::is_same_v<_Ty, ignore_type>) | |||
co_await awaitor; | |||
else | |||
@@ -147,7 +165,7 @@ RESUMEF_NS | |||
template<class _Tup, size_t _Idx, _WhenTaskT _Awaitable, _WhenTaskT... _Rest> | |||
inline void when_all_one__(scheduler_t& sch, state_when_t* state, _Tup& values, _Awaitable&& awaitable, _Rest&&... rest) | |||
{ | |||
sch + when_all_connector(state, std::forward<_Awaitable>(awaitable), std::get<_Idx>(values)); | |||
sch + when_all_connector_1(state, std::forward<_Awaitable>(awaitable), std::get<_Idx>(values)); | |||
when_all_one__<_Tup, _Idx + 1, _Rest...>(sch, state, values, std::forward<_Rest>(rest)...); | |||
} | |||
@@ -155,18 +173,17 @@ RESUMEF_NS | |||
template<class _Val, _WhenIterT _Iter> | |||
inline void when_all_range__(scheduler_t& sch, state_when_t* state, std::vector<_Val> & values, _Iter begin, _Iter end) | |||
{ | |||
using _Awaitable = decltype(*begin); | |||
intptr_t _Idx = 0; | |||
for (; begin != end; ++begin, ++_Idx) | |||
{ | |||
sch + when_all_connector(state, std::move(*begin), values[_Idx]); | |||
sch + when_all_connector_2<_Awaitable, _Val>(state, *begin, values[_Idx]); | |||
} | |||
} | |||
//----------------------------------------------------------------------------------------------------------------------------------------- | |||
using when_any_pair = std::pair<intptr_t, any_t>; | |||
using when_any_pair_ptr = std::shared_ptr<when_any_pair>; | |||
template<_WhenTaskT _Awaitable> | |||
future_t<> when_any_connector(counted_ptr<state_when_t> state, _Awaitable task, when_any_pair_ptr value, intptr_t idx) | |||
{ | |||
@@ -276,7 +293,7 @@ inline namespace when_v2 | |||
COMMA_RESUMEF_ENABLE_IF(detail::is_when_task_iter_v<_Iter>) | |||
> | |||
auto when_all(_Iter begin, _Iter end) | |||
-> future_t<std::vector<detail::awaitor_result_t<decltype(*std::declval<_Iter>())>>> | |||
-> future_t<std::vector<detail::awaitor_result_t<decltype(*begin)>>> | |||
{ | |||
co_return co_await when_all(*current_scheduler(), begin, end); | |||
} | |||
@@ -284,7 +301,8 @@ inline namespace when_v2 | |||
template<_ContainerT _Cont | |||
COMMA_RESUMEF_ENABLE_IF(traits::is_container_v<_Cont>) | |||
> | |||
decltype(auto) when_all(_Cont& cont) | |||
auto when_all(_Cont&& cont) | |||
-> future_t<std::vector<detail::awaitor_result_t<decltype(*std::begin(cont))>>> | |||
{ | |||
return when_all(std::begin(cont), std::end(cont)); | |||
} | |||
@@ -295,9 +313,9 @@ inline namespace when_v2 | |||
COMMA_RESUMEF_ENABLE_IF(std::conjunction_v<detail::is_when_task<_Awaitable>...>) | |||
> | |||
auto when_any(scheduler_t& sch, _Awaitable&&... args) | |||
-> detail::when_future_t<detail::when_any_pair> | |||
-> detail::when_future_t<when_any_pair> | |||
{ | |||
detail::when_future_t<detail::when_any_pair> awaitor{ sizeof...(_Awaitable) > 0 ? 1 : 0 }; | |||
detail::when_future_t<when_any_pair> awaitor{ sizeof...(_Awaitable) > 0 ? 1 : 0 }; | |||
awaitor._values->first = -1; | |||
detail::when_any_one__(sch, awaitor._state.get(), awaitor._values, 0, std::forward<_Awaitable>(args)...); | |||
@@ -308,9 +326,9 @@ inline namespace when_v2 | |||
COMMA_RESUMEF_ENABLE_IF(detail::is_when_task_iter_v<_Iter>) | |||
> | |||
auto when_any(scheduler_t& sch, _Iter begin, _Iter end) | |||
-> detail::when_future_t<detail::when_any_pair> | |||
-> detail::when_future_t<when_any_pair> | |||
{ | |||
detail::when_future_t<detail::when_any_pair> awaitor{ begin == end ? 0 : 1 }; | |||
detail::when_future_t<when_any_pair> awaitor{ begin == end ? 0 : 1 }; | |||
awaitor._values->first = -1; | |||
detail::when_any_range__<_Iter>(sch, awaitor._state.get(), awaitor._values, begin, end); | |||
@@ -329,7 +347,7 @@ inline namespace when_v2 | |||
COMMA_RESUMEF_ENABLE_IF(std::conjunction_v<detail::is_when_task<_Awaitable>...>) | |||
> | |||
auto when_any(_Awaitable&&... awaitor) | |||
-> future_t<detail::when_any_pair> | |||
-> future_t<when_any_pair> | |||
{ | |||
co_return co_await when_any(*current_scheduler(), std::forward<_Awaitable>(awaitor)...); | |||
} | |||
@@ -338,7 +356,7 @@ inline namespace when_v2 | |||
COMMA_RESUMEF_ENABLE_IF(detail::is_when_task_iter_v<_Iter>) | |||
> | |||
auto when_any(_Iter begin, _Iter end) | |||
-> future_t<detail::when_any_pair> | |||
-> future_t<when_any_pair> | |||
{ | |||
co_return co_await when_any(*current_scheduler(), begin, end); | |||
} | |||
@@ -346,7 +364,7 @@ inline namespace when_v2 | |||
template<_ContainerT _Cont | |||
COMMA_RESUMEF_ENABLE_IF(traits::is_container_v<_Cont>) | |||
> | |||
decltype(auto) when_any(_Cont& cont) | |||
auto when_any(_Cont&& cont) | |||
{ | |||
return when_any(std::begin(cont), std::end(cont)); | |||
} |
@@ -139,7 +139,7 @@ void test_wait_timeout_all() | |||
intptr_t counter = 0; | |||
for (;;) | |||
{ | |||
if (co_await event_t::wait_all_until(system_clock::now() + 500ms, evts)) | |||
if (co_await event_t::wait_all_for(500ms, evts)) | |||
{ | |||
std::cout << counter << std::endl; | |||
std::cout << "all event signal!" << std::endl; |