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

source code of boost/libs/beast/include/boost/beast/websocket/detail/decorator.hpp