// // Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com) // // 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) // // Official repository: https://github.com/boostorg/beast // #ifndef BOOST_BEAST_CORE_IMPL_SAVED_HANDLER_HPP #define BOOST_BEAST_CORE_IMPL_SAVED_HANDLER_HPP #include #include #include #include #include #include #include #include #include #include namespace boost { namespace beast { //------------------------------------------------------------------------------ class saved_handler::base { protected: ~base() = default; saved_handler * owner_; public: base(saved_handler * owner) : owner_(owner){} void set_owner(saved_handler * new_owner) { owner_ = new_owner;} virtual void destroy() = 0; virtual void invoke() = 0; }; //------------------------------------------------------------------------------ template class saved_handler::impl final : public base { using alloc_type = typename beast::detail::allocator_traits< Alloc>::template rebind_alloc; using alloc_traits = beast::detail::allocator_traits; struct ebo_pair : boost::empty_value { Handler h; template ebo_pair( alloc_type const& a, Handler_&& h_) : boost::empty_value( boost::empty_init_t{}, a) , h(std::forward(h_)) { } }; ebo_pair v_; #if defined(BOOST_ASIO_NO_TS_EXECUTORS) typename std::decay>(), net::execution::outstanding_work.tracked))>::type wg2_; #else // defined(BOOST_ASIO_NO_TS_EXECUTORS) net::executor_work_guard< net::associated_executor_t> wg2_; #endif // defined(BOOST_ASIO_NO_TS_EXECUTORS) net::cancellation_slot slot_{net::get_associated_cancellation_slot(v_.h)}; public: template impl(alloc_type const& a, Handler_&& h, saved_handler * owner) : base(owner), v_(a, std::forward(h)) #if defined(BOOST_ASIO_NO_TS_EXECUTORS) , wg2_(net::prefer( net::get_associated_executor(v_.h), net::execution::outstanding_work.tracked)) #else // defined(BOOST_ASIO_NO_TS_EXECUTORS) , wg2_(net::get_associated_executor(v_.h)) #endif // defined(BOOST_ASIO_NO_TS_EXECUTORS) { } ~impl() { } void destroy() override { auto v = std::move(v_); slot_.clear(); alloc_traits::destroy(v.get(), this); alloc_traits::deallocate(v.get(), this, 1); } void invoke() override { slot_.clear(); auto v = std::move(v_); alloc_traits::destroy(v.get(), this); alloc_traits::deallocate(v.get(), this, 1); v.h(); } void self_complete() { slot_.clear(); owner_->p_ = nullptr; auto v = std::move(v_); alloc_traits::destroy(v.get(), this); alloc_traits::deallocate(v.get(), this, 1); v.h(net::error::operation_aborted); } }; //------------------------------------------------------------------------------ template void saved_handler:: emplace(Handler&& handler, Allocator const& alloc, net::cancellation_type cancel_type) { // Can't delete a handler before invoking BOOST_ASSERT(! has_value()); using handler_type = typename std::decay::type; using alloc_type = typename detail::allocator_traits:: template rebind_alloc>; using alloc_traits = beast::detail::allocator_traits; struct storage { alloc_type a; impl* p; explicit storage(Allocator const& a_) : a(a_) , p(alloc_traits::allocate(a, 1)) { } ~storage() { if(p) alloc_traits::deallocate(a, p, 1); } }; auto cancel_slot = net::get_associated_cancellation_slot(handler); storage s(alloc); alloc_traits::construct(s.a, s.p, s.a, std::forward(handler), this); auto tmp = boost::exchange(s.p, nullptr); p_ = tmp; if (cancel_slot.is_connected()) { struct cancel_op { impl* p; net::cancellation_type accepted_ct; cancel_op(impl* p, net::cancellation_type accepted_ct) : p(p), accepted_ct(accepted_ct) {} void operator()(net::cancellation_type ct) { if ((ct & accepted_ct) != net::cancellation_type::none) p->self_complete(); } }; cancel_slot.template emplace(tmp, cancel_type); } } template void saved_handler:: emplace(Handler&& handler, net::cancellation_type cancel_type) { // Can't delete a handler before invoking BOOST_ASSERT(! has_value()); emplace( std::forward(handler), net::get_associated_allocator(handler), cancel_type); } } // beast } // boost #endif