gather.h

#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

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值