File indexing completed on 2025-12-16 09:44:27
0001
0002
0003
0004
0005
0006
0007
0008 #ifndef BOOST_COBALT_HANDLE_HPP
0009 #define BOOST_COBALT_HANDLE_HPP
0010
0011 #include <boost/asio/associator.hpp>
0012 #include <coroutine>
0013 #include <memory>
0014
0015 namespace boost::cobalt
0016 {
0017
0018 template<typename T>
0019 struct unique_handle
0020 {
0021 unique_handle() noexcept = default;
0022 #if defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING)
0023 explicit unique_handle(T * promise,
0024 const boost::source_location & loc = BOOST_CURRENT_LOCATION) noexcept : handle_(promise), loc_(loc) {}
0025 #else
0026 explicit unique_handle(T * promise) noexcept : handle_(promise) {}
0027 #endif
0028 unique_handle(std::nullptr_t) noexcept {}
0029
0030 std::coroutine_handle<T> release()
0031 {
0032 return std::coroutine_handle<T>::from_promise(*handle_.release());
0033 }
0034
0035 void* address() const noexcept { return get_handle_().address(); }
0036
0037 #if defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING)
0038 static unique_handle from_address(
0039 void* a,
0040 const boost::source_location & loc = BOOST_CURRENT_LOCATION) noexcept
0041 {
0042 unique_handle res;
0043 res.loc_ = loc;
0044 res.handle_.reset(&std::coroutine_handle<T>::from_address(a).promise());
0045 return res;
0046 }
0047 #else
0048 static unique_handle from_address(void* a) noexcept
0049 {
0050 unique_handle res;
0051 res.handle_.reset(&std::coroutine_handle<T>::from_address(a).promise());
0052 return res;
0053 }
0054 #endif
0055
0056
0057 bool done() const noexcept { return get_handle_().done(); }
0058 explicit operator bool() const { return static_cast<bool>(handle_); }
0059
0060 void destroy() { handle_.reset(); }
0061
0062 void operator()() const &
0063 {
0064 #if defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING)
0065 BOOST_ASIO_HANDLER_LOCATION((loc_.file_name(), loc_.line(), loc_.function_name()));
0066 #endif
0067 resume();
0068 }
0069 void resume() const & { get_handle_().resume(); }
0070
0071 void operator()() &&
0072 {
0073 #if defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING)
0074 BOOST_ASIO_HANDLER_LOCATION((loc_.file_name(), loc_.line(), loc_.function_name()));
0075 #endif
0076 release().resume();
0077 }
0078 void resume() && { release().resume(); }
0079
0080 T & promise() {return *handle_;}
0081
0082 #if defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING)
0083 constexpr static unique_handle from_promise(
0084 T &p,
0085 const boost::source_location & loc = BOOST_CURRENT_LOCATION) noexcept
0086 {
0087 unique_handle res;
0088 res.loc_ = loc;
0089 res.handle_.reset(&p);
0090 return res;
0091 }
0092 #else
0093 constexpr static unique_handle from_promise(T &p) noexcept
0094 {
0095 unique_handle res;
0096 res.handle_.reset(&p);
0097 return res;
0098 }
0099 #endif
0100
0101 T & operator*() {return *handle_;}
0102 const T & operator*() const {return *handle_;}
0103
0104
0105 T * operator->() {return handle_.get();}
0106 const T * operator->() const {return handle_.get();}
0107
0108 T * get() {return handle_.get();}
0109 const T * get() const {return handle_.get();}
0110
0111 #if defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING)
0112 void reset(T * handle = nullptr,
0113 const boost::source_location & loc = BOOST_CURRENT_LOCATION)
0114 {
0115 loc_ = loc; handle_.reset(handle);
0116 }
0117 #else
0118 void reset(T * handle = nullptr) {handle_.reset(handle);}
0119 #endif
0120
0121 friend
0122 auto operator==(const unique_handle & h, std::nullptr_t) {return h.handle_ == nullptr;}
0123 friend
0124 auto operator!=(const unique_handle & h, std::nullptr_t) {return h.handle_ != nullptr;}
0125
0126 private:
0127 struct deleter_
0128 {
0129 void operator()(T * p)
0130 {
0131 std::coroutine_handle<T>::from_promise(*p).destroy();
0132 }
0133 };
0134
0135 std::coroutine_handle<T> get_handle_() const
0136 {
0137 return std::coroutine_handle<T>::from_promise(*handle_);
0138 }
0139
0140 std::unique_ptr<T, deleter_> handle_;
0141 #if defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING)
0142 boost::source_location loc_;
0143 #endif
0144 };
0145
0146 template<>
0147 struct unique_handle<void>
0148 {
0149 unique_handle() noexcept = default;
0150 unique_handle(std::nullptr_t) noexcept {}
0151 #if defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING)
0152 explicit unique_handle(void * handle,
0153 const boost::source_location & loc = BOOST_CURRENT_LOCATION) noexcept : handle_(handle), loc_(loc) {}
0154 #else
0155 explicit unique_handle(void * handle) noexcept : handle_(handle) {}
0156 #endif
0157 std::coroutine_handle<void> release()
0158 {
0159 return std::coroutine_handle<void>::from_address(handle_.release());
0160 }
0161 void* address() const noexcept { return get_handle_().address(); }
0162 #if defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING)
0163 static unique_handle<void> from_address(void* a,
0164 const boost::source_location & loc = BOOST_CURRENT_LOCATION) noexcept
0165 {
0166
0167 unique_handle res;
0168 res.loc_ = loc;
0169 res.handle_.reset(std::coroutine_handle<void>::from_address(a).address());
0170 return res;
0171 }
0172 #else
0173 static unique_handle<void> from_address(void* a) noexcept
0174 {
0175
0176 unique_handle res;
0177 res.handle_.reset(std::coroutine_handle<void>::from_address(a).address());
0178 return res;
0179 }
0180 #endif
0181
0182 explicit operator bool() const { return static_cast<bool>(handle_); }
0183 bool done() const noexcept { return get_handle_().done(); }
0184
0185 void operator()() const &
0186 {
0187 #if defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING)
0188 BOOST_ASIO_HANDLER_LOCATION((loc_.file_name(), loc_.line(), loc_.function_name()));
0189 #endif
0190 resume();
0191 }
0192 void resume() const & { get_handle_().resume(); }
0193
0194 void operator()() &&
0195 {
0196 #if defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING)
0197 BOOST_ASIO_HANDLER_LOCATION((loc_.file_name(), loc_.line(), loc_.function_name()));
0198 #endif
0199 release().resume();
0200 }
0201 void resume() && { release().resume(); }
0202
0203 void destroy() { handle_.reset(); }
0204
0205 void * get() { return handle_.get(); }
0206 const void * get() const { return handle_.get(); }
0207
0208 #if defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING)
0209 void reset(void * handle = nullptr,
0210 const boost::source_location & loc = BOOST_CURRENT_LOCATION)
0211 {
0212 loc_ = loc;
0213 handle_.reset(handle);
0214 }
0215 #else
0216 void reset(void * handle = nullptr) {handle_.reset(handle);}
0217 #endif
0218
0219 friend
0220 auto operator==(const unique_handle & h, std::nullptr_t) {return h.handle_ == nullptr;}
0221 friend
0222 auto operator!=(const unique_handle & h, std::nullptr_t) {return h.handle_ != nullptr;}
0223 private:
0224 struct deleter_
0225 {
0226 void operator()(void * p)
0227 {
0228 std::coroutine_handle<void>::from_address(p).destroy();
0229 }
0230 };
0231
0232 std::coroutine_handle<void> get_handle_() const
0233 {
0234 return std::coroutine_handle<void>::from_address(handle_.get());
0235 }
0236
0237 std::unique_ptr<void, deleter_> handle_;
0238 #if defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING)
0239 boost::source_location loc_;
0240 #endif
0241 };
0242
0243 template<>
0244 struct unique_handle<std::noop_coroutine_promise>
0245 {
0246 unique_handle() noexcept = default;
0247 unique_handle(std::nullptr_t) noexcept {}
0248
0249 std::coroutine_handle<void> release()
0250 {
0251 return std::noop_coroutine();
0252 }
0253 void* address() const noexcept { return std::noop_coroutine().address(); }
0254 bool done() const noexcept { return true;}
0255 void operator()() const {}
0256 void resume() const {}
0257 void destroy() {}
0258 explicit operator bool() const { return true; }
0259
0260 struct executor_type
0261 {
0262 template<typename Fn>
0263 void execute(Fn &&) const {}
0264 };
0265
0266 executor_type get_executor() const {return {}; }
0267
0268 friend
0269 auto operator==(const unique_handle &, std::nullptr_t) {return false;}
0270 friend
0271 auto operator!=(const unique_handle &, std::nullptr_t) {return true;}
0272 };
0273
0274 }
0275
0276 namespace boost::asio
0277 {
0278
0279 template <template <typename, typename> class Associator,
0280 typename Promise, typename DefaultCandidate>
0281 requires (!std::is_void_v<Promise>)
0282 struct associator<Associator,
0283 boost::cobalt::unique_handle<Promise>, DefaultCandidate>
0284 : Associator<Promise, DefaultCandidate>
0285 {
0286 static typename Associator<Promise, DefaultCandidate>::type
0287 get(const boost::cobalt::unique_handle<Promise>& h) BOOST_ASIO_NOEXCEPT
0288 {
0289 return Associator<Promise, DefaultCandidate>::get(*h);
0290 }
0291
0292 static BOOST_ASIO_AUTO_RETURN_TYPE_PREFIX2(
0293 typename Associator<Handler, DefaultCandidate>::type)
0294 get(const boost::cobalt::unique_handle<Promise>& h,
0295 const DefaultCandidate& c) BOOST_ASIO_NOEXCEPT
0296 BOOST_ASIO_AUTO_RETURN_TYPE_SUFFIX((
0297 Associator<Promise, DefaultCandidate>::get(*h, c)))
0298 {
0299 return Associator<Promise, DefaultCandidate>::get(*h, c);
0300 }
0301 };
0302
0303 }
0304
0305
0306 #endif