completion_handler_erasure.hpp 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. //
  2. // experimental/detail/completion_handler_erasure.hpp
  3. // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  4. //
  5. // Copyright (c) 2021-2022 Klemens D. Morgenstern
  6. // (klemens dot morgenstern at gmx dot net)
  7. //
  8. // Distributed under the Boost Software License, Version 1.0. (See accompanying
  9. // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  10. //
  11. #ifndef ASIO_EXPERIMENTAL_DETAIL_COMPLETION_HANDLER_ERASURE_HPP
  12. #define ASIO_EXPERIMENTAL_DETAIL_COMPLETION_HANDLER_ERASURE_HPP
  13. #include <new>
  14. #include "asio/associated_allocator.hpp"
  15. #include "asio/dispatch.hpp"
  16. namespace asio {
  17. class any_io_executor;
  18. namespace experimental {
  19. namespace detail {
  20. template<typename Signature, typename Executor>
  21. struct completion_handler_erasure_base;
  22. template<typename Func, typename Signature, typename Executor>
  23. struct completion_handler_erasure_impl;
  24. template<typename Return, typename... Args, typename Executor>
  25. struct completion_handler_erasure_base<Return(Args...), Executor>
  26. {
  27. Executor executor;
  28. completion_handler_erasure_base(Executor&& executor)
  29. : executor(std::move(executor))
  30. {
  31. }
  32. virtual Return call(Args... args) = 0;
  33. virtual void destroy() = 0;
  34. virtual ~completion_handler_erasure_base() = default;
  35. };
  36. template<typename Func, typename Return, typename... Args, typename Executor>
  37. struct completion_handler_erasure_impl<Func, Return(Args...), Executor> final
  38. : completion_handler_erasure_base<Return(Args...), Executor>
  39. {
  40. using allocator_base = typename associated_allocator<Func>::type;
  41. using allocator_type =
  42. typename std::allocator_traits<allocator_base>::template rebind_alloc<
  43. completion_handler_erasure_impl>;
  44. completion_handler_erasure_impl(Executor&& exec, Func&& func)
  45. : completion_handler_erasure_base<Return(Args...), Executor>(
  46. std::move(exec)), func(std::move(func))
  47. {
  48. }
  49. struct uninit_deleter_t
  50. {
  51. allocator_type allocator;
  52. uninit_deleter_t(const Func& func)
  53. : allocator(get_associated_allocator(func))
  54. {
  55. }
  56. void operator()(completion_handler_erasure_impl* p)
  57. {
  58. std::allocator_traits<allocator_type>::deallocate(allocator, p, 1);
  59. }
  60. };
  61. static completion_handler_erasure_impl* make(Executor exec, Func&& func)
  62. {
  63. uninit_deleter_t deleter(func);
  64. std::unique_ptr<completion_handler_erasure_impl, uninit_deleter_t>
  65. uninit_ptr(std::allocator_traits<allocator_type>::allocate(
  66. deleter.allocator, 1), deleter);
  67. completion_handler_erasure_impl* ptr =
  68. new (uninit_ptr.get()) completion_handler_erasure_impl(
  69. std::move(exec), std::move(func));
  70. uninit_ptr.release();
  71. return ptr;
  72. }
  73. struct deleter_t
  74. {
  75. allocator_type allocator;
  76. deleter_t(const Func& func)
  77. : allocator(get_associated_allocator(func))
  78. {
  79. }
  80. void operator()(completion_handler_erasure_impl* p)
  81. {
  82. std::allocator_traits<allocator_type>::destroy(allocator, p);
  83. std::allocator_traits<allocator_type>::deallocate(allocator, p, 1);
  84. }
  85. };
  86. virtual Return call(Args... args) override
  87. {
  88. std::unique_ptr<completion_handler_erasure_impl,
  89. deleter_t> p(this, deleter_t(func));
  90. Func f(std::move(func));
  91. p.reset();
  92. std::move(f)(std::move(args)...);
  93. }
  94. virtual void destroy() override
  95. {
  96. std::unique_ptr<completion_handler_erasure_impl,
  97. deleter_t>(this, deleter_t(func));
  98. }
  99. Func func;
  100. };
  101. template<typename Signature, typename Executor = any_io_executor>
  102. struct completion_handler_erasure;
  103. template<typename Return, typename... Args, typename Executor>
  104. struct completion_handler_erasure<Return(Args...), Executor>
  105. {
  106. struct deleter_t
  107. {
  108. void operator()(
  109. completion_handler_erasure_base<Return(Args...), Executor>* p)
  110. {
  111. p->destroy();
  112. }
  113. };
  114. completion_handler_erasure(const completion_handler_erasure&) = delete;
  115. completion_handler_erasure(completion_handler_erasure&&) = default;
  116. completion_handler_erasure& operator=(
  117. const completion_handler_erasure&) = delete;
  118. completion_handler_erasure& operator=(
  119. completion_handler_erasure&&) = default;
  120. constexpr completion_handler_erasure() = default;
  121. constexpr completion_handler_erasure(nullptr_t)
  122. : completion_handler_erasure()
  123. {
  124. }
  125. template<typename Func>
  126. completion_handler_erasure(Executor exec, Func&& func)
  127. : impl_(completion_handler_erasure_impl<
  128. std::decay_t<Func>, Return(Args...), Executor>::make(
  129. std::move(exec), std::forward<Func>(func)))
  130. {
  131. }
  132. ~completion_handler_erasure()
  133. {
  134. if (impl_)
  135. {
  136. Executor executor(impl_->executor);
  137. asio::dispatch(executor,
  138. [impl = std::move(impl_)]() mutable
  139. {
  140. impl.reset();
  141. });
  142. }
  143. }
  144. Return operator()(Args... args)
  145. {
  146. if (impl_)
  147. impl_.release()->call(std::move(args)...);
  148. }
  149. constexpr bool operator==(nullptr_t) const noexcept {return impl_ == nullptr;}
  150. constexpr bool operator!=(nullptr_t) const noexcept {return impl_ != nullptr;}
  151. constexpr bool operator!() const noexcept {return impl_ == nullptr;}
  152. private:
  153. std::unique_ptr<
  154. completion_handler_erasure_base<Return(Args...), Executor>, deleter_t>
  155. impl_;
  156. };
  157. } // namespace detail
  158. } // namespace experimental
  159. } // namespace asio
  160. #endif // ASIO_EXPERIMENTAL_DETAIL_COMPLETION_HANDLER_ERASURE_HPP