// // experimental/detail/completion_handler_erasure.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2021-2022 Klemens D. Morgenstern // (klemens dot morgenstern at gmx dot 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_ASIO_EXPERIMENTAL_DETAIL_COMPLETION_HANDLER_ERASURE_HPP #define BOOST_ASIO_EXPERIMENTAL_DETAIL_COMPLETION_HANDLER_ERASURE_HPP #include #include #include namespace boost { namespace asio { class any_io_executor; namespace experimental { namespace detail { template struct completion_handler_erasure_base; template struct completion_handler_erasure_impl; template struct completion_handler_erasure_base { Executor executor; completion_handler_erasure_base(Executor&& executor) : executor(std::move(executor)) { } virtual Return call(Args... args) = 0; virtual void destroy() = 0; virtual ~completion_handler_erasure_base() = default; }; template struct completion_handler_erasure_impl final : completion_handler_erasure_base { using allocator_base = typename associated_allocator::type; using allocator_type = typename std::allocator_traits::template rebind_alloc< completion_handler_erasure_impl>; completion_handler_erasure_impl(Executor&& exec, Func&& func) : completion_handler_erasure_base( std::move(exec)), func(std::move(func)) { } struct uninit_deleter_t { allocator_type allocator; uninit_deleter_t(const Func& func) : allocator(get_associated_allocator(func)) { } void operator()(completion_handler_erasure_impl* p) { std::allocator_traits::deallocate(allocator, p, 1); } }; static completion_handler_erasure_impl* make(Executor exec, Func&& func) { uninit_deleter_t deleter(func); std::unique_ptr uninit_ptr(std::allocator_traits::allocate( deleter.allocator, 1), deleter); completion_handler_erasure_impl* ptr = new (uninit_ptr.get()) completion_handler_erasure_impl( std::move(exec), std::move(func)); uninit_ptr.release(); return ptr; } struct deleter_t { allocator_type allocator; deleter_t(const Func& func) : allocator(get_associated_allocator(func)) { } void operator()(completion_handler_erasure_impl* p) { std::allocator_traits::destroy(allocator, p); std::allocator_traits::deallocate(allocator, p, 1); } }; virtual Return call(Args... args) override { std::unique_ptr p(this, deleter_t(func)); Func f(std::move(func)); p.reset(); std::move(f)(std::move(args)...); } virtual void destroy() override { std::unique_ptr(this, deleter_t(func)); } Func func; }; template struct completion_handler_erasure; template struct completion_handler_erasure { struct deleter_t { void operator()( completion_handler_erasure_base* p) { p->destroy(); } }; completion_handler_erasure(const completion_handler_erasure&) = delete; completion_handler_erasure(completion_handler_erasure&&) = default; completion_handler_erasure& operator=( const completion_handler_erasure&) = delete; completion_handler_erasure& operator=( completion_handler_erasure&&) = default; constexpr completion_handler_erasure() = default; constexpr completion_handler_erasure(nullptr_t) : completion_handler_erasure() { } template completion_handler_erasure(Executor exec, Func&& func) : impl_(completion_handler_erasure_impl< std::decay_t, Return(Args...), Executor>::make( std::move(exec), std::forward(func))) { } ~completion_handler_erasure() { if (impl_) { Executor executor(impl_->executor); boost::asio::dispatch(executor, [impl = std::move(impl_)]() mutable { impl.reset(); }); } } Return operator()(Args... args) { if (impl_) impl_.release()->call(std::move(args)...); } constexpr bool operator==(nullptr_t) const noexcept {return impl_ == nullptr;} constexpr bool operator!=(nullptr_t) const noexcept {return impl_ != nullptr;} constexpr bool operator!() const noexcept {return impl_ == nullptr;} private: std::unique_ptr< completion_handler_erasure_base, deleter_t> impl_; }; } // namespace detail } // namespace experimental } // namespace asio } // namespace boost #endif // BOOST_ASIO_EXPERIMENTAL_DETAIL_COMPLETION_HANDLER_ERASURE_HPP