pausation.hpp 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  1. //
  2. // Copyright (c) 2016-2017 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_WEBSOCKET_DETAIL_PAUSATION_HPP
  10. #define BOOST_BEAST_WEBSOCKET_DETAIL_PAUSATION_HPP
  11. #include <boost/beast/core/detail/allocator.hpp>
  12. #include <boost/asio/associated_allocator.hpp>
  13. #include <boost/assert.hpp>
  14. #include <memory>
  15. #include <utility>
  16. namespace boost {
  17. namespace beast {
  18. namespace websocket {
  19. namespace detail {
  20. // A container that holds a suspended, asynchronous composed
  21. // operation. The contained object may be invoked later to
  22. // resume the operation, or the container may be destroyed.
  23. //
  24. class pausation
  25. {
  26. struct handler
  27. {
  28. handler() = default;
  29. handler(handler &&) = delete;
  30. handler(handler const&) = delete;
  31. virtual ~handler() = default;
  32. virtual void destroy() = 0;
  33. virtual void invoke() = 0;
  34. };
  35. template<class Handler>
  36. class impl : public handler
  37. {
  38. Handler h_;
  39. public:
  40. template<class DeducedHandler>
  41. impl(DeducedHandler&& h)
  42. : h_(std::forward<DeducedHandler>(h))
  43. {
  44. }
  45. void
  46. destroy() override
  47. {
  48. Handler h(std::move(h_));
  49. typename beast::detail::allocator_traits<
  50. boost::asio::associated_allocator_t<
  51. Handler>>::template rebind_alloc<impl> alloc{
  52. boost::asio::get_associated_allocator(h)};
  53. beast::detail::allocator_traits<
  54. decltype(alloc)>::destroy(alloc, this);
  55. beast::detail::allocator_traits<
  56. decltype(alloc)>::deallocate(alloc, this, 1);
  57. }
  58. void
  59. invoke() override
  60. {
  61. Handler h(std::move(h_));
  62. typename beast::detail::allocator_traits<
  63. boost::asio::associated_allocator_t<
  64. Handler>>::template rebind_alloc<impl> alloc{
  65. boost::asio::get_associated_allocator(h)};
  66. beast::detail::allocator_traits<
  67. decltype(alloc)>::destroy(alloc, this);
  68. beast::detail::allocator_traits<
  69. decltype(alloc)>::deallocate(alloc, this, 1);
  70. h();
  71. }
  72. };
  73. handler* h_ = nullptr;
  74. public:
  75. pausation() = default;
  76. pausation(pausation const&) = delete;
  77. pausation& operator=(pausation const&) = delete;
  78. ~pausation()
  79. {
  80. if(h_)
  81. h_->destroy();
  82. }
  83. pausation(pausation&& other)
  84. {
  85. boost::ignore_unused(other);
  86. BOOST_ASSERT(! other.h_);
  87. }
  88. pausation&
  89. operator=(pausation&& other)
  90. {
  91. boost::ignore_unused(other);
  92. BOOST_ASSERT(! h_);
  93. BOOST_ASSERT(! other.h_);
  94. return *this;
  95. }
  96. template<class CompletionHandler>
  97. void
  98. emplace(CompletionHandler&& handler);
  99. explicit
  100. operator bool() const
  101. {
  102. return h_ != nullptr;
  103. }
  104. bool
  105. maybe_invoke()
  106. {
  107. if(h_)
  108. {
  109. auto const h = h_;
  110. h_ = nullptr;
  111. h->invoke();
  112. return true;
  113. }
  114. return false;
  115. }
  116. };
  117. template<class CompletionHandler>
  118. void
  119. pausation::emplace(CompletionHandler&& handler)
  120. {
  121. BOOST_ASSERT(! h_);
  122. typename beast::detail::allocator_traits<
  123. boost::asio::associated_allocator_t<
  124. CompletionHandler>>::template rebind_alloc<
  125. impl<CompletionHandler>> alloc{
  126. boost::asio::get_associated_allocator(handler)};
  127. using A = decltype(alloc);
  128. auto const d =
  129. [&alloc](impl<CompletionHandler>* p)
  130. {
  131. beast::detail::allocator_traits<A>::deallocate(alloc, p, 1);
  132. };
  133. std::unique_ptr<impl<CompletionHandler>, decltype(d)> p{
  134. beast::detail::allocator_traits<A>::allocate(alloc, 1), d};
  135. beast::detail::allocator_traits<A>::construct(
  136. alloc, p.get(), std::forward<CompletionHandler>(handler));
  137. h_ = p.release();
  138. }
  139. } // detail
  140. } // websocket
  141. } // beast
  142. } // boost
  143. #endif