File indexing completed on 2025-01-30 10:03:45
0001
0002
0003
0004
0005 #ifndef CPPCORO_DETAIL_WHEN_ALL_READY_AWAITABLE_HPP_INCLUDED
0006 #define CPPCORO_DETAIL_WHEN_ALL_READY_AWAITABLE_HPP_INCLUDED
0007
0008 #include <cppcoro/detail/when_all_counter.hpp>
0009
0010 #include <cppcoro/coroutine.hpp>
0011 #include <tuple>
0012
0013 namespace cppcoro
0014 {
0015 namespace detail
0016 {
0017 template<typename TASK_CONTAINER>
0018 class when_all_ready_awaitable;
0019
0020 template<>
0021 class when_all_ready_awaitable<std::tuple<>>
0022 {
0023 public:
0024
0025 constexpr when_all_ready_awaitable() noexcept {}
0026 explicit constexpr when_all_ready_awaitable(std::tuple<>) noexcept {}
0027
0028 constexpr bool await_ready() const noexcept { return true; }
0029 void await_suspend(cppcoro::coroutine_handle<>) noexcept {}
0030 std::tuple<> await_resume() const noexcept { return {}; }
0031
0032 };
0033
0034 template<typename... TASKS>
0035 class when_all_ready_awaitable<std::tuple<TASKS...>>
0036 {
0037 public:
0038
0039 explicit when_all_ready_awaitable(TASKS&&... tasks)
0040 noexcept(std::conjunction_v<std::is_nothrow_move_constructible<TASKS>...>)
0041 : m_counter(sizeof...(TASKS))
0042 , m_tasks(std::move(tasks)...)
0043 {}
0044
0045 explicit when_all_ready_awaitable(std::tuple<TASKS...>&& tasks)
0046 noexcept(std::is_nothrow_move_constructible_v<std::tuple<TASKS...>>)
0047 : m_counter(sizeof...(TASKS))
0048 , m_tasks(std::move(tasks))
0049 {}
0050
0051 when_all_ready_awaitable(when_all_ready_awaitable&& other) noexcept
0052 : m_counter(sizeof...(TASKS))
0053 , m_tasks(std::move(other.m_tasks))
0054 {}
0055
0056 auto operator co_await() & noexcept
0057 {
0058 struct awaiter
0059 {
0060 awaiter(when_all_ready_awaitable& awaitable) noexcept
0061 : m_awaitable(awaitable)
0062 {}
0063
0064 bool await_ready() const noexcept
0065 {
0066 return m_awaitable.is_ready();
0067 }
0068
0069 bool await_suspend(cppcoro::coroutine_handle<> awaitingCoroutine) noexcept
0070 {
0071 return m_awaitable.try_await(awaitingCoroutine);
0072 }
0073
0074 std::tuple<TASKS...>& await_resume() noexcept
0075 {
0076 return m_awaitable.m_tasks;
0077 }
0078
0079 private:
0080
0081 when_all_ready_awaitable& m_awaitable;
0082
0083 };
0084
0085 return awaiter{ *this };
0086 }
0087
0088 auto operator co_await() && noexcept
0089 {
0090 struct awaiter
0091 {
0092 awaiter(when_all_ready_awaitable& awaitable) noexcept
0093 : m_awaitable(awaitable)
0094 {}
0095
0096 bool await_ready() const noexcept
0097 {
0098 return m_awaitable.is_ready();
0099 }
0100
0101 bool await_suspend(cppcoro::coroutine_handle<> awaitingCoroutine) noexcept
0102 {
0103 return m_awaitable.try_await(awaitingCoroutine);
0104 }
0105
0106 std::tuple<TASKS...>&& await_resume() noexcept
0107 {
0108 return std::move(m_awaitable.m_tasks);
0109 }
0110
0111 private:
0112
0113 when_all_ready_awaitable& m_awaitable;
0114
0115 };
0116
0117 return awaiter{ *this };
0118 }
0119
0120 private:
0121
0122 bool is_ready() const noexcept
0123 {
0124 return m_counter.is_ready();
0125 }
0126
0127 bool try_await(cppcoro::coroutine_handle<> awaitingCoroutine) noexcept
0128 {
0129 start_tasks(std::make_integer_sequence<std::size_t, sizeof...(TASKS)>{});
0130 return m_counter.try_await(awaitingCoroutine);
0131 }
0132
0133 template<std::size_t... INDICES>
0134 void start_tasks(std::integer_sequence<std::size_t, INDICES...>) noexcept
0135 {
0136 (void)std::initializer_list<int>{
0137 (std::get<INDICES>(m_tasks).start(m_counter), 0)...
0138 };
0139 }
0140
0141 when_all_counter m_counter;
0142 std::tuple<TASKS...> m_tasks;
0143
0144 };
0145
0146 template<typename TASK_CONTAINER>
0147 class when_all_ready_awaitable
0148 {
0149 public:
0150
0151 explicit when_all_ready_awaitable(TASK_CONTAINER&& tasks) noexcept
0152 : m_counter(tasks.size())
0153 , m_tasks(std::forward<TASK_CONTAINER>(tasks))
0154 {}
0155
0156 when_all_ready_awaitable(when_all_ready_awaitable&& other)
0157 noexcept(std::is_nothrow_move_constructible_v<TASK_CONTAINER>)
0158 : m_counter(other.m_tasks.size())
0159 , m_tasks(std::move(other.m_tasks))
0160 {}
0161
0162 when_all_ready_awaitable(const when_all_ready_awaitable&) = delete;
0163 when_all_ready_awaitable& operator=(const when_all_ready_awaitable&) = delete;
0164
0165 auto operator co_await() & noexcept
0166 {
0167 class awaiter
0168 {
0169 public:
0170
0171 awaiter(when_all_ready_awaitable& awaitable)
0172 : m_awaitable(awaitable)
0173 {}
0174
0175 bool await_ready() const noexcept
0176 {
0177 return m_awaitable.is_ready();
0178 }
0179
0180 bool await_suspend(cppcoro::coroutine_handle<> awaitingCoroutine) noexcept
0181 {
0182 return m_awaitable.try_await(awaitingCoroutine);
0183 }
0184
0185 TASK_CONTAINER& await_resume() noexcept
0186 {
0187 return m_awaitable.m_tasks;
0188 }
0189
0190 private:
0191
0192 when_all_ready_awaitable& m_awaitable;
0193
0194 };
0195
0196 return awaiter{ *this };
0197 }
0198
0199
0200 auto operator co_await() && noexcept
0201 {
0202 class awaiter
0203 {
0204 public:
0205
0206 awaiter(when_all_ready_awaitable& awaitable)
0207 : m_awaitable(awaitable)
0208 {}
0209
0210 bool await_ready() const noexcept
0211 {
0212 return m_awaitable.is_ready();
0213 }
0214
0215 bool await_suspend(cppcoro::coroutine_handle<> awaitingCoroutine) noexcept
0216 {
0217 return m_awaitable.try_await(awaitingCoroutine);
0218 }
0219
0220 TASK_CONTAINER&& await_resume() noexcept
0221 {
0222 return std::move(m_awaitable.m_tasks);
0223 }
0224
0225 private:
0226
0227 when_all_ready_awaitable& m_awaitable;
0228
0229 };
0230
0231 return awaiter{ *this };
0232 }
0233
0234 private:
0235
0236 bool is_ready() const noexcept
0237 {
0238 return m_counter.is_ready();
0239 }
0240
0241 bool try_await(cppcoro::coroutine_handle<> awaitingCoroutine) noexcept
0242 {
0243 for (auto&& task : m_tasks)
0244 {
0245 task.start(m_counter);
0246 }
0247
0248 return m_counter.try_await(awaitingCoroutine);
0249 }
0250
0251 when_all_counter m_counter;
0252 TASK_CONTAINER m_tasks;
0253
0254 };
0255 }
0256 }
0257
0258 #endif