decorator.hpp 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315
  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_WEBSOCKET_DETAIL_DECORATOR_HPP
  10. #define BOOST_BEAST_WEBSOCKET_DETAIL_DECORATOR_HPP
  11. #include <boost/beast/websocket/rfc6455.hpp>
  12. #include <boost/core/exchange.hpp>
  13. #include <boost/type_traits/aligned_storage.hpp>
  14. #include <boost/type_traits/make_void.hpp>
  15. #include <algorithm>
  16. #include <memory>
  17. #include <new>
  18. #include <type_traits>
  19. #include <utility>
  20. namespace boost {
  21. namespace beast {
  22. namespace websocket {
  23. namespace detail {
  24. // VFALCO NOTE: When this is two traits, one for
  25. // request and one for response,
  26. // Visual Studio 2015 fails.
  27. template<class T, class U, class = void>
  28. struct can_invoke_with : std::false_type
  29. {
  30. };
  31. template<class T, class U>
  32. struct can_invoke_with<T, U, boost::void_t<decltype(
  33. std::declval<T&>()(std::declval<U&>()))>>
  34. : std::true_type
  35. {
  36. };
  37. template<class T>
  38. using is_decorator = std::integral_constant<bool,
  39. can_invoke_with<T, request_type>::value ||
  40. can_invoke_with<T, response_type>::value>;
  41. class decorator
  42. {
  43. friend class decorator_test;
  44. struct incomplete;
  45. struct exemplar
  46. {
  47. void (incomplete::*mf)();
  48. std::shared_ptr<incomplete> sp;
  49. void* param;
  50. };
  51. union storage
  52. {
  53. void* p_;
  54. void (*fn_)();
  55. typename boost::aligned_storage<
  56. sizeof(exemplar),
  57. alignof(exemplar)>::type buf_;
  58. };
  59. struct vtable
  60. {
  61. void (*move)(
  62. storage& dst, storage& src) noexcept;
  63. void (*destroy)(storage& dst) noexcept;
  64. void (*invoke_req)(
  65. storage& dst, request_type& req);
  66. void (*invoke_res)(
  67. storage& dst, response_type& req);
  68. static void move_fn(
  69. storage&, storage&) noexcept
  70. {
  71. }
  72. static void destroy_fn(
  73. storage&) noexcept
  74. {
  75. }
  76. static void invoke_req_fn(
  77. storage&, request_type&)
  78. {
  79. }
  80. static void invoke_res_fn(
  81. storage&, response_type&)
  82. {
  83. }
  84. static vtable const* get_default()
  85. {
  86. static const vtable impl{
  87. &move_fn,
  88. &destroy_fn,
  89. &invoke_req_fn,
  90. &invoke_res_fn
  91. };
  92. return &impl;
  93. }
  94. };
  95. template<class F, bool Inline =
  96. (sizeof(F) <= sizeof(storage) &&
  97. alignof(F) <= alignof(storage) &&
  98. std::is_nothrow_move_constructible<F>::value)>
  99. struct vtable_impl;
  100. storage storage_;
  101. vtable const* vtable_ = vtable::get_default();
  102. // VFALCO NOTE: When this is two traits, one for
  103. // request and one for response,
  104. // Visual Studio 2015 fails.
  105. template<class T, class U, class = void>
  106. struct maybe_invoke
  107. {
  108. void
  109. operator()(T&, U&)
  110. {
  111. }
  112. };
  113. template<class T, class U>
  114. struct maybe_invoke<T, U, boost::void_t<decltype(
  115. std::declval<T&>()(std::declval<U&>()))>>
  116. {
  117. void
  118. operator()(T& t, U& u)
  119. {
  120. t(u);
  121. }
  122. };
  123. public:
  124. decorator() = default;
  125. decorator(decorator const&) = delete;
  126. decorator& operator=(decorator const&) = delete;
  127. ~decorator()
  128. {
  129. vtable_->destroy(storage_);
  130. }
  131. decorator(decorator&& other) noexcept
  132. : vtable_(boost::exchange(
  133. other.vtable_, vtable::get_default()))
  134. {
  135. vtable_->move(
  136. storage_, other.storage_);
  137. }
  138. template<class F,
  139. class = typename std::enable_if<
  140. ! std::is_convertible<
  141. F, decorator>::value>::type>
  142. explicit
  143. decorator(F&& f)
  144. : vtable_(vtable_impl<
  145. typename std::decay<F>::type>::
  146. construct(storage_, std::forward<F>(f)))
  147. {
  148. }
  149. decorator&
  150. operator=(decorator&& other) noexcept
  151. {
  152. vtable_->destroy(storage_);
  153. vtable_ = boost::exchange(
  154. other.vtable_, vtable::get_default());
  155. vtable_->move(storage_, other.storage_);
  156. return *this;
  157. }
  158. void
  159. operator()(request_type& req)
  160. {
  161. vtable_->invoke_req(storage_, req);
  162. }
  163. void
  164. operator()(response_type& res)
  165. {
  166. vtable_->invoke_res(storage_, res);
  167. }
  168. };
  169. template<class F>
  170. struct decorator::vtable_impl<F, true>
  171. {
  172. template<class Arg>
  173. static
  174. vtable const*
  175. construct(storage& dst, Arg&& arg)
  176. {
  177. ::new (static_cast<void*>(&dst.buf_)) F(
  178. std::forward<Arg>(arg));
  179. return get();
  180. }
  181. static
  182. void
  183. move(storage& dst, storage& src) noexcept
  184. {
  185. auto& f = *beast::detail::launder_cast<F*>(&src.buf_);
  186. ::new (&dst.buf_) F(std::move(f));
  187. }
  188. static
  189. void
  190. destroy(storage& dst) noexcept
  191. {
  192. beast::detail::launder_cast<F*>(&dst.buf_)->~F();
  193. }
  194. static
  195. void
  196. invoke_req(storage& dst, request_type& req)
  197. {
  198. maybe_invoke<F, request_type>{}(
  199. *beast::detail::launder_cast<F*>(&dst.buf_), req);
  200. }
  201. static
  202. void
  203. invoke_res(storage& dst, response_type& res)
  204. {
  205. maybe_invoke<F, response_type>{}(
  206. *beast::detail::launder_cast<F*>(&dst.buf_), res);
  207. }
  208. static
  209. vtable
  210. const* get()
  211. {
  212. static constexpr vtable impl{
  213. &move,
  214. &destroy,
  215. &invoke_req,
  216. &invoke_res};
  217. return &impl;
  218. }
  219. };
  220. template<class F>
  221. struct decorator::vtable_impl<F, false>
  222. {
  223. template<class Arg>
  224. static
  225. vtable const*
  226. construct(storage& dst, Arg&& arg)
  227. {
  228. dst.p_ = new F(std::forward<Arg>(arg));
  229. return get();
  230. }
  231. static
  232. void
  233. move(storage& dst, storage& src) noexcept
  234. {
  235. dst.p_ = src.p_;
  236. }
  237. static
  238. void
  239. destroy(storage& dst) noexcept
  240. {
  241. delete static_cast<F*>(dst.p_);
  242. }
  243. static
  244. void
  245. invoke_req(
  246. storage& dst, request_type& req)
  247. {
  248. maybe_invoke<F, request_type>{}(
  249. *static_cast<F*>(dst.p_), req);
  250. }
  251. static
  252. void
  253. invoke_res(
  254. storage& dst, response_type& res)
  255. {
  256. maybe_invoke<F, response_type>{}(
  257. *static_cast<F*>(dst.p_), res);
  258. }
  259. static
  260. vtable const*
  261. get()
  262. {
  263. static constexpr vtable impl{&move,
  264. &destroy, &invoke_req, &invoke_res};
  265. return &impl;
  266. }
  267. };
  268. } // detail
  269. } // websocket
  270. } // beast
  271. } // boost
  272. #endif