File indexing completed on 2025-09-16 08:29:50
0001
0002
0003
0004
0005 #ifndef BOOST_COBALT_HANDLER_HPP
0006 #define BOOST_COBALT_HANDLER_HPP
0007
0008 #include <boost/cobalt/this_coro.hpp>
0009 #include <boost/cobalt/unique_handle.hpp>
0010 #include <boost/cobalt/detail/util.hpp>
0011
0012 #include <boost/cobalt/detail/sbo_resource.hpp>
0013 #include <boost/asio/bind_allocator.hpp>
0014 #include <boost/asio/post.hpp>
0015 #include <boost/system/result.hpp>
0016
0017 #include <memory>
0018 #include <optional>
0019
0020 namespace boost::cobalt
0021 {
0022
0023 namespace detail
0024 {
0025
0026 template<typename ... Args>
0027 struct composition_promise;
0028 enum class completed_immediately_t
0029 {
0030 no, maybe, yes, initiating
0031 };
0032
0033 struct completion_handler_noop_executor
0034 {
0035 executor exec;
0036 completed_immediately_t * completed_immediately = nullptr;
0037
0038 template<typename Fn>
0039 void execute(Fn && fn) const
0040 {
0041
0042 if (completed_immediately &&
0043 ((*completed_immediately == completed_immediately_t::initiating)
0044 || (*completed_immediately == completed_immediately_t::maybe)))
0045 {
0046
0047
0048 *completed_immediately = completed_immediately_t::maybe;
0049 fn();
0050
0051 if (*completed_immediately != completed_immediately_t::yes)
0052 *completed_immediately = completed_immediately_t::initiating;
0053 }
0054 else
0055 {
0056 asio::post(exec, std::forward<Fn>(fn));
0057 }
0058 }
0059
0060 friend bool operator==(const completion_handler_noop_executor&, const completion_handler_noop_executor&) noexcept
0061 {
0062 return true;
0063 }
0064
0065 friend bool operator!=(const completion_handler_noop_executor&, const completion_handler_noop_executor&) noexcept
0066 {
0067 return false;
0068 }
0069
0070 completion_handler_noop_executor(const completion_handler_noop_executor & rhs) noexcept = default;
0071 completion_handler_noop_executor(cobalt::executor inner, completed_immediately_t * completed_immediately)
0072 : exec(std::move(inner)), completed_immediately(completed_immediately)
0073 {
0074 }
0075
0076 };
0077
0078 template<typename Promise>
0079 executor
0080 get_executor(std::coroutine_handle<Promise> h)
0081 {
0082 if constexpr (requires {h.promise().get_executor();})
0083 {
0084 return h.promise().get_executor();
0085 }
0086 else
0087 return this_thread::get_executor();
0088 }
0089
0090 inline executor
0091 get_executor(std::coroutine_handle<>)
0092 {
0093 return this_thread::get_executor();
0094 }
0095
0096
0097 struct completion_handler_base
0098 {
0099 using cancellation_slot_type = asio::cancellation_slot;
0100 cancellation_slot_type cancellation_slot ;
0101 cancellation_slot_type get_cancellation_slot() const noexcept
0102 {
0103 return cancellation_slot ;
0104 }
0105
0106 using executor_type = executor;
0107 executor_type executor_ ;
0108 const executor_type & get_executor() const noexcept
0109 {
0110 return executor_ ;
0111 }
0112
0113 #if !defined(BOOST_COBALT_NO_PMR)
0114 using allocator_type = pmr::polymorphic_allocator<void>;
0115 pmr::polymorphic_allocator<void> allocator ;
0116 allocator_type get_allocator() const noexcept
0117 {
0118 return allocator ;
0119 }
0120 #else
0121 using allocator_type = detail::sbo_allocator<void>;
0122 detail::sbo_allocator<void> allocator ;
0123 allocator_type get_allocator() const noexcept
0124 {
0125 return allocator ;
0126 }
0127 #endif
0128 using immediate_executor_type = completion_handler_noop_executor;
0129 completed_immediately_t * completed_immediately = nullptr;
0130 immediate_executor_type get_immediate_executor() const noexcept
0131 {
0132 return {get_executor(), completed_immediately};
0133 }
0134
0135 template<typename Promise>
0136 completion_handler_base(std::coroutine_handle<Promise> h,
0137 completed_immediately_t * completed_immediately = nullptr)
0138 : cancellation_slot(asio::get_associated_cancellation_slot(h.promise())),
0139 executor_(cobalt::detail::get_executor(h)),
0140 #if !defined(BOOST_COBALT_NO_PMR)
0141 allocator(asio::get_associated_allocator(h.promise(), this_thread::get_allocator())),
0142 #else
0143 allocator(detail::get_null_sbo_resource()),
0144 #endif
0145 completed_immediately(completed_immediately)
0146 {
0147 }
0148 #if !defined(BOOST_COBALT_NO_PMR)
0149 template<typename Promise>
0150 completion_handler_base(std::coroutine_handle<Promise> h,
0151 pmr::memory_resource * resource,
0152 completed_immediately_t * completed_immediately = nullptr)
0153 : cancellation_slot(asio::get_associated_cancellation_slot(h.promise())),
0154 executor_(cobalt::detail::get_executor(h)),
0155 allocator(resource),
0156 completed_immediately(completed_immediately)
0157 {
0158 }
0159 #else
0160 template<typename Promise>
0161 completion_handler_base(std::coroutine_handle<Promise> h,
0162 detail::sbo_resource * resource,
0163 completed_immediately_t * completed_immediately = nullptr)
0164 : cancellation_slot(asio::get_associated_cancellation_slot(h.promise())),
0165 executor_(cobalt::detail::get_executor(h)),
0166 allocator(resource),
0167 completed_immediately(completed_immediately)
0168 {
0169 }
0170
0171 #endif
0172 };
0173
0174
0175 template<typename Handler>
0176 void assign_cancellation(std::coroutine_handle<void>, Handler &&) {}
0177
0178 template<typename Promise, typename Handler>
0179 void assign_cancellation(std::coroutine_handle<Promise> h, Handler && func)
0180 {
0181 if constexpr (requires {h.promise().get_cancellation_slot();})
0182 if (h.promise().get_cancellation_slot().is_connected())
0183 h.promise().get_cancellation_slot().assign(std::forward<Handler>(func));
0184 }
0185
0186 }
0187
0188 template<typename ... Args>
0189 struct handler
0190 {
0191 void operator()(Args ... args)
0192 {
0193 result.emplace(static_cast<Args>(args)...);
0194 }
0195 handler(std::optional<std::tuple<Args...>> &result) : result(result) {}
0196 private:
0197 std::optional<std::tuple<Args...>> &result;
0198 };
0199
0200 template<typename ... Args>
0201 handler(std::optional<std::tuple<Args...>> &result) -> handler<Args...>;
0202
0203 template<typename ... Args>
0204 struct completion_handler : detail::completion_handler_base
0205 {
0206 completion_handler(completion_handler && ) = default;
0207
0208 template<typename Promise>
0209 completion_handler(std::coroutine_handle<Promise> h,
0210 std::optional<std::tuple<Args...>> &result,
0211 detail::completed_immediately_t * completed_immediately = nullptr
0212 #if defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING)
0213 , const boost::source_location & loc = BOOST_CURRENT_LOCATION
0214 #endif
0215 ) : completion_handler_base(h, completed_immediately),
0216 self(h.address()), result(result)
0217 #if defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING)
0218 , loc_(loc)
0219 #endif
0220 {
0221 }
0222
0223 #if !defined(BOOST_COBALT_NO_PMR)
0224 template<typename Promise>
0225 completion_handler(std::coroutine_handle<Promise> h,
0226 std::optional<std::tuple<Args...>> &result,
0227 pmr::memory_resource * resource,
0228 detail::completed_immediately_t * completed_immediately = nullptr
0229 #if defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING)
0230 , const boost::source_location & loc = BOOST_CURRENT_LOCATION
0231 #endif
0232 ) : completion_handler_base(h, resource, completed_immediately),
0233 self(h.address()), result(result)
0234 #if defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING)
0235 , loc_(loc)
0236 #endif
0237 {
0238 }
0239 #else
0240 template<typename Promise>
0241 completion_handler(std::coroutine_handle<Promise> h,
0242 std::optional<std::tuple<Args...>> &result,
0243 detail::sbo_resource * resource,
0244 detail::completed_immediately_t * completed_immediately = nullptr)
0245 : completion_handler_base(h, resource, completed_immediately),
0246 self(h.address()), result(result)
0247 {
0248 }
0249 #endif
0250
0251
0252 void operator()(Args ... args)
0253 {
0254 #if defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING)
0255 BOOST_ASIO_HANDLER_LOCATION((loc_.file_name(), loc_.line(), loc_.function_name()));
0256 #endif
0257 result.emplace(std::move(args)...);
0258 BOOST_ASSERT(this->self != nullptr);
0259 auto p = this->self.release();
0260 if (completed_immediately != nullptr
0261 && *completed_immediately == detail::completed_immediately_t::maybe)
0262 {
0263 *completed_immediately = detail::completed_immediately_t::yes;
0264 return;
0265 }
0266
0267 std::move(p)();
0268 }
0269 using result_type = std::optional<std::tuple<Args...>>;
0270
0271 ~completion_handler()
0272 {
0273 if (self && completed_immediately
0274 && *completed_immediately == detail::completed_immediately_t::initiating
0275 && std::uncaught_exceptions() > 0)
0276 self.release();
0277 }
0278 private:
0279 unique_handle<void> self;
0280 std::optional<std::tuple<Args...>> &result;
0281 #if defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING)
0282 boost::source_location loc_;
0283 #endif
0284
0285 template<typename ... Args_>
0286 friend struct detail::composition_promise;
0287 };
0288
0289 };
0290
0291 #endif