saved_handler.hpp 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. //
  2. // Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
  3. //
  4. // Distributed under the Boost Software License, Version 1.0. (See accompanying
  5. // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  6. //
  7. // Official repository: https://github.com/boostorg/beast
  8. //
  9. #ifndef BOOST_BEAST_CORE_IMPL_SAVED_HANDLER_HPP
  10. #define BOOST_BEAST_CORE_IMPL_SAVED_HANDLER_HPP
  11. #include <boost/beast/core/detail/allocator.hpp>
  12. #include <boost/asio/associated_allocator.hpp>
  13. #include <boost/asio/associated_executor.hpp>
  14. #include <boost/asio/executor_work_guard.hpp>
  15. #include <boost/assert.hpp>
  16. #include <boost/core/empty_value.hpp>
  17. #include <boost/core/exchange.hpp>
  18. #include <utility>
  19. namespace boost {
  20. namespace beast {
  21. //------------------------------------------------------------------------------
  22. class saved_handler::base
  23. {
  24. protected:
  25. ~base() = default;
  26. public:
  27. base() = default;
  28. virtual void destroy() = 0;
  29. virtual void invoke() = 0;
  30. };
  31. //------------------------------------------------------------------------------
  32. template<class Handler, class Alloc>
  33. class saved_handler::impl final : public base
  34. {
  35. using alloc_type = typename
  36. beast::detail::allocator_traits<
  37. Alloc>::template rebind_alloc<impl>;
  38. using alloc_traits =
  39. beast::detail::allocator_traits<alloc_type>;
  40. struct ebo_pair : boost::empty_value<alloc_type>
  41. {
  42. Handler h;
  43. template<class Handler_>
  44. ebo_pair(
  45. alloc_type const& a,
  46. Handler_&& h_)
  47. : boost::empty_value<alloc_type>(
  48. boost::empty_init_t{}, a)
  49. , h(std::forward<Handler_>(h_))
  50. {
  51. }
  52. };
  53. ebo_pair v_;
  54. net::executor_work_guard<
  55. net::associated_executor_t<Handler>> wg2_;
  56. public:
  57. template<class Handler_>
  58. impl(alloc_type const& a, Handler_&& h)
  59. : v_(a, std::forward<Handler_>(h))
  60. , wg2_(net::get_associated_executor(v_.h))
  61. {
  62. }
  63. void
  64. destroy() override
  65. {
  66. auto v = std::move(v_);
  67. alloc_traits::destroy(v.get(), this);
  68. alloc_traits::deallocate(v.get(), this, 1);
  69. }
  70. void
  71. invoke() override
  72. {
  73. auto v = std::move(v_);
  74. alloc_traits::destroy(v.get(), this);
  75. alloc_traits::deallocate(v.get(), this, 1);
  76. v.h();
  77. }
  78. };
  79. //------------------------------------------------------------------------------
  80. template<class Handler, class Allocator>
  81. void
  82. saved_handler::
  83. emplace(Handler&& handler, Allocator const& alloc)
  84. {
  85. // Can't delete a handler before invoking
  86. BOOST_ASSERT(! has_value());
  87. using handler_type =
  88. typename std::decay<Handler>::type;
  89. using alloc_type = typename
  90. detail::allocator_traits<Allocator>::
  91. template rebind_alloc<impl<
  92. handler_type, Allocator>>;
  93. using alloc_traits =
  94. beast::detail::allocator_traits<alloc_type>;
  95. struct storage
  96. {
  97. alloc_type a;
  98. impl<Handler, Allocator>* p;
  99. explicit
  100. storage(Allocator const& a_)
  101. : a(a_)
  102. , p(alloc_traits::allocate(a, 1))
  103. {
  104. }
  105. ~storage()
  106. {
  107. if(p)
  108. alloc_traits::deallocate(a, p, 1);
  109. }
  110. };
  111. storage s(alloc);
  112. alloc_traits::construct(s.a, s.p,
  113. s.a, std::forward<Handler>(handler));
  114. p_ = boost::exchange(s.p, nullptr);
  115. }
  116. template<class Handler>
  117. void
  118. saved_handler::
  119. emplace(Handler&& handler)
  120. {
  121. // Can't delete a handler before invoking
  122. BOOST_ASSERT(! has_value());
  123. emplace(
  124. std::forward<Handler>(handler),
  125. net::get_associated_allocator(handler));
  126. }
  127. } // beast
  128. } // boost
  129. #endif