Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-30 10:03:45

0001 ///////////////////////////////////////////////////////////////////////////////
0002 // Copyright (c) Lewis Baker
0003 // Licenced under MIT license. See LICENSE.txt for details.
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