File indexing completed on 2025-01-30 10:03:45
0001
0002
0003
0004
0005 #ifndef CPPCORO_DETAIL_SYNC_WAIT_TASK_HPP_INCLUDED
0006 #define CPPCORO_DETAIL_SYNC_WAIT_TASK_HPP_INCLUDED
0007
0008 #include <cppcoro/config.hpp>
0009 #include <cppcoro/awaitable_traits.hpp>
0010 #include <cppcoro/detail/lightweight_manual_reset_event.hpp>
0011
0012 #include <cppcoro/coroutine.hpp>
0013 #include <cassert>
0014 #include <exception>
0015 #include <utility>
0016
0017 namespace cppcoro
0018 {
0019 namespace detail
0020 {
0021 template<typename RESULT>
0022 class sync_wait_task;
0023
0024 template<typename RESULT>
0025 class sync_wait_task_promise final
0026 {
0027 using coroutine_handle_t = cppcoro::coroutine_handle<sync_wait_task_promise<RESULT>>;
0028
0029 public:
0030
0031 using reference = RESULT&&;
0032
0033 sync_wait_task_promise() noexcept
0034 {}
0035
0036 void start(detail::lightweight_manual_reset_event& event)
0037 {
0038 m_event = &event;
0039 coroutine_handle_t::from_promise(*this).resume();
0040 }
0041
0042 auto get_return_object() noexcept
0043 {
0044 return coroutine_handle_t::from_promise(*this);
0045 }
0046
0047 cppcoro::suspend_always initial_suspend() noexcept
0048 {
0049 return{};
0050 }
0051
0052 auto final_suspend() noexcept
0053 {
0054 class completion_notifier
0055 {
0056 public:
0057
0058 bool await_ready() const noexcept { return false; }
0059
0060 void await_suspend(coroutine_handle_t coroutine) const noexcept
0061 {
0062 coroutine.promise().m_event->set();
0063 }
0064
0065 void await_resume() noexcept {}
0066 };
0067
0068 return completion_notifier{};
0069 }
0070
0071 #if CPPCORO_COMPILER_MSVC && CPPCORO_COMPILER_MSVC < 19'20'00000
0072
0073
0074 template<typename Awaitable>
0075 Awaitable&& await_transform(Awaitable&& awaitable)
0076 {
0077 return static_cast<Awaitable&&>(awaitable);
0078 }
0079
0080 struct get_promise_t {};
0081 static constexpr get_promise_t get_promise = {};
0082
0083 auto await_transform(get_promise_t)
0084 {
0085 class awaiter
0086 {
0087 public:
0088 awaiter(sync_wait_task_promise* promise) noexcept : m_promise(promise) {}
0089 bool await_ready() noexcept {
0090 return true;
0091 }
0092 void await_suspend(cppcoro::coroutine_handle<>) noexcept {}
0093 sync_wait_task_promise& await_resume() noexcept
0094 {
0095 return *m_promise;
0096 }
0097 private:
0098 sync_wait_task_promise* m_promise;
0099 };
0100 return awaiter{ this };
0101 }
0102 #endif
0103
0104 auto yield_value(reference result) noexcept
0105 {
0106 m_result = std::addressof(result);
0107 return final_suspend();
0108 }
0109
0110 void return_void() noexcept
0111 {
0112
0113
0114 assert(false);
0115 }
0116
0117 void unhandled_exception()
0118 {
0119 m_exception = std::current_exception();
0120 }
0121
0122 reference result()
0123 {
0124 if (m_exception)
0125 {
0126 std::rethrow_exception(m_exception);
0127 }
0128
0129 return static_cast<reference>(*m_result);
0130 }
0131
0132 private:
0133
0134 detail::lightweight_manual_reset_event* m_event;
0135 std::remove_reference_t<RESULT>* m_result;
0136 std::exception_ptr m_exception;
0137
0138 };
0139
0140 template<>
0141 class sync_wait_task_promise<void>
0142 {
0143 using coroutine_handle_t = cppcoro::coroutine_handle<sync_wait_task_promise<void>>;
0144
0145 public:
0146
0147 sync_wait_task_promise() noexcept
0148 {}
0149
0150 void start(detail::lightweight_manual_reset_event& event)
0151 {
0152 m_event = &event;
0153 coroutine_handle_t::from_promise(*this).resume();
0154 }
0155
0156 auto get_return_object() noexcept
0157 {
0158 return coroutine_handle_t::from_promise(*this);
0159 }
0160
0161 cppcoro::suspend_always initial_suspend() noexcept
0162 {
0163 return{};
0164 }
0165
0166 auto final_suspend() noexcept
0167 {
0168 class completion_notifier
0169 {
0170 public:
0171
0172 bool await_ready() const noexcept { return false; }
0173
0174 void await_suspend(coroutine_handle_t coroutine) const noexcept
0175 {
0176 coroutine.promise().m_event->set();
0177 }
0178
0179 void await_resume() noexcept {}
0180 };
0181
0182 return completion_notifier{};
0183 }
0184
0185 void return_void() {}
0186
0187 void unhandled_exception()
0188 {
0189 m_exception = std::current_exception();
0190 }
0191
0192 void result()
0193 {
0194 if (m_exception)
0195 {
0196 std::rethrow_exception(m_exception);
0197 }
0198 }
0199
0200 private:
0201
0202 detail::lightweight_manual_reset_event* m_event;
0203 std::exception_ptr m_exception;
0204
0205 };
0206
0207 template<typename RESULT>
0208 class sync_wait_task final
0209 {
0210 public:
0211
0212 using promise_type = sync_wait_task_promise<RESULT>;
0213
0214 using coroutine_handle_t = cppcoro::coroutine_handle<promise_type>;
0215
0216 sync_wait_task(coroutine_handle_t coroutine) noexcept
0217 : m_coroutine(coroutine)
0218 {}
0219
0220 sync_wait_task(sync_wait_task&& other) noexcept
0221 : m_coroutine(std::exchange(other.m_coroutine, coroutine_handle_t{}))
0222 {}
0223
0224 ~sync_wait_task()
0225 {
0226 if (m_coroutine) m_coroutine.destroy();
0227 }
0228
0229 sync_wait_task(const sync_wait_task&) = delete;
0230 sync_wait_task& operator=(const sync_wait_task&) = delete;
0231
0232 void start(lightweight_manual_reset_event& event) noexcept
0233 {
0234 m_coroutine.promise().start(event);
0235 }
0236
0237 decltype(auto) result()
0238 {
0239 return m_coroutine.promise().result();
0240 }
0241
0242 private:
0243
0244 coroutine_handle_t m_coroutine;
0245
0246 };
0247
0248 #if CPPCORO_COMPILER_MSVC && CPPCORO_COMPILER_MSVC < 19'20'00000
0249
0250
0251
0252
0253 template<
0254 typename AWAITABLE,
0255 typename RESULT = typename cppcoro::awaitable_traits<AWAITABLE&&>::await_result_t,
0256 std::enable_if_t<!std::is_void_v<RESULT>, int> = 0>
0257 sync_wait_task<RESULT> make_sync_wait_task(AWAITABLE& awaitable)
0258 {
0259
0260
0261
0262
0263
0264 auto& promise = co_await sync_wait_task_promise<RESULT>::get_promise;
0265 co_await promise.yield_value(co_await std::forward<AWAITABLE>(awaitable));
0266
0267
0268 }
0269
0270 template<
0271 typename AWAITABLE,
0272 typename RESULT = typename cppcoro::awaitable_traits<AWAITABLE&&>::await_result_t,
0273 std::enable_if_t<std::is_void_v<RESULT>, int> = 0>
0274 sync_wait_task<void> make_sync_wait_task(AWAITABLE& awaitable)
0275 {
0276 co_await static_cast<AWAITABLE&&>(awaitable);
0277 }
0278 #else
0279 template<
0280 typename AWAITABLE,
0281 typename RESULT = typename cppcoro::awaitable_traits<AWAITABLE&&>::await_result_t,
0282 std::enable_if_t<!std::is_void_v<RESULT>, int> = 0>
0283 sync_wait_task<RESULT> make_sync_wait_task(AWAITABLE&& awaitable)
0284 {
0285 co_yield co_await std::forward<AWAITABLE>(awaitable);
0286 }
0287
0288 template<
0289 typename AWAITABLE,
0290 typename RESULT = typename cppcoro::awaitable_traits<AWAITABLE&&>::await_result_t,
0291 std::enable_if_t<std::is_void_v<RESULT>, int> = 0>
0292 sync_wait_task<void> make_sync_wait_task(AWAITABLE&& awaitable)
0293 {
0294 co_await std::forward<AWAITABLE>(awaitable);
0295 }
0296 #endif
0297 }
0298 }
0299
0300 #endif