File indexing completed on 2025-01-18 09:29:27
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #ifndef BOOST_BEAST_CORE_IMPL_SAVED_HANDLER_HPP
0011 #define BOOST_BEAST_CORE_IMPL_SAVED_HANDLER_HPP
0012
0013 #include <boost/beast/core/detail/allocator.hpp>
0014 #include <boost/asio/associated_allocator.hpp>
0015 #include <boost/asio/associated_cancellation_slot.hpp>
0016 #include <boost/asio/associated_executor.hpp>
0017 #include <boost/asio/error.hpp>
0018 #include <boost/asio/executor_work_guard.hpp>
0019 #include <boost/assert.hpp>
0020 #include <boost/core/empty_value.hpp>
0021 #include <boost/core/exchange.hpp>
0022 #include <utility>
0023
0024 namespace boost {
0025 namespace beast {
0026
0027
0028
0029 class saved_handler::base
0030 {
0031 protected:
0032 ~base() = default;
0033 saved_handler * owner_;
0034 public:
0035 base(saved_handler * owner) : owner_(owner){}
0036 void set_owner(saved_handler * new_owner) { owner_ = new_owner;}
0037 virtual void destroy() = 0;
0038 virtual void invoke() = 0;
0039 };
0040
0041
0042
0043 template<class Handler, class Alloc>
0044 class saved_handler::impl final : public base
0045 {
0046 using alloc_type = typename
0047 beast::detail::allocator_traits<
0048 Alloc>::template rebind_alloc<impl>;
0049
0050 using alloc_traits =
0051 beast::detail::allocator_traits<alloc_type>;
0052
0053 struct ebo_pair : boost::empty_value<alloc_type>
0054 {
0055 Handler h;
0056
0057 template<class Handler_>
0058 ebo_pair(
0059 alloc_type const& a,
0060 Handler_&& h_)
0061 : boost::empty_value<alloc_type>(
0062 boost::empty_init_t{}, a)
0063 , h(std::forward<Handler_>(h_))
0064 {
0065 }
0066 };
0067
0068 ebo_pair v_;
0069 #if defined(BOOST_ASIO_NO_TS_EXECUTORS)
0070 typename std::decay<decltype(net::prefer(std::declval<
0071 net::associated_executor_t<Handler>>(),
0072 net::execution::outstanding_work.tracked))>::type
0073 wg2_;
0074 #else
0075 net::executor_work_guard<
0076 net::associated_executor_t<Handler>> wg2_;
0077 #endif
0078 net::cancellation_slot slot_{net::get_associated_cancellation_slot(v_.h)};
0079 public:
0080 template<class Handler_>
0081 impl(alloc_type const& a, Handler_&& h,
0082 saved_handler * owner)
0083 : base(owner), v_(a, std::forward<Handler_>(h))
0084 #if defined(BOOST_ASIO_NO_TS_EXECUTORS)
0085 , wg2_(net::prefer(
0086 net::get_associated_executor(v_.h),
0087 net::execution::outstanding_work.tracked))
0088 #else
0089 , wg2_(net::get_associated_executor(v_.h))
0090 #endif
0091 {
0092 }
0093
0094 ~impl()
0095 {
0096 }
0097
0098 void
0099 destroy() override
0100 {
0101 auto v = std::move(v_);
0102 slot_.clear();
0103 alloc_traits::destroy(v.get(), this);
0104 alloc_traits::deallocate(v.get(), this, 1);
0105 }
0106
0107 void
0108 invoke() override
0109 {
0110 slot_.clear();
0111 auto v = std::move(v_);
0112 alloc_traits::destroy(v.get(), this);
0113 alloc_traits::deallocate(v.get(), this, 1);
0114 v.h();
0115 }
0116
0117 void self_complete()
0118 {
0119 slot_.clear();
0120 owner_->p_ = nullptr;
0121 auto v = std::move(v_);
0122 alloc_traits::destroy(v.get(), this);
0123 alloc_traits::deallocate(v.get(), this, 1);
0124 v.h(net::error::operation_aborted);
0125 }
0126 };
0127
0128
0129
0130 template<class Handler, class Allocator>
0131 void
0132 saved_handler::
0133 emplace(Handler&& handler, Allocator const& alloc,
0134 net::cancellation_type cancel_type)
0135 {
0136
0137 BOOST_ASSERT(! has_value());
0138 using handler_type =
0139 typename std::decay<Handler>::type;
0140 using alloc_type = typename
0141 detail::allocator_traits<Allocator>::
0142 template rebind_alloc<impl<
0143 handler_type, Allocator>>;
0144 using alloc_traits =
0145 beast::detail::allocator_traits<alloc_type>;
0146 struct storage
0147 {
0148 alloc_type a;
0149 impl<Handler, Allocator>* p;
0150
0151 explicit
0152 storage(Allocator const& a_)
0153 : a(a_)
0154 , p(alloc_traits::allocate(a, 1))
0155 {
0156 }
0157
0158 ~storage()
0159 {
0160 if(p)
0161 alloc_traits::deallocate(a, p, 1);
0162 }
0163 };
0164
0165
0166 auto cancel_slot = net::get_associated_cancellation_slot(handler);
0167 storage s(alloc);
0168 alloc_traits::construct(s.a, s.p,
0169 s.a, std::forward<Handler>(handler), this);
0170
0171 auto tmp = boost::exchange(s.p, nullptr);
0172 p_ = tmp;
0173
0174 if (cancel_slot.is_connected())
0175 {
0176 struct cancel_op
0177 {
0178 impl<Handler, Allocator>* p;
0179 net::cancellation_type accepted_ct;
0180 cancel_op(impl<Handler, Allocator>* p,
0181 net::cancellation_type accepted_ct)
0182 : p(p), accepted_ct(accepted_ct) {}
0183
0184 void operator()(net::cancellation_type ct)
0185 {
0186 if ((ct & accepted_ct) != net::cancellation_type::none)
0187 p->self_complete();
0188 }
0189 };
0190 cancel_slot.template emplace<cancel_op>(tmp, cancel_type);
0191 }
0192 }
0193
0194 template<class Handler>
0195 void
0196 saved_handler::
0197 emplace(Handler&& handler, net::cancellation_type cancel_type)
0198 {
0199
0200 BOOST_ASSERT(! has_value());
0201 emplace(
0202 std::forward<Handler>(handler),
0203 net::get_associated_allocator(handler),
0204 cancel_type);
0205 }
0206
0207 }
0208 }
0209
0210 #endif