@@ -79,4 +79,5 @@ RESUMEF_NS | |||
#include "exception.inl" | |||
#include "type_traits.inl" | |||
#include "type_concept.inl" | |||
#include "macro_def.inl" |
@@ -30,7 +30,10 @@ RESUMEF_NS | |||
void run(); | |||
//void break_all(); | |||
template<class _Ty, typename = std::enable_if_t<traits::is_callable_v<_Ty> || traits::is_future_v<_Ty> || traits::is_generator_v<_Ty> >> | |||
template<class _Ty | |||
COMMA_RESUMEF_ENABLE_IF(traits::is_callable_v<_Ty> || traits::is_future_v<_Ty> || traits::is_generator_v<_Ty>) | |||
> | |||
RESUMEF_REQUIRES(traits::is_callable_v<_Ty> || traits::is_future_v<_Ty> || traits::is_generator_v<_Ty>) | |||
inline void operator + (_Ty&& t_) | |||
{ | |||
if constexpr (traits::is_callable_v<_Ty>) |
@@ -0,0 +1,70 @@ | |||
#pragma once | |||
#include <concepts> | |||
RESUMEF_NS | |||
{ | |||
#define RESUMEF_ENABLE_CONCEPT 1 | |||
#if RESUMEF_ENABLE_CONCEPT | |||
template<typename T> | |||
concept _AwaitorT = requires(T && v) | |||
{ | |||
{ v.await_ready() } -> bool; | |||
{ v.await_suspend(std::declval<std::experimental::coroutine_handle<promise_t<>>>()) }; | |||
{ v.await_resume() }; | |||
}; | |||
template<typename T> | |||
concept _HasStateT = _AwaitorT<T> && requires(T && v) | |||
{ | |||
{ v._state }; | |||
}; | |||
template<typename T> | |||
concept _FutureT = _AwaitorT<T> && _HasStateT<T> && requires | |||
{ | |||
{ T::value_type }; | |||
{ T::state_type }; | |||
{ T::promise_type }; | |||
}; | |||
template<typename T> | |||
concept _CallableT = std::invocable<T>; | |||
template<typename T> | |||
concept _GeneratorT = std::is_same_v<T, generator_t<_Ty>>; | |||
template<typename T> | |||
concept _WhenTaskT = _AwaitorT<T> || _CallableT<T>; | |||
template<typename T> | |||
concept _WhenIterT = requires(T&& u, T&& v) | |||
{ | |||
{ ++u } -> T; | |||
{ u != v } -> bool; | |||
{ *u }; | |||
//requires _WhenTaskT<*u>; | |||
}; | |||
#define COMMA_RESUMEF_ENABLE_IF(...) ,typename=std::enable_if_t<__VA_ARGS__> | |||
#define RESUMEF_ENABLE_IF(...) typename=std::enable_if_t<__VA_ARGS__> | |||
#define RESUMEF_REQUIRES(...) requires __VA_ARGS__ | |||
#else | |||
#define _AwaitorT typename | |||
#define _HasStateT typename | |||
#define _FutureT typename | |||
#define _CallableT typename | |||
#define _GeneratorT typename | |||
#define _WhenTaskT typename | |||
#define _WhenIterT typename | |||
#define COMMA_RESUMEF_ENABLE_IF(...) ,typename=std::enable_if_t<__VA_ARGS__> | |||
#define RESUMEF_ENABLE_IF(...) typename=std::enable_if_t<__VA_ARGS__> | |||
#define RESUMEF_REQUIRES(...) | |||
#endif | |||
} |
@@ -163,21 +163,35 @@ RESUMEF_NS | |||
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; | |||
template<typename _Ty, class = std::void_t<>> | |||
struct is_callable : std::false_type{}; | |||
template<typename _Ty> | |||
struct is_callable<_Ty, std::void_t<decltype(std::declval<_Ty>()())>> : std::true_type {}; | |||
template<typename _Ty> | |||
constexpr bool is_callable_v = is_callable<_Ty>::value; | |||
template<class _Ty, class = std::void_t<>> | |||
struct is_iterator : std::false_type {}; | |||
template<class _Ty> | |||
struct is_iterator | |||
<_Ty, | |||
std::void_t< | |||
decltype(++std::declval<_Ty>()) | |||
, decltype(std::declval<_Ty>() != std::declval<_Ty>()) | |||
, decltype(*std::declval<_Ty>()) | |||
> | |||
> | |||
: std::true_type{}; | |||
template<class _Ty> | |||
struct is_iterator<_Ty&> : is_iterator<_Ty> {}; | |||
template<class _Ty> | |||
struct is_iterator<_Ty&&> : is_iterator<_Ty> {}; | |||
template<class _Ty> | |||
struct is_iterator<const _Ty> : is_iterator<_Ty> {}; | |||
template<class _Ty> | |||
struct is_iterator<const _Ty&> : is_iterator<_Ty> {}; | |||
template<class _Ty> | |||
constexpr bool is_iterator_v = is_iterator<remove_cvref_t<_Ty>>::value; | |||
} | |||
} |
@@ -107,7 +107,7 @@ RESUMEF_NS | |||
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; | |||
using awaitor_result_t = typename awaitor_result_impl<std::remove_reference_t<_Ty>>::value_type; | |||
template<class _Ty> | |||
@@ -222,11 +222,11 @@ RESUMEF_NS | |||
inline namespace when_v2 | |||
{ | |||
template<class... _Awaitable, | |||
class = std::enable_if_t<std::conjunction_v<detail::is_when_task<_Awaitable>...>> | |||
template<_WhenTaskT... _Awaitable | |||
COMMA_RESUMEF_ENABLE_IF(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>...> > | |||
decltype(auto) when_all(scheduler_t& sch, _Awaitable&&... args) | |||
// -> detail::when_future_t<std::tuple<detail::awaitor_result_t<_Awaitable>...> > | |||
{ | |||
using tuple_type = std::tuple<detail::awaitor_result_t<_Awaitable>...>; | |||
@@ -236,14 +236,13 @@ inline namespace when_v2 | |||
return awaitor; | |||
} | |||
template<class _Iter, | |||
class _Awaitable = decltype(*std::declval<_Iter>()), | |||
class = std::enable_if_t<detail::is_when_task_v<_Awaitable>> | |||
template<_WhenIterT _Iter | |||
COMMA_RESUMEF_ENABLE_IF(traits::is_iterator_v<_Iter> && detail::is_when_task_v<decltype(*std::declval<_Iter>())>) | |||
> | |||
auto when_all(scheduler_t& sch, _Iter begin, _Iter end) | |||
-> detail::when_future_t<std::vector<detail::awaitor_result_t<_Awaitable> > > | |||
auto when_all(scheduler_t& sch, _Iter begin, _Iter end) | |||
// -> detail::when_future_t<std::vector<detail::awaitor_result_t<decltype(*std::declval<_Iter>())> > > | |||
{ | |||
using value_type = detail::awaitor_result_t<_Awaitable>; | |||
using value_type = detail::awaitor_result_t<decltype(*std::declval<_Iter>())>; | |||
using vector_type = std::vector<value_type>; | |||
detail::when_future_t<vector_type> awaitor{ std::distance(begin, end) }; | |||
@@ -253,8 +252,8 @@ inline namespace when_v2 | |||
return awaitor; | |||
} | |||
template<class... _Awaitable, | |||
class = std::enable_if_t<std::conjunction_v<detail::is_when_task<_Awaitable>...>> | |||
template<_WhenTaskT... _Awaitable | |||
COMMA_RESUMEF_ENABLE_IF(std::conjunction_v<detail::is_when_task<_Awaitable>...>) | |||
> | |||
auto when_all(_Awaitable&&... awaitor) | |||
-> future_t<std::tuple<detail::awaitor_result_t<_Awaitable>...>> | |||
@@ -262,12 +261,11 @@ inline namespace when_v2 | |||
co_return co_await when_all(*current_scheduler(), std::forward<_Awaitable>(awaitor)...); | |||
} | |||
template<class _Iter, | |||
class _Awaitable = decltype(*std::declval<_Iter>()), | |||
class = std::enable_if_t<detail::is_when_task_v<_Awaitable>> | |||
template<_WhenIterT _Iter | |||
COMMA_RESUMEF_ENABLE_IF(traits::is_iterator_v<_Iter> && detail::is_when_task_v<decltype(*std::declval<_Iter>())>) | |||
> | |||
auto when_all(_Iter begin, _Iter end) | |||
-> future_t<std::vector<detail::awaitor_result_t<_Awaitable>>> | |||
auto when_all(_Iter begin, _Iter end) | |||
-> future_t<std::vector<detail::awaitor_result_t<decltype(*std::declval<_Iter>())>>> | |||
{ | |||
co_return co_await when_all(*current_scheduler(), begin, end); | |||
} | |||
@@ -277,11 +275,11 @@ inline namespace when_v2 | |||
template<class... _Awaitable, | |||
class = std::enable_if_t<std::conjunction_v<detail::is_when_task<_Awaitable>...>> | |||
template<_WhenTaskT... _Awaitable | |||
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<detail::when_any_pair> | |||
{ | |||
detail::when_future_t<detail::when_any_pair> awaitor{ sizeof...(_Awaitable) > 0 ? 1 : 0 }; | |||
awaitor._values->first = -1; | |||
@@ -290,11 +288,10 @@ inline namespace when_v2 | |||
return awaitor; | |||
} | |||
template<class _Iter, | |||
typename _Awaitable = decltype(*std::declval<_Iter>()), | |||
class = std::enable_if_t<detail::is_when_task_v<_Awaitable>> | |||
template<_WhenIterT _Iter | |||
COMMA_RESUMEF_ENABLE_IF(traits::is_iterator_v<_Iter> && detail::is_when_task_v<decltype(*std::declval<_Iter>())>) | |||
> | |||
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> awaitor{ begin == end ? 0 : 1 }; | |||
@@ -304,8 +301,8 @@ inline namespace when_v2 | |||
return awaitor; | |||
} | |||
template<class... _Awaitable, | |||
class = std::enable_if_t<std::conjunction_v<detail::is_when_task<_Awaitable>...>> | |||
template<_WhenTaskT... _Awaitable | |||
COMMA_RESUMEF_ENABLE_IF(std::conjunction_v<detail::is_when_task<_Awaitable>...>) | |||
> | |||
auto when_any(_Awaitable&&... awaitor) | |||
-> future_t<detail::when_any_pair> | |||
@@ -313,9 +310,8 @@ inline namespace when_v2 | |||
co_return co_await when_any(*current_scheduler(), std::forward<_Awaitable>(awaitor)...); | |||
} | |||
template<class _Iter, | |||
typename _Awaitable = decltype(*std::declval<_Iter>()), | |||
class = std::enable_if_t<detail::is_when_task_v<_Awaitable>> | |||
template<_WhenIterT _Iter | |||
COMMA_RESUMEF_ENABLE_IF(traits::is_iterator_v<_Iter> && detail::is_when_task_v<decltype(*std::declval<_Iter>())>) | |||
> | |||
auto when_any(_Iter begin, _Iter end) | |||
-> future_t<detail::when_any_pair> |
@@ -44,7 +44,7 @@ int main(int argc, const char* argv[]) | |||
//test_ring_queue<resumef::ring_queue_lockfree<int, uint64_t>>(); | |||
//resumable_main_switch_scheduler(); | |||
//resumable_main_when_all(); | |||
resumable_main_when_all(); | |||
//resumable_main_event_v2(); | |||
//return 0; | |||
@@ -40,13 +40,13 @@ | |||
</PropertyGroup> | |||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> | |||
<ConfigurationType>Application</ConfigurationType> | |||
<PlatformToolset>ClangCL</PlatformToolset> | |||
<PlatformToolset>v142</PlatformToolset> | |||
<UseDebugLibraries>true</UseDebugLibraries> | |||
</PropertyGroup> | |||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> | |||
<ConfigurationType>Application</ConfigurationType> | |||
<UseDebugLibraries>false</UseDebugLibraries> | |||
<PlatformToolset>ClangCL</PlatformToolset> | |||
<PlatformToolset>v142</PlatformToolset> | |||
<WholeProgramOptimization>true</WholeProgramOptimization> | |||
<CharacterSet>NotSet</CharacterSet> | |||
</PropertyGroup> | |||
@@ -262,6 +262,7 @@ | |||
<None Include="..\librf\src\macro_def.inl" /> | |||
<None Include="..\librf\src\promise.inl" /> | |||
<None Include="..\librf\src\state.inl" /> | |||
<None Include="..\librf\src\type_concept.inl" /> | |||
<None Include="..\librf\src\type_traits.inl" /> | |||
<None Include="..\README.md" /> | |||
</ItemGroup> |
@@ -258,5 +258,8 @@ | |||
<None Include="..\librf\src\event_v2.inl"> | |||
<Filter>librf\src</Filter> | |||
</None> | |||
<None Include="..\librf\src\type_concept.inl"> | |||
<Filter>librf\src</Filter> | |||
</None> | |||
</ItemGroup> | |||
</Project> |