decorator.hpp 6.6 KB

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