#include "src/generator.h" | #include "src/generator.h" | ||||
#include "src/rf_task.h" | #include "src/rf_task.h" | ||||
#include "src/utils.h" | |||||
#include "src/timer.h" | #include "src/timer.h" | ||||
#include "src/scheduler.h" | #include "src/scheduler.h" | ||||
{ | { | ||||
return sleep_for_(std::chrono::duration_cast<std::chrono::system_clock::duration>(dt_), scheduler_); | 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> | template<class _Clock, class _Duration = typename _Clock::duration> | ||||
inline future_t<> sleep_until(const std::chrono::time_point<_Clock, _Duration>& tp_, scheduler_t& scheduler_) | 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_); | 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> | template<class _Clock, class _Duration> | ||||
inline future_t<> sleep_until(const std::chrono::time_point<_Clock, _Duration>& tp_) | 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> | template <class Rep, class Period> | ||||
inline future_t<> operator co_await(std::chrono::duration<Rep, Period> dt_) | inline future_t<> operator co_await(std::chrono::duration<Rep, Period> dt_) | ||||
{ | { | ||||
return sleep_for(dt_); | |||||
co_await sleep_for(dt_, *current_scheduler()); | |||||
} | } | ||||
} | } |
{ | { | ||||
namespace traits | 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> | template<class _Ty> | ||||
struct is_coroutine_handle : std::false_type {}; | struct is_coroutine_handle : std::false_type {}; | ||||
template<class _PromiseT> | 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> | template<class _Ty> | ||||
constexpr bool is_coroutine_handle_v = is_coroutine_handle<remove_cvref_t<_Ty>>::value; | constexpr bool is_coroutine_handle_v = is_coroutine_handle<remove_cvref_t<_Ty>>::value; | ||||
using type = decltype(get_awaitor(std::declval<_Ty>())); | using type = decltype(get_awaitor(std::declval<_Ty>())); | ||||
using value_type = decltype(std::declval<type>().await_resume()); | 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; | |||||
} | } | ||||
} | } |
{ | { | ||||
namespace traits | 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; | |||||
} | } | ||||
} | } |
using value_type = ignore_type; | 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> | 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> | 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>) | if constexpr(std::is_same_v<_Ty, ignore_type>) | ||||
co_await awaitor; | co_await awaitor; | ||||
using when_any_pair_ptr = std::shared_ptr<when_any_pair>; | using when_any_pair_ptr = std::shared_ptr<when_any_pair>; | ||||
template<class _Awaitable> | 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); | 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>) | if constexpr (std::is_same_v<value_type, ignore_type>) | ||||
{ | { | ||||
template<class _Awaitable, class... _Rest> | 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) | 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)...); | when_any_one__(sch, state, value, _Idx + 1, std::forward<_Rest>(rest)...); | ||||
} | } | ||||
intptr_t _Idx = 0; | intptr_t _Idx = 0; | ||||
for (; begin != end; ++begin, ++_Idx) | 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)); | |||||
} | } | ||||
} | } | ||||
} | } | ||||
inline namespace when_v2 | inline namespace when_v2 | ||||
{ | { | ||||
template<class... _Awaitable, | 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) | auto when_all(scheduler_t& sch, _Awaitable&&... args) | ||||
-> detail::when_future_t<std::tuple<detail::awaitor_result_t<_Awaitable>...> > | -> detail::when_future_t<std::tuple<detail::awaitor_result_t<_Awaitable>...> > | ||||
template<class _Iter, | template<class _Iter, | ||||
class _Awaitable = decltype(*std::declval<_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) | auto when_all(scheduler_t& sch, _Iter begin, _Iter end) | ||||
-> detail::when_future_t<std::vector<detail::awaitor_result_t<_Awaitable> > > | -> detail::when_future_t<std::vector<detail::awaitor_result_t<_Awaitable> > > | ||||
} | } | ||||
template<class... _Awaitable, | 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) | auto when_all(_Awaitable&&... awaitor) | ||||
-> future_t<std::tuple<detail::awaitor_result_t<_Awaitable>...>> | -> future_t<std::tuple<detail::awaitor_result_t<_Awaitable>...>> | ||||
template<class _Iter, | template<class _Iter, | ||||
class _Awaitable = decltype(*std::declval<_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) | auto when_all(_Iter begin, _Iter end) | ||||
-> future_t<std::vector<detail::awaitor_result_t<_Awaitable>>> | -> future_t<std::vector<detail::awaitor_result_t<_Awaitable>>> | ||||
template<class... _Awaitable, | 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) | auto when_any(scheduler_t& sch, _Awaitable&&... args) | ||||
-> detail::when_future_t<detail::when_any_pair> | -> detail::when_future_t<detail::when_any_pair> | ||||
template<class _Iter, | template<class _Iter, | ||||
typename _Awaitable = decltype(*std::declval<_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) | auto when_any(scheduler_t& sch, _Iter begin, _Iter end) | ||||
-> detail::when_future_t<detail::when_any_pair> | -> detail::when_future_t<detail::when_any_pair> | ||||
} | } | ||||
template<class... _Awaitable, | 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) | auto when_any(_Awaitable&&... awaitor) | ||||
-> future_t<detail::when_any_pair> | -> future_t<detail::when_any_pair> | ||||
template<class _Iter, | template<class _Iter, | ||||
typename _Awaitable = decltype(*std::declval<_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) | auto when_any(_Iter begin, _Iter end) | ||||
-> future_t<detail::when_any_pair> | -> future_t<detail::when_any_pair> |
std::cout << dt << "@a" << std::endl; | std::cout << dt << "@a" << std::endl; | ||||
co_return dt; | co_return dt; | ||||
}(), | |||||
}, | |||||
[]() ->future_t<> | []() ->future_t<> | ||||
{ | { | ||||
auto dt = rand() % 1000; | auto dt = rand() % 1000; | ||||
co_await sleep_for(1ms * dt); | co_await sleep_for(1ms * dt); | ||||
std::cout << dt << "@b" << std::endl; | std::cout << dt << "@b" << std::endl; | ||||
}(), | |||||
}, | |||||
[]() ->future_t<> | []() ->future_t<> | ||||
{ | { | ||||
auto dt = rand() % 1000; | auto dt = rand() % 1000; | ||||
co_await sleep_for(1ms * dt); | co_await sleep_for(1ms * dt); | ||||
std::cout << dt << "@c" << std::endl; | std::cout << dt << "@c" << std::endl; | ||||
}()); | |||||
}); | |||||
if (vals.first == 0) | if (vals.first == 0) | ||||
std::cout << "first done! value is " << resumef::any_cast<int>(vals.second) << std::endl; | std::cout << "first done! value is " << resumef::any_cast<int>(vals.second) << std::endl; | ||||
else | else | ||||
std::cout << "any done! index is " << vals.first << std::endl; | std::cout << "any done! index is " << vals.first << std::endl; | ||||
co_await sleep_for(1010ms); | |||||
co_await 1010ms; | |||||
std::cout << std::endl; | std::cout << std::endl; | ||||
auto my_sleep = [](const char * name) -> future_t<int> | auto my_sleep = [](const char * name) -> future_t<int> | ||||
co_await when_all(); | co_await when_all(); | ||||
std::cout << "when all: zero!" << std::endl << std::endl; | 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")); | auto ab = co_await when_all(my_sleep("a"), my_sleep_v("b")); | ||||
//ab.1 is std::ignore | //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"); | 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")); | auto def = co_await when_all(my_sleep("d"), my_sleep_v("e"), my_sleep("f")); | ||||
//def.1 is std::ignore | //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") }; | 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)); | 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; | std::cout << "all range done!" << std::endl; | ||||
}; | }; |
<ClInclude Include="..\librf\src\timer.h" /> | <ClInclude Include="..\librf\src\timer.h" /> | ||||
<ClInclude Include="..\librf\src\unix\clang_builtin.h" /> | <ClInclude Include="..\librf\src\unix\clang_builtin.h" /> | ||||
<ClInclude Include="..\librf\src\unix\coroutine.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.h" /> | ||||
<ClInclude Include="..\librf\src\when_v2.h" /> | <ClInclude Include="..\librf\src\when_v2.h" /> | ||||
<ClInclude Include="..\librf\src\_awaker.h" /> | <ClInclude Include="..\librf\src\_awaker.h" /> |
<ClInclude Include="..\librf\src\timer.h"> | <ClInclude Include="..\librf\src\timer.h"> | ||||
<Filter>librf\src</Filter> | <Filter>librf\src</Filter> | ||||
</ClInclude> | </ClInclude> | ||||
<ClInclude Include="..\librf\src\utils.h"> | |||||
<Filter>librf\src</Filter> | |||||
</ClInclude> | |||||
<ClInclude Include="..\librf\src\unix\coroutine.h"> | <ClInclude Include="..\librf\src\unix\coroutine.h"> | ||||
<Filter>librf\src\unix</Filter> | <Filter>librf\src\unix</Filter> | ||||
</ClInclude> | </ClInclude> |