#endif | #endif | ||||
#include "src/def.h" | #include "src/def.h" | ||||
#include "src/macro_def.inl" | |||||
#include "src/spinlock.h" | #include "src/spinlock.h" | ||||
#include "src/counted_ptr.h" | #include "src/counted_ptr.h" | ||||
#include "src/type_traits.inl" | |||||
#include "src/type_concept.inl" | |||||
#include "src/state.h" | #include "src/state.h" | ||||
#include "src/future.h" | #include "src/future.h" | ||||
#include "src/promise.h" | #include "src/promise.h" |
} | } | ||||
#include "exception.inl" | #include "exception.inl" | ||||
#include "type_traits.inl" | |||||
#include "type_concept.inl" | |||||
#include "macro_def.inl" |
{ | { | ||||
return e.wait_for(dt); | return e.wait_for(dt); | ||||
} | } | ||||
template<class _Clock, class _Duration> | |||||
template<class _Clock, class _Duration> | |||||
auto wait_until(event_v2::event_t& e, const std::chrono::time_point<_Clock, _Duration>& tp) | auto wait_until(event_v2::event_t& e, const std::chrono::time_point<_Clock, _Duration>& tp) | ||||
{ | { | ||||
return e.wait_until(tp); | return e.wait_until(tp); |
#pragma once | #pragma once | ||||
#ifndef RESUMEF_ENABLE_CONCEPT | |||||
#define RESUMEF_ENABLE_CONCEPT 0 | |||||
#endif | |||||
#if RESUMEF_ENABLE_CONCEPT | |||||
#include <concepts> | #include <concepts> | ||||
#endif | |||||
RESUMEF_NS | RESUMEF_NS | ||||
{ | { | ||||
#ifndef RESUMEF_ENABLE_CONCEPT | |||||
#define RESUMEF_ENABLE_CONCEPT 1 | |||||
#endif | |||||
#if RESUMEF_ENABLE_CONCEPT | #if RESUMEF_ENABLE_CONCEPT | ||||
concept _HasStateT = requires(T && v) | concept _HasStateT = requires(T && v) | ||||
{ | { | ||||
{ v._state }; | { v._state }; | ||||
{ traits::is_state_pointer_v<decltype(v._state)> != false }; | |||||
}; | }; | ||||
template<typename T> | template<typename T> | ||||
concept _WhenTaskT = _AwaitorT<T> || _CallableT<T>; | concept _WhenTaskT = _AwaitorT<T> || _CallableT<T>; | ||||
template<typename T> | template<typename T> | ||||
concept _WhenIterT = requires(T&& u, T&& v) | |||||
concept _IteratorT = requires(T && u, T && v) | |||||
{ | { | ||||
{ ++u } -> T; | |||||
{ ++u }->T; | |||||
{ u != v } -> bool; | { u != v } -> bool; | ||||
{ *u }; | { *u }; | ||||
}; | |||||
template<typename T> | |||||
concept _WhenIterT = _IteratorT<T> && requires(T&& u, T&& v) | |||||
{ | |||||
requires _WhenTaskT<decltype(*u)>; | requires _WhenTaskT<decltype(*u)>; | ||||
}; | }; | ||||
template<typename T> | |||||
concept _ContainerT = requires(T && v) | |||||
{ | |||||
{ std::begin(v) }; | |||||
{ std::end(v) }; | |||||
requires std::same_as<decltype(std::begin(v)), decltype(std::end(v))>; | |||||
requires _IteratorT<decltype(std::begin(v))>; | |||||
requires _IteratorT<decltype(std::end(v))>; | |||||
}; | |||||
#define COMMA_RESUMEF_ENABLE_IF(...) | #define COMMA_RESUMEF_ENABLE_IF(...) | ||||
#define RESUMEF_ENABLE_IF(...) | #define RESUMEF_ENABLE_IF(...) | ||||
#define RESUMEF_REQUIRES(...) requires __VA_ARGS__ | #define RESUMEF_REQUIRES(...) requires __VA_ARGS__ | ||||
#define _CallableT typename | #define _CallableT typename | ||||
#define _GeneratorT typename | #define _GeneratorT typename | ||||
#define _WhenTaskT typename | #define _WhenTaskT typename | ||||
#define _IteratorT typename | |||||
#define _WhenIterT typename | #define _WhenIterT typename | ||||
#define _ContainerT typename | |||||
#define COMMA_RESUMEF_ENABLE_IF(...) ,typename=std::enable_if_t<__VA_ARGS__> | #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_ENABLE_IF(...) typename=std::enable_if_t<__VA_ARGS__> |
template<class _Ty> | template<class _Ty> | ||||
constexpr bool is_generator_v = is_generator<remove_cvref_t<_Ty>>::value; | constexpr bool is_generator_v = is_generator<remove_cvref_t<_Ty>>::value; | ||||
template<class _Ty, class = std::void_t<>> | |||||
struct is_state_pointer : std::false_type {}; | |||||
template<class _Ty> | |||||
struct is_state_pointer<_Ty, std::void_t<std::enable_if_t<std::is_convertible_v<_Ty, state_base_t*>>>> : std::true_type {}; | |||||
template<class _Ty> | |||||
struct is_state_pointer<counted_ptr<_Ty>> : is_state_pointer<_Ty> {}; | |||||
template<class _Ty> | |||||
constexpr bool is_state_pointer_v = is_state_pointer<remove_cvref_t<_Ty>>::value; | |||||
template<class _Ty, class = std::void_t<>> | template<class _Ty, class = std::void_t<>> | ||||
struct has_state : std::false_type {}; | struct has_state : std::false_type {}; | ||||
template<class _Ty> | template<class _Ty> | ||||
> | > | ||||
: std::true_type{}; | : std::true_type{}; | ||||
template<class _Ty> | 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> {}; | |||||
constexpr bool is_iterator_v = is_iterator<remove_cvref_t<_Ty>>::value; | |||||
template<class _Ty, class = std::void_t<>> | |||||
struct is_container : std::false_type {}; | |||||
template<class _Ty> | template<class _Ty> | ||||
constexpr bool is_iterator_v = is_iterator<remove_cvref_t<_Ty>>::value; | |||||
struct is_container | |||||
<_Ty, | |||||
std::void_t< | |||||
decltype(std::begin(std::declval<_Ty>())) | |||||
, decltype(std::end(std::declval<_Ty>())) | |||||
> | |||||
> | |||||
: is_iterator<decltype(std::begin(std::declval<_Ty>()))> {}; | |||||
template<class _Ty> | |||||
constexpr bool is_container_v = is_container<remove_cvref_t<_Ty>>::value; | |||||
} | } | ||||
} | } |
template<class _Ty> | template<class _Ty> | ||||
constexpr bool is_when_task_v = is_when_task<_Ty>::value; | constexpr bool is_when_task_v = is_when_task<_Ty>::value; | ||||
template<class _Ty> | |||||
constexpr bool is_when_task_iter_v = traits::is_iterator_v<_Ty> | |||||
&& is_when_task_v<decltype(*std::declval<_Ty>())>; | |||||
template<class _Ty, class _Task = decltype(*std::declval<_Ty>())> | |||||
constexpr bool is_when_task_iter_v = traits::is_iterator_v<_Ty> && is_when_task_v<_Task>; | |||||
template<_WhenTaskT _Awaitable> | template<_WhenTaskT _Awaitable> | ||||
decltype(auto) when_real_awaitor(_Awaitable&& awaitor) | decltype(auto) when_real_awaitor(_Awaitable&& awaitor) | ||||
return awaitor; | return awaitor; | ||||
} | } | ||||
template<_ContainerT _Cont | |||||
COMMA_RESUMEF_ENABLE_IF(traits::is_container_v<_Cont>) | |||||
> | |||||
decltype(auto) when_all(scheduler_t& sch, _Cont& cont) | |||||
{ | |||||
return when_all(sch, std::begin(cont), std::end(cont)); | |||||
} | |||||
template<_WhenTaskT... _Awaitable | template<_WhenTaskT... _Awaitable | ||||
COMMA_RESUMEF_ENABLE_IF(std::conjunction_v<detail::is_when_task<_Awaitable>...>) | COMMA_RESUMEF_ENABLE_IF(std::conjunction_v<detail::is_when_task<_Awaitable>...>) | ||||
> | > | ||||
co_return co_await when_all(*current_scheduler(), begin, end); | co_return co_await when_all(*current_scheduler(), begin, end); | ||||
} | } | ||||
template<_ContainerT _Cont | |||||
COMMA_RESUMEF_ENABLE_IF(traits::is_container_v<_Cont>) | |||||
> | |||||
decltype(auto) when_all(_Cont& cont) | |||||
{ | |||||
return when_all(std::begin(cont), std::end(cont)); | |||||
} | |||||
template<_WhenTaskT... _Awaitable | template<_WhenTaskT... _Awaitable | ||||
return awaitor; | return awaitor; | ||||
} | } | ||||
template<_ContainerT _Cont | |||||
COMMA_RESUMEF_ENABLE_IF(traits::is_container_v<_Cont>) | |||||
> | |||||
decltype(auto) when_any(scheduler_t& sch, _Cont& cont) | |||||
{ | |||||
return when_any(sch, std::begin(cont), std::end(cont)); | |||||
} | |||||
template<_WhenTaskT... _Awaitable | template<_WhenTaskT... _Awaitable | ||||
COMMA_RESUMEF_ENABLE_IF(std::conjunction_v<detail::is_when_task<_Awaitable>...>) | COMMA_RESUMEF_ENABLE_IF(std::conjunction_v<detail::is_when_task<_Awaitable>...>) | ||||
> | > | ||||
co_return co_await when_any(*current_scheduler(), begin, end); | co_return co_await when_any(*current_scheduler(), begin, end); | ||||
} | } | ||||
template<_ContainerT _Cont | |||||
COMMA_RESUMEF_ENABLE_IF(traits::is_container_v<_Cont>) | |||||
> | |||||
decltype(auto) when_any(_Cont& cont) | |||||
{ | |||||
return when_any(std::begin(cont), std::end(cont)); | |||||
} | |||||
} | } | ||||
} | } |
#include "librf.h" | #include "librf.h" | ||||
#if _HAS_CXX17 || RESUMEF_USE_BOOST_ANY | |||||
using namespace resumef; | using namespace resumef; | ||||
/* | |||||
void test_when_any() | void test_when_any() | ||||
{ | { | ||||
using namespace std::chrono; | using namespace std::chrono; | ||||
}; | }; | ||||
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") }; | ||||
vals = co_await when_any(std::begin(v), std::end(v)); | |||||
//vals = co_await when_any(*this_scheduler(), std::begin(v), std::end(v)); | |||||
//vals = co_await when_any(std::begin(v), std::end(v)); | |||||
vals = co_await when_any(v); | |||||
std::cout << "any range done! index is " << vals.first << ", valus is " << resumef::any_cast<int>(vals.second) << std::endl; | std::cout << "any range done! index is " << vals.first << ", valus is " << resumef::any_cast<int>(vals.second) << std::endl; | ||||
}; | }; | ||||
this_scheduler()->run_until_notask(); | this_scheduler()->run_until_notask(); | ||||
} | } | ||||
*/ | |||||
void test_when_all() | void test_when_all() | ||||
{ | { | ||||
GO | GO | ||||
{ | { | ||||
/* | |||||
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 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 - 4:" << 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(*this_scheduler(), std::begin(v), std::end(v)); | |||||
//std::cout << "when all - 5:" << vals[0] << "," << vals[1] << "," << vals[2] << "," << std::endl << std::endl; | |||||
//auto vals = co_await when_all(*this_scheduler(), std::begin(v), std::end(v)); | |||||
//auto vals = co_await when_all(*this_scheduler(), v); | |||||
auto vals = co_await when_all(v); | |||||
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; | |||||
}; | }; | ||||
this_scheduler()->run_until_notask(); | this_scheduler()->run_until_notask(); | ||||
} | } | ||||
#endif | |||||
void resumable_main_when_all() | void resumable_main_when_all() | ||||
{ | { | ||||
#if _HAS_CXX17 || RESUMEF_USE_BOOST_ANY | |||||
srand((uint32_t)time(nullptr)); | srand((uint32_t)time(nullptr)); | ||||
//test_when_any(); | |||||
test_when_any(); | |||||
std::cout << std::endl; | std::cout << std::endl; | ||||
test_when_all(); | test_when_all(); | ||||
#endif | |||||
} | } | ||||