#include "src/channel.h" | #include "src/channel.h" | ||||
#include "src/scheduler.h" | #include "src/scheduler.h" | ||||
#include "src/sleep.h" | #include "src/sleep.h" | ||||
#if _HAS_CXX17 | |||||
#if _HAS_CXX17 || RESUMEF_USE_BOOST_ANY | |||||
#include "src/when.h" | #include "src/when.h" | ||||
#endif | #endif |
#include "_awaker.h" | #include "_awaker.h" | ||||
#if _HAS_CXX17 | |||||
#if _HAS_CXX17 || RESUMEF_USE_BOOST_ANY | |||||
#include "when.h" | #include "when.h" | ||||
#include <assert.h> | #include <assert.h> |
#pragma once | #pragma once | ||||
#include "_awaker.h" | #include "_awaker.h" | ||||
#if RESUMEF_USE_BOOST_ANY | |||||
#include <boost/any.hpp> | |||||
namespace resumef | |||||
{ | |||||
using any_t = boost::any; | |||||
using boost::any_cast; | |||||
} | |||||
#else | |||||
#include <any> | #include <any> | ||||
namespace resumef | |||||
{ | |||||
using any_t = std::any; | |||||
using std::any_cast; | |||||
} | |||||
#endif | |||||
//纠结过when_any的返回值,是选用index + std::any,还是选用std::variant<>。最终选择了std::any。 | //纠结过when_any的返回值,是选用index + std::any,还是选用std::variant<>。最终选择了std::any。 | ||||
//std::variant<>存在第一个元素不能默认构造的问题,需要使用std::monostate来占位,导致下标不是从0开始。 | //std::variant<>存在第一个元素不能默认构造的问题,需要使用std::monostate来占位,导致下标不是从0开始。 | ||||
inline future_vt operator ()() const | inline future_vt operator ()() const | ||||
{ | { | ||||
if constexpr(std::is_same_v<future_type, future_vt>) | |||||
{ | |||||
co_await _f; | |||||
_val.get() = std::ignore; | |||||
} | |||||
else | |||||
{ | |||||
_val.get() = co_await _f; | |||||
} | |||||
_val.get() = co_await _f; | |||||
_e->signal(); | |||||
} | |||||
}; | |||||
template<class _Ty> | |||||
struct when_all_functor<future_vt, _Ty> | |||||
{ | |||||
using value_type = _Ty; | |||||
using future_type = future_vt; | |||||
when_impl_ptr _e; | |||||
mutable future_type _f; | |||||
mutable std::reference_wrapper<value_type> _val; | |||||
when_all_functor(const detail::when_impl_ptr & e, future_type f, value_type & v) | |||||
: _e(e) | |||||
, _f(std::move(f)) | |||||
, _val(v) | |||||
{} | |||||
when_all_functor(when_all_functor &&) noexcept = default; | |||||
when_all_functor & operator = (const when_all_functor &) = default; | |||||
when_all_functor & operator = (when_all_functor &&) = default; | |||||
inline future_vt operator ()() const | |||||
{ | |||||
co_await _f; | |||||
_val.get() = std::ignore; | |||||
_e->signal(); | _e->signal(); | ||||
} | } | ||||
}; | }; | ||||
return awaitable.get_future(); | return awaitable.get_future(); | ||||
} | } | ||||
using when_any_pair = std::pair<intptr_t, std::any>; | |||||
using when_any_pair = std::pair<intptr_t, any_t>; | |||||
using when_any_result_ptr = std::shared_ptr<when_any_pair>; | using when_any_result_ptr = std::shared_ptr<when_any_pair>; | ||||
template<class _Fty> | template<class _Fty> | ||||
{ | { | ||||
if (_val->first < 0) | if (_val->first < 0) | ||||
{ | { | ||||
if constexpr(std::is_same_v<future_type, future_vt>) | |||||
auto tval = co_await _f; | |||||
if (_val->first < 0) | |||||
{ | { | ||||
co_await _f; | |||||
if (_val->first < 0) | |||||
{ | |||||
_val->first = _Idx; | |||||
_e->signal(); | |||||
} | |||||
_val->first = _Idx; | |||||
_val->second = std::move(tval); | |||||
_e->signal(); | |||||
} | } | ||||
else | |||||
} | |||||
else | |||||
{ | |||||
co_await _f; | |||||
} | |||||
} | |||||
}; | |||||
template<> | |||||
struct when_any_functor<future_vt> | |||||
{ | |||||
using value_type = when_any_pair; | |||||
using future_type = future_vt; | |||||
when_impl_ptr _e; | |||||
mutable future_type _f; | |||||
mutable when_any_result_ptr _val; | |||||
intptr_t _Idx; | |||||
when_any_functor(const when_impl_ptr & e, future_type f, const when_any_result_ptr & v, intptr_t idx) | |||||
: _e(e) | |||||
, _f(std::move(f)) | |||||
, _val(v) | |||||
, _Idx(idx) | |||||
{ | |||||
assert(idx >= 0); | |||||
} | |||||
when_any_functor(when_any_functor &&) noexcept = default; | |||||
when_any_functor & operator = (const when_any_functor &) = default; | |||||
when_any_functor & operator = (when_any_functor &&) = default; | |||||
inline future_vt operator ()() const | |||||
{ | |||||
if (_val->first < 0) | |||||
{ | |||||
co_await _f; | |||||
if (_val->first < 0) | |||||
{ | { | ||||
auto tval = co_await _f; | |||||
if (_val->first < 0) | |||||
{ | |||||
_val->first = _Idx; | |||||
_val->second = std::move(tval); | |||||
_e->signal(); | |||||
} | |||||
_val->first = _Idx; | |||||
_e->signal(); | |||||
} | } | ||||
} | } | ||||
else | else | ||||
template<class... _Fty> | template<class... _Fty> | ||||
auto when_any(scheduler & s, _Fty&&... f) -> future_t<detail::when_any_pair> | auto when_any(scheduler & s, _Fty&&... f) -> future_t<detail::when_any_pair> | ||||
{ | { | ||||
auto vals = std::make_shared<detail::when_any_pair>(-1, std::any{}); | |||||
auto vals = std::make_shared<detail::when_any_pair>(-1, any_t{}); | |||||
return detail::when_any_count(sizeof...(_Fty) ? 1 : 0, vals, s, std::forward<_Fty>(f)...); | return detail::when_any_count(sizeof...(_Fty) ? 1 : 0, vals, s, std::forward<_Fty>(f)...); | ||||
} | } | ||||
template<class _Iter, typename _Fty = decltype(*std::declval<_Iter>())> | template<class _Iter, typename _Fty = decltype(*std::declval<_Iter>())> | ||||
auto when_any(scheduler & s, _Iter begin, _Iter end) -> future_t<detail::when_any_pair> | auto when_any(scheduler & s, _Iter begin, _Iter end) -> future_t<detail::when_any_pair> | ||||
{ | { | ||||
auto vals = std::make_shared<detail::when_any_pair>(-1, std::any{}); | |||||
auto vals = std::make_shared<detail::when_any_pair>(-1, any_t{}); | |||||
return detail::when_any_range((begin != end) ? 1 : 0, vals, s, begin, end); | return detail::when_any_range((begin != end) ? 1 : 0, vals, s, begin, end); | ||||
} | } |
#include "librf.h" | #include "librf.h" | ||||
#if _HAS_CXX17 | |||||
#if _HAS_CXX17 || RESUMEF_USE_BOOST_ANY | |||||
using namespace resumef; | using namespace resumef; | ||||
}()); | }()); | ||||
if (vals.first == 0) | if (vals.first == 0) | ||||
std::cout << "first done! value is " << std::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; | ||||
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(std::begin(v), std::end(v)); | ||||
std::cout << "any range done! index is " << vals.first << ", valus is " << std::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(); | ||||
} | } | ||||
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 [a, b] = co_await when_all(my_sleep("a"), my_sleep_v("b")); | |||||
(void)b; //b is std::ignore | |||||
std::cout << "when all:" << a << 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; | |||||
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:" << c << std::endl << std::endl; | ||||
auto [d, e, f] = co_await when_all(my_sleep("d"), my_sleep_v("e"), my_sleep("f")); | |||||
(void)e; //e is std::ignore | |||||
std::cout << "when all:" << d << "," << f << 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::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)); | ||||
void resumable_main_when_all() | void resumable_main_when_all() | ||||
{ | { | ||||
#if _HAS_CXX17 | |||||
#if _HAS_CXX17 || RESUMEF_USE_BOOST_ANY | |||||
srand((uint32_t)time(nullptr)); | srand((uint32_t)time(nullptr)); | ||||
test_when_any(); | test_when_any(); |
<ClCompile> | <ClCompile> | ||||
<WarningLevel>Level3</WarningLevel> | <WarningLevel>Level3</WarningLevel> | ||||
<Optimization>Disabled</Optimization> | <Optimization>Disabled</Optimization> | ||||
<PreprocessorDefinitions>_DEBUG;_CONSOLE;ASIO_STANDALONE;RESUMEF_DEBUG_COUNTER=0;RESUMEF_ENABLE_MULT_SCHEDULER=1;%(PreprocessorDefinitions)</PreprocessorDefinitions> | |||||
<PreprocessorDefinitions>_DEBUG;_CONSOLE;ASIO_STANDALONE;RESUMEF_DEBUG_COUNTER=0;RESUMEF_ENABLE_MULT_SCHEDULER=1;RESUMEF_USE_BOOST_ANY=1;%(PreprocessorDefinitions)</PreprocessorDefinitions> | |||||
<SDLCheck>true</SDLCheck> | <SDLCheck>true</SDLCheck> | ||||
<AdditionalIncludeDirectories>..\librf;..\..\asio-1.10.6\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> | <AdditionalIncludeDirectories>..\librf;..\..\asio-1.10.6\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> | ||||
<AdditionalOptions>/await</AdditionalOptions> | <AdditionalOptions>/await</AdditionalOptions> |