#ifndef ASYNCIO_GATHER_H
#define ASYNCIO_GATHER_H
#include <asyncio/task.h>
#include <asyncio/void_value.h>
#include <asyncio/noncopyable.h>
#include <asyncio/concept/awaitable.h>
#include <stdexcept>
#include <tuple>
#include <variant>
namespace ASYNCIO_NS {
namespace detail {
template<typename... Rs>
class GatherAwaiter: NonCopyable {
using ResultTypes = std::tuple<GetTypeIfVoid_t<Rs>...>;
public:
constexpr bool await_ready() noexcept { return is_finished(); }
constexpr auto await_resume() const {
if (auto exception = std::get_if<std::exception_ptr>(&result_)) { // 要么抛出异常
std::rethrow_exception(*exception);
}
if (auto res = std::get_if<ResultTypes>(&result_)) { return *res; } // 要么返回结果
throw std::runtime_error("result is unset");
}
template<typename Promise>
void await_suspend(std::coroutine_handle<Promise> continuation) noexcept {
continuation_ = &continuation.promise(); // 等待gather的协程的句柄
// set continuation_ to SUSPEND, don't schedule anymore, until it resume continuation_
continuation_->set_state(Handle::SUSPEND); // 将当前协程的句柄状态设置为suspend
}
template<concepts::Awaitable... Futs>
explicit GatherAwaiter(Futs&&... futs) // (委托)构造函数
: GatherAwaiter(std::make_index_sequence<sizeof...(Futs)>{}, std::forward<Futs>(futs)...) {}
private:
/*
在C++中,可变模板参数是一种模板,它可以接受任意数量的参数。这些参数可以是类型,也可以是非类型参数。
例如,"concepts::Awaitable... Futs"和"size_t ...Is"就是可变模板参数。
在这个例子中,"concepts::Awaitable... Futs"表示可以接受任意数量的满足Awaitable概念的参数,"size_t
...Is"表示可以接受任意数量的size_t类型的参数。
"std::make_tuple(collect_result<Is>(no_wait_at_initial_suspend,
std::forward<Futs>(futs))...)"是一个编译时展开的例程,它会为每一个Futs创建一个元组,并将其放入tasks_中。
这是C++17引入的新特性,叫做参数包。
*/
template<concepts::Awaitable... Futs, size_t ...Is>
explicit GatherAwaiter(std::index_sequence<Is...>, Futs&&... futs) // 构造函数
: tasks_{ std::make_tuple(collect_result<Is>(no_wait_at_initial_suspend, std::forward<Futs>(futs))...) } // 它使用了折叠表达式来展开参数包 futs 中的每个元素,并调用 collect_result 函数对它们进行处理,然后将结果存储在 tasks_ 成员变量中。
{ }
template<size_t Idx, concepts::Awaitable Fut>
Task<> collect_result(NoWaitAtInitialSuspend, Fut&& fut) {
try {
auto& results = std::get<ResultTypes>(result_);
// co_await等待结果
if constexpr (std::is_void_v<AwaitResult<Fut>>) { co_await std::forward<Fut>(fut); } // void
else { std::get<Idx>(results) = std::move(co_await std::forward<Fut>(fut)); } // 收集第Idx个结果
++count_; // 完成一个就++count
} catch(...) {
result_ = std::current_exception();
}
if (is_finished()) { // 已经结束,就将等待gather的协程句柄加入调度
get_event_loop().call_soon(*continuation_);
}
}
private:
bool is_finished() { // 如果全部完成或者执行任务过程中有异常产生,就认为结束了
return (count_ == sizeof...(Rs)
|| std::get_if<std::exception_ptr>(&result_) != nullptr);
}
private:
std::variant<ResultTypes, std::exception_ptr> result_; // 结果
std::tuple<Task<std::void_t<Rs>>...> tasks_; // task列表,等待执行
CoroHandle* continuation_{}; // 等待gather的协程的句柄
int count_{0}; // 已完成的task数量
};
template<concepts::Awaitable... Futs> // C++17 deduction guide
GatherAwaiter(Futs&&...) -> GatherAwaiter<AwaitResult<Futs>...>;
template<concepts::Awaitable... Futs>
struct GatherAwaiterRepositry {
explicit GatherAwaiterRepositry(Futs&&... futs)
: futs_(std::forward<Futs>(futs)...) { }
auto operator co_await() && {
// std:apply: 它允许将一个可调用对象(函数、函数指针、成员函数等)以及一个参数包作为参数,并在调用时展开参数包并将其传递给可调用对象
return std::apply([]<concepts::Awaitable... F>(F&&... f) {
return GatherAwaiter { std::forward<F>(f)... };
}, std::move(futs_));
}
private:
// futs_ to lift Future's lifetime
// 1. if Future is rvalue(Fut&&), then move it to tuple(Fut)
// 2. if Future is xvalue(Fut&&), then move it to tuple(Fut)
// 3. if Future is lvalue(Fut&), then store as lvalue-ref(Fut&)
std::tuple<Futs...> futs_;
};
template<concepts::Awaitable... Futs> // need deduction guide to deduce future type
GatherAwaiterRepositry(Futs&&...) -> GatherAwaiterRepositry<Futs...>;
template<concepts::Awaitable... Futs>
auto gather(NoWaitAtInitialSuspend, Futs&&... futs) // need NoWaitAtInitialSuspend to lift futures lifetime early
-> Task<std::tuple<GetTypeIfVoid_t<AwaitResult<Futs>>...>> { // lift awaitable type(GatherAwaiterRepositry) to coroutine
co_return co_await GatherAwaiterRepositry { std::forward<Futs>(futs)... };
}
}
template<concepts::Awaitable... Futs>
[[nodiscard("discard gather doesn't make sense")]]
auto gather(Futs&&... futs) {
return detail::gather(no_wait_at_initial_suspend, std::forward<Futs>(futs)...);
}
}
#endif // ASYNCIO_GATHER_H
04-10
2377
![](https://csdnimg.cn/release/blogv2/dist/pc/img/readCountWhite.png)
05-15
317
![](https://csdnimg.cn/release/blogv2/dist/pc/img/readCountWhite.png)
“相关推荐”对你有帮助么?
-
非常没帮助
-
没帮助
-
一般
-
有帮助
-
非常有帮助
提交