@@ -48,7 +48,6 @@ | |||
#include "src/generator.h" | |||
#include "src/rf_task.h" | |||
#include "src/utils.h" | |||
#include "src/timer.h" | |||
#include "src/scheduler.h" | |||
@@ -20,27 +20,28 @@ RESUMEF_NS | |||
{ | |||
return sleep_for_(std::chrono::duration_cast<std::chrono::system_clock::duration>(dt_), scheduler_); | |||
} | |||
template<class _Rep, class _Period> | |||
inline future_t<> sleep_for(const std::chrono::duration<_Rep, _Period>& dt_) | |||
{ | |||
return sleep_for_(std::chrono::duration_cast<std::chrono::system_clock::duration>(dt_), *this_scheduler()); | |||
} | |||
template<class _Clock, class _Duration = typename _Clock::duration> | |||
inline future_t<> sleep_until(const std::chrono::time_point<_Clock, _Duration>& tp_, scheduler_t& scheduler_) | |||
{ | |||
return sleep_until_(std::chrono::time_point_cast<std::chrono::system_clock::duration>(tp_), scheduler_); | |||
} | |||
template<class _Rep, class _Period> | |||
inline future_t<> sleep_for(const std::chrono::duration<_Rep, _Period>& dt_) | |||
{ | |||
co_await sleep_for_(std::chrono::duration_cast<std::chrono::system_clock::duration>(dt_), *current_scheduler()); | |||
} | |||
template<class _Clock, class _Duration> | |||
inline future_t<> sleep_until(const std::chrono::time_point<_Clock, _Duration>& tp_) | |||
{ | |||
return sleep_until_(std::chrono::time_point_cast<std::chrono::system_clock::duration>(tp_), *this_scheduler()); | |||
co_await sleep_until_(std::chrono::time_point_cast<std::chrono::system_clock::duration>(tp_), *current_scheduler()); | |||
} | |||
template <class Rep, class Period> | |||
inline future_t<> operator co_await(std::chrono::duration<Rep, Period> dt_) | |||
{ | |||
return sleep_for(dt_); | |||
co_await sleep_for(dt_, *current_scheduler()); | |||
} | |||
} |
@@ -4,10 +4,56 @@ RESUMEF_NS | |||
{ | |||
namespace traits | |||
{ | |||
//is_coroutine_handle<T> | |||
//is_coroutine_handle_v<T> | |||
//判断是不是coroutine_handle<>类型 | |||
// | |||
//is_valid_await_suspend_return_v<T> | |||
//判断是不是awaitor的await_suspend()函数的有效返回值 | |||
// | |||
//is_awaitor<T> | |||
//is_awaitor_v<T> | |||
//判断是不是一个awaitor规范。 | |||
//一个awaitor可以被co_await操作,要求满足coroutine的awaitor的三个函数接口规范 | |||
// | |||
//is_future<T> | |||
//is_future_v<T> | |||
//判断是不是一个librf的future规范。 | |||
//future除了要求是一个awaitor外,还要求定义了value_type/state_type/promise_type三个类型, | |||
//并且具备counted_ptr<state_type>类型的_state变量。 | |||
// | |||
//is_promise<T> | |||
//is_promise_v<T> | |||
//判断是不是一个librf的promise_t类 | |||
// | |||
//is_generator<T> | |||
//is_generator_v<T> | |||
//判断是不是一个librf的generator_t类 | |||
// | |||
//has_state<T> | |||
//has_state_v<T> | |||
//判断是否具有_state的成员变量 | |||
// | |||
//get_awaitor<T>(T&&t) | |||
//通过T获得其被co_await后的awaitor | |||
// | |||
//awaitor_traits<T> | |||
//获得一个awaitor的特征。 | |||
// type:awaitor的类型 | |||
// value_type:awaitor::await_resume()的返回值类型 | |||
// | |||
//is_callable<T> | |||
//is_callable_v<T> | |||
//判断是不是一个可被调用的类型,如函数,仿函数,lambda等 | |||
// | |||
//is_scheduler_task<T> | |||
//is_scheduler_task_v<T> | |||
//判断是不是可以被调度器调度的任务。调度器支持future和callable | |||
template<class _Ty> | |||
struct is_coroutine_handle : std::false_type {}; | |||
template<class _PromiseT> | |||
struct is_coroutine_handle<std::experimental::coroutine_handle<_PromiseT>> : std::true_type {}; | |||
struct is_coroutine_handle<coroutine_handle<_PromiseT>> : std::true_type {}; | |||
template<class _Ty> | |||
constexpr bool is_coroutine_handle_v = is_coroutine_handle<remove_cvref_t<_Ty>>::value; | |||
@@ -116,5 +162,22 @@ RESUMEF_NS | |||
using type = decltype(get_awaitor(std::declval<_Ty>())); | |||
using value_type = decltype(std::declval<type>().await_resume()); | |||
}; | |||
template<typename _Function> | |||
inline auto _IsCallable(_Function&& _Func, int) -> decltype(_Func(), std::true_type()) | |||
{ | |||
(_Func); | |||
return std::true_type(); | |||
} | |||
template<typename _Function> | |||
inline std::false_type _IsCallable(_Function&&, ...) | |||
{ | |||
return std::false_type(); | |||
} | |||
template<typename _Function> | |||
using is_callable = decltype(_IsCallable(std::declval<_Function>(), 0)); | |||
template<typename _Function> | |||
constexpr bool is_callable_v = is_callable<_Function>::value; | |||
} | |||
} |
@@ -4,22 +4,5 @@ RESUMEF_NS | |||
{ | |||
namespace traits | |||
{ | |||
template<typename _Function> | |||
inline auto _IsCallable(_Function&& _Func, int) -> decltype(_Func(), std::true_type()) | |||
{ | |||
(_Func); | |||
return std::true_type(); | |||
} | |||
template<typename _Function> | |||
inline std::false_type _IsCallable(_Function&&, ...) | |||
{ | |||
return std::false_type(); | |||
} | |||
template<typename _Function> | |||
using is_callable = decltype(_IsCallable(std::declval<_Function>(), 0)); | |||
template<typename _Function> | |||
constexpr bool is_callable_v = is_callable<_Function>::value; | |||
} | |||
} |
@@ -97,16 +97,37 @@ RESUMEF_NS | |||
using value_type = ignore_type; | |||
}; | |||
template<class _Ty, bool = traits::is_callable_v<_Ty>> | |||
struct awaitor_result_impl | |||
{ | |||
using value_type = typename convert_void_2_ignore< | |||
typename traits::awaitor_traits<_Ty>::value_type | |||
>::value_type; | |||
}; | |||
template<class _Ty> | |||
struct awaitor_result_impl<_Ty, true> : awaitor_result_impl<decltype(std::declval<_Ty>()()), false> {}; | |||
template<class _Ty> | |||
using awaitor_result_t = typename awaitor_result_impl<_Ty>::value_type; | |||
template<class _Ty> | |||
using awaitor_result_t = typename convert_void_2_ignore< | |||
typename traits::awaitor_traits<_Ty>::value_type | |||
>::value_type; | |||
struct is_when_task : std::bool_constant<traits::is_awaitor_v<_Ty> || traits::is_callable_v<_Ty>> {}; | |||
template<class _Ty> | |||
constexpr bool is_when_task_v = is_when_task<_Ty>::value; | |||
template<class _Awaitable> | |||
decltype(auto) when_real_awaitor(_Awaitable&& awaitor) | |||
{ | |||
if constexpr (traits::is_callable_v<_Awaitable>) | |||
return awaitor(); | |||
else | |||
return std::forward<_Awaitable>(awaitor); | |||
} | |||
template<class _Awaitable, class _Ty> | |||
future_t<> when_all_connector(state_when_t* state, _Awaitable awaitor, _Ty& value) | |||
future_t<> when_all_connector(state_when_t* state, _Awaitable task, _Ty& value) | |||
{ | |||
static_assert(traits::is_awaitor_v<_Awaitable>); | |||
decltype(auto) awaitor = when_real_awaitor(task); | |||
if constexpr(std::is_same_v<_Ty, ignore_type>) | |||
co_await awaitor; | |||
@@ -145,12 +166,13 @@ RESUMEF_NS | |||
using when_any_pair_ptr = std::shared_ptr<when_any_pair>; | |||
template<class _Awaitable> | |||
future_t<> when_any_connector(counted_ptr<state_when_t> state, _Awaitable awaitor, when_any_pair_ptr value, intptr_t idx) | |||
future_t<> when_any_connector(counted_ptr<state_when_t> state, _Awaitable task, when_any_pair_ptr value, intptr_t idx) | |||
{ | |||
assert(idx >= 0); | |||
static_assert(traits::is_awaitor_v<_Awaitable>); | |||
using value_type = awaitor_result_t<_Awaitable>; | |||
decltype(auto) awaitor = when_real_awaitor(task); | |||
using value_type = awaitor_result_t<decltype(awaitor)>; | |||
if constexpr (std::is_same_v<value_type, ignore_type>) | |||
{ | |||
@@ -183,7 +205,7 @@ RESUMEF_NS | |||
template<class _Awaitable, class... _Rest> | |||
inline void when_any_one__(scheduler_t& sch, state_when_t* state, when_any_pair_ptr value, intptr_t _Idx, _Awaitable&& awaitable, _Rest&&... rest) | |||
{ | |||
sch + when_any_connector(state, awaitable, value, _Idx); | |||
sch + when_any_connector(state, std::forward<_Awaitable>(awaitable), value, _Idx); | |||
when_any_one__(sch, state, value, _Idx + 1, std::forward<_Rest>(rest)...); | |||
} | |||
@@ -195,7 +217,7 @@ RESUMEF_NS | |||
intptr_t _Idx = 0; | |||
for (; begin != end; ++begin, ++_Idx) | |||
{ | |||
sch + when_any_connector(state, *begin, value, static_cast<intptr_t>(_Idx)); | |||
sch + when_any_connector(state, std::move(*begin), value, static_cast<intptr_t>(_Idx)); | |||
} | |||
} | |||
} | |||
@@ -203,7 +225,7 @@ RESUMEF_NS | |||
inline namespace when_v2 | |||
{ | |||
template<class... _Awaitable, | |||
class = std::enable_if_t<std::conjunction_v<traits::is_awaitor<_Awaitable>...>> | |||
class = std::enable_if_t<std::conjunction_v<detail::is_when_task<_Awaitable>...>> | |||
> | |||
auto when_all(scheduler_t& sch, _Awaitable&&... args) | |||
-> detail::when_future_t<std::tuple<detail::awaitor_result_t<_Awaitable>...> > | |||
@@ -218,7 +240,7 @@ inline namespace when_v2 | |||
template<class _Iter, | |||
class _Awaitable = decltype(*std::declval<_Iter>()), | |||
class = std::enable_if_t<traits::is_awaitor_v<_Awaitable>> | |||
class = std::enable_if_t<detail::is_when_task_v<_Awaitable>> | |||
> | |||
auto when_all(scheduler_t& sch, _Iter begin, _Iter end) | |||
-> detail::when_future_t<std::vector<detail::awaitor_result_t<_Awaitable> > > | |||
@@ -234,7 +256,7 @@ inline namespace when_v2 | |||
} | |||
template<class... _Awaitable, | |||
class = std::enable_if_t<std::conjunction_v<traits::is_awaitor<_Awaitable>...>> | |||
class = std::enable_if_t<std::conjunction_v<detail::is_when_task<_Awaitable>...>> | |||
> | |||
auto when_all(_Awaitable&&... awaitor) | |||
-> future_t<std::tuple<detail::awaitor_result_t<_Awaitable>...>> | |||
@@ -244,7 +266,7 @@ inline namespace when_v2 | |||
template<class _Iter, | |||
class _Awaitable = decltype(*std::declval<_Iter>()), | |||
class = std::enable_if_t<traits::is_awaitor_v<_Awaitable>> | |||
class = std::enable_if_t<detail::is_when_task_v<_Awaitable>> | |||
> | |||
auto when_all(_Iter begin, _Iter end) | |||
-> future_t<std::vector<detail::awaitor_result_t<_Awaitable>>> | |||
@@ -258,7 +280,7 @@ inline namespace when_v2 | |||
template<class... _Awaitable, | |||
class = std::enable_if_t<std::conjunction_v<traits::is_awaitor<_Awaitable>...>> | |||
class = std::enable_if_t<std::conjunction_v<detail::is_when_task<_Awaitable>...>> | |||
> | |||
auto when_any(scheduler_t& sch, _Awaitable&&... args) | |||
-> detail::when_future_t<detail::when_any_pair> | |||
@@ -272,7 +294,7 @@ inline namespace when_v2 | |||
template<class _Iter, | |||
typename _Awaitable = decltype(*std::declval<_Iter>()), | |||
class = std::enable_if_t<traits::is_awaitor_v<_Awaitable>> | |||
class = std::enable_if_t<detail::is_when_task_v<_Awaitable>> | |||
> | |||
auto when_any(scheduler_t& sch, _Iter begin, _Iter end) | |||
-> detail::when_future_t<detail::when_any_pair> | |||
@@ -285,7 +307,7 @@ inline namespace when_v2 | |||
} | |||
template<class... _Awaitable, | |||
class = std::enable_if_t<std::conjunction_v<traits::is_awaitor<_Awaitable>...>> | |||
class = std::enable_if_t<std::conjunction_v<detail::is_when_task<_Awaitable>...>> | |||
> | |||
auto when_any(_Awaitable&&... awaitor) | |||
-> future_t<detail::when_any_pair> | |||
@@ -295,7 +317,7 @@ inline namespace when_v2 | |||
template<class _Iter, | |||
typename _Awaitable = decltype(*std::declval<_Iter>()), | |||
class = std::enable_if_t<traits::is_awaitor_v<_Awaitable>> | |||
class = std::enable_if_t<detail::is_when_task_v<_Awaitable>> | |||
> | |||
auto when_any(_Iter begin, _Iter end) | |||
-> future_t<detail::when_any_pair> |
@@ -28,26 +28,26 @@ void test_when_any() | |||
std::cout << dt << "@a" << std::endl; | |||
co_return dt; | |||
}(), | |||
}, | |||
[]() ->future_t<> | |||
{ | |||
auto dt = rand() % 1000; | |||
co_await sleep_for(1ms * dt); | |||
std::cout << dt << "@b" << std::endl; | |||
}(), | |||
}, | |||
[]() ->future_t<> | |||
{ | |||
auto dt = rand() % 1000; | |||
co_await sleep_for(1ms * dt); | |||
std::cout << dt << "@c" << std::endl; | |||
}()); | |||
}); | |||
if (vals.first == 0) | |||
std::cout << "first done! value is " << resumef::any_cast<int>(vals.second) << std::endl; | |||
else | |||
std::cout << "any done! index is " << vals.first << std::endl; | |||
co_await sleep_for(1010ms); | |||
co_await 1010ms; | |||
std::cout << std::endl; | |||
auto my_sleep = [](const char * name) -> future_t<int> | |||
@@ -92,20 +92,44 @@ void test_when_all() | |||
co_await when_all(); | |||
std::cout << "when all: zero!" << std::endl << std::endl; | |||
auto vals1 = co_await when_all( | |||
[]() ->future_t<int> | |||
{ | |||
auto dt = rand() % 1000; | |||
co_await sleep_for(1ms * dt); | |||
std::cout << dt << "@i" << std::endl; | |||
co_return dt; | |||
}, | |||
[]() ->future_t<> | |||
{ | |||
auto dt = rand() % 1000; | |||
co_await sleep_for(1ms * dt); | |||
std::cout << dt << "@j" << std::endl; | |||
}, | |||
[]() ->future_t<> | |||
{ | |||
auto dt = rand() % 1000; | |||
co_await sleep_for(1ms * dt); | |||
std::cout << dt << "@k" << std::endl; | |||
}); | |||
std::cout << "when all - 1:" << std::get<0>(vals1) << std::endl << std::endl; | |||
auto ab = co_await when_all(my_sleep("a"), my_sleep_v("b")); | |||
//ab.1 is std::ignore | |||
std::cout << "when all:" << std::get<0>(ab) << std::endl << std::endl; | |||
std::cout << "when all - 2:" << std::get<0>(ab) << std::endl << std::endl; | |||
auto c = co_await my_sleep("c"); | |||
std::cout << "when all:" << c << std::endl << std::endl; | |||
std::cout << "when all - 3:" << c << std::endl << std::endl; | |||
auto def = co_await when_all(my_sleep("d"), my_sleep_v("e"), my_sleep("f")); | |||
//def.1 is std::ignore | |||
std::cout << "when all:" << std::get<0>(def) << "," << std::get<2>(def) << std::endl << std::endl; | |||
std::cout << "when all - 4:" << std::get<0>(def) << "," << std::get<2>(def) << std::endl << std::endl; | |||
std::vector<future_t<int> > v{ my_sleep("g"), my_sleep("h"), my_sleep("i") }; | |||
auto vals = co_await when_all(std::begin(v), std::end(v)); | |||
std::cout << "when all:" << vals[0] << "," << vals[1] << "," << vals[2] << "," << std::endl << std::endl; | |||
std::cout << "when all - 5:" << vals[0] << "," << vals[1] << "," << vals[2] << "," << std::endl << std::endl; | |||
std::cout << "all range done!" << std::endl; | |||
}; |
@@ -247,7 +247,6 @@ | |||
<ClInclude Include="..\librf\src\timer.h" /> | |||
<ClInclude Include="..\librf\src\unix\clang_builtin.h" /> | |||
<ClInclude Include="..\librf\src\unix\coroutine.h" /> | |||
<ClInclude Include="..\librf\src\utils.h" /> | |||
<ClInclude Include="..\librf\src\when.h" /> | |||
<ClInclude Include="..\librf\src\when_v2.h" /> | |||
<ClInclude Include="..\librf\src\_awaker.h" /> |
@@ -165,9 +165,6 @@ | |||
<ClInclude Include="..\librf\src\timer.h"> | |||
<Filter>librf\src</Filter> | |||
</ClInclude> | |||
<ClInclude Include="..\librf\src\utils.h"> | |||
<Filter>librf\src</Filter> | |||
</ClInclude> | |||
<ClInclude Include="..\librf\src\unix\coroutine.h"> | |||
<Filter>librf\src\unix</Filter> | |||
</ClInclude> |