// // Copyright (c) 2023 Klemens Morgenstern (klemens.morgenstern@gmx.net) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // #ifndef BOOST_COBALT_HANDLE_HPP #define BOOST_COBALT_HANDLE_HPP #include #include #include namespace boost::cobalt { template struct unique_handle { unique_handle() noexcept = default; #if defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING) explicit unique_handle(T * promise, const boost::source_location & loc = BOOST_CURRENT_LOCATION) noexcept : handle_(promise), loc_(loc) {} #else explicit unique_handle(T * promise) noexcept : handle_(promise) {} #endif unique_handle(std::nullptr_t) noexcept {} std::coroutine_handle release() { return std::coroutine_handle::from_promise(*handle_.release()); } void* address() const noexcept { return get_handle_().address(); } #if defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING) static unique_handle from_address( void* a, const boost::source_location & loc = BOOST_CURRENT_LOCATION) noexcept { unique_handle res; res.loc_ = loc; res.handle_.reset(&std::coroutine_handle::from_address(a).promise()); return res; } #else static unique_handle from_address(void* a) noexcept { unique_handle res; res.handle_.reset(&std::coroutine_handle::from_address(a).promise()); return res; } #endif bool done() const noexcept { return get_handle_().done(); } explicit operator bool() const { return static_cast(handle_); } void destroy() { handle_.reset(); } void operator()() const & { #if defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING) BOOST_ASIO_HANDLER_LOCATION((loc_.file_name(), loc_.line(), loc_.function_name())); #endif resume(); } void resume() const & { get_handle_().resume(); } void operator()() && { #if defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING) BOOST_ASIO_HANDLER_LOCATION((loc_.file_name(), loc_.line(), loc_.function_name())); #endif release().resume(); } void resume() && { release().resume(); } T & promise() {return *handle_;} #if defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING) constexpr static unique_handle from_promise( T &p, const boost::source_location & loc = BOOST_CURRENT_LOCATION) noexcept { unique_handle res; res.loc_ = loc; res.handle_.reset(&p); return res; } #else constexpr static unique_handle from_promise(T &p) noexcept { unique_handle res; res.handle_.reset(&p); return res; } #endif T & operator*() {return *handle_;} const T & operator*() const {return *handle_;} T * operator->() {return handle_.get();} const T * operator->() const {return handle_.get();} T * get() {return handle_.get();} const T * get() const {return handle_.get();} #if defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING) void reset(T * handle = nullptr, const boost::source_location & loc = BOOST_CURRENT_LOCATION) { loc_ = loc; handle_.reset(handle); } #else void reset(T * handle = nullptr) {handle_.reset(handle);} #endif friend auto operator==(const unique_handle & h, std::nullptr_t) {return h.handle_ == nullptr;} friend auto operator!=(const unique_handle & h, std::nullptr_t) {return h.handle_ != nullptr;} private: struct deleter_ { void operator()(T * p) { std::coroutine_handle::from_promise(*p).destroy(); } }; std::coroutine_handle get_handle_() const { return std::coroutine_handle::from_promise(*handle_); } std::unique_ptr handle_; #if defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING) boost::source_location loc_; #endif }; template<> struct unique_handle { unique_handle() noexcept = default; unique_handle(std::nullptr_t) noexcept {} #if defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING) explicit unique_handle(void * handle, const boost::source_location & loc = BOOST_CURRENT_LOCATION) noexcept : handle_(handle), loc_(loc) {} #else explicit unique_handle(void * handle) noexcept : handle_(handle) {} #endif std::coroutine_handle release() { return std::coroutine_handle::from_address(handle_.release()); } void* address() const noexcept { return get_handle_().address(); } #if defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING) static unique_handle from_address(void* a, const boost::source_location & loc = BOOST_CURRENT_LOCATION) noexcept { unique_handle res; res.loc_ = loc; res.handle_.reset(std::coroutine_handle::from_address(a).address()); return res; } #else static unique_handle from_address(void* a) noexcept { unique_handle res; res.handle_.reset(std::coroutine_handle::from_address(a).address()); return res; } #endif explicit operator bool() const { return static_cast(handle_); } bool done() const noexcept { return get_handle_().done(); } void operator()() const & { #if defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING) BOOST_ASIO_HANDLER_LOCATION((loc_.file_name(), loc_.line(), loc_.function_name())); #endif resume(); } void resume() const & { get_handle_().resume(); } void operator()() && { #if defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING) BOOST_ASIO_HANDLER_LOCATION((loc_.file_name(), loc_.line(), loc_.function_name())); #endif release().resume(); } void resume() && { release().resume(); } void destroy() { handle_.reset(); } void * get() { return handle_.get(); } const void * get() const { return handle_.get(); } #if defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING) void reset(void * handle = nullptr, const boost::source_location & loc = BOOST_CURRENT_LOCATION) { loc_ = loc; handle_.reset(handle); } #else void reset(void * handle = nullptr) {handle_.reset(handle);} #endif friend auto operator==(const unique_handle & h, std::nullptr_t) {return h.handle_ == nullptr;} friend auto operator!=(const unique_handle & h, std::nullptr_t) {return h.handle_ != nullptr;} private: struct deleter_ { void operator()(void * p) { std::coroutine_handle::from_address(p).destroy(); } }; std::coroutine_handle get_handle_() const { return std::coroutine_handle::from_address(handle_.get()); } std::unique_ptr handle_; #if defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING) boost::source_location loc_; #endif }; template<> struct unique_handle { unique_handle() noexcept = default; unique_handle(std::nullptr_t) noexcept {} std::coroutine_handle release() { return std::noop_coroutine(); } void* address() const noexcept { return std::noop_coroutine().address(); } bool done() const noexcept { return true;} void operator()() const {} void resume() const {} void destroy() {} explicit operator bool() const { return true; } struct executor_type { template void execute(Fn &&) const {} }; executor_type get_executor() const {return {}; } friend auto operator==(const unique_handle &, std::nullptr_t) {return false;} friend auto operator!=(const unique_handle &, std::nullptr_t) {return true;} }; } namespace boost::asio { template