File indexing completed on 2025-01-18 09:29:32
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #ifndef BOOST_BEAST_WEBSOCKET_DETAIL_DECORATOR_HPP
0011 #define BOOST_BEAST_WEBSOCKET_DETAIL_DECORATOR_HPP
0012
0013 #include <boost/beast/websocket/rfc6455.hpp>
0014 #include <boost/core/exchange.hpp>
0015 #include <boost/type_traits/aligned_storage.hpp>
0016 #include <boost/type_traits/make_void.hpp>
0017 #include <algorithm>
0018 #include <memory>
0019 #include <new>
0020 #include <type_traits>
0021 #include <utility>
0022
0023 namespace boost {
0024 namespace beast {
0025 namespace websocket {
0026 namespace detail {
0027
0028
0029
0030
0031
0032 template<class T, class U, class = void>
0033 struct can_invoke_with : std::false_type
0034 {
0035 };
0036
0037 template<class T, class U>
0038 struct can_invoke_with<T, U, boost::void_t<decltype(
0039 std::declval<T&>()(std::declval<U&>()))>>
0040 : std::true_type
0041 {
0042 };
0043
0044 template<class T>
0045 using is_decorator = std::integral_constant<bool,
0046 can_invoke_with<T, request_type>::value ||
0047 can_invoke_with<T, response_type>::value>;
0048
0049 class decorator
0050 {
0051 friend class decorator_test;
0052
0053 struct incomplete;
0054
0055 struct exemplar
0056 {
0057 void (incomplete::*mf)();
0058 std::shared_ptr<incomplete> sp;
0059 void* param;
0060 };
0061
0062 union storage
0063 {
0064 void* p_;
0065 void (*fn_)();
0066 typename boost::aligned_storage<
0067 sizeof(exemplar),
0068 alignof(exemplar)>::type buf_;
0069 };
0070
0071 struct vtable
0072 {
0073 void (*move)(
0074 storage& dst, storage& src) noexcept;
0075 void (*destroy)(storage& dst) noexcept;
0076 void (*invoke_req)(
0077 storage& dst, request_type& req);
0078 void (*invoke_res)(
0079 storage& dst, response_type& req);
0080
0081 static void move_fn(
0082 storage&, storage&) noexcept
0083 {
0084 }
0085
0086 static void destroy_fn(
0087 storage&) noexcept
0088 {
0089 }
0090
0091 static void invoke_req_fn(
0092 storage&, request_type&)
0093 {
0094 }
0095
0096 static void invoke_res_fn(
0097 storage&, response_type&)
0098 {
0099 }
0100
0101 static vtable const* get_default()
0102 {
0103 static const vtable impl{
0104 &move_fn,
0105 &destroy_fn,
0106 &invoke_req_fn,
0107 &invoke_res_fn
0108 };
0109 return &impl;
0110 }
0111 };
0112
0113 template<class F, bool Inline =
0114 (sizeof(F) <= sizeof(storage) &&
0115 alignof(F) <= alignof(storage) &&
0116 std::is_nothrow_move_constructible<F>::value)>
0117 struct vtable_impl;
0118
0119 storage storage_;
0120 vtable const* vtable_ = vtable::get_default();
0121
0122
0123
0124
0125
0126 template<class T, class U, class = void>
0127 struct maybe_invoke
0128 {
0129 void
0130 operator()(T&, U&)
0131 {
0132 }
0133 };
0134
0135 template<class T, class U>
0136 struct maybe_invoke<T, U, boost::void_t<decltype(
0137 std::declval<T&>()(std::declval<U&>()))>>
0138 {
0139 void
0140 operator()(T& t, U& u)
0141 {
0142 t(u);
0143 }
0144 };
0145
0146 public:
0147 decorator() = default;
0148 decorator(decorator const&) = delete;
0149 decorator& operator=(decorator const&) = delete;
0150
0151 ~decorator()
0152 {
0153 vtable_->destroy(storage_);
0154 }
0155
0156 decorator(decorator&& other) noexcept
0157 : vtable_(boost::exchange(
0158 other.vtable_, vtable::get_default()))
0159 {
0160 vtable_->move(
0161 storage_, other.storage_);
0162 }
0163
0164 template<class F,
0165 class = typename std::enable_if<
0166 ! std::is_convertible<
0167 F, decorator>::value>::type>
0168 explicit
0169 decorator(F&& f)
0170 : vtable_(vtable_impl<
0171 typename std::decay<F>::type>::
0172 construct(storage_, std::forward<F>(f)))
0173 {
0174 }
0175
0176 decorator&
0177 operator=(decorator&& other) noexcept
0178 {
0179 vtable_->destroy(storage_);
0180 vtable_ = boost::exchange(
0181 other.vtable_, vtable::get_default());
0182 vtable_->move(storage_, other.storage_);
0183 return *this;
0184 }
0185
0186 void
0187 operator()(request_type& req)
0188 {
0189 vtable_->invoke_req(storage_, req);
0190 }
0191
0192 void
0193 operator()(response_type& res)
0194 {
0195 vtable_->invoke_res(storage_, res);
0196 }
0197 };
0198
0199 template<class F>
0200 struct decorator::vtable_impl<F, true>
0201 {
0202 template<class Arg>
0203 static
0204 vtable const*
0205 construct(storage& dst, Arg&& arg)
0206 {
0207 ::new (static_cast<void*>(&dst.buf_)) F(
0208 std::forward<Arg>(arg));
0209 return get();
0210 }
0211
0212 static
0213 void
0214 move(storage& dst, storage& src) noexcept
0215 {
0216 auto& f = *beast::detail::launder_cast<F*>(&src.buf_);
0217 ::new (&dst.buf_) F(std::move(f));
0218 }
0219
0220 static
0221 void
0222 destroy(storage& dst) noexcept
0223 {
0224 beast::detail::launder_cast<F*>(&dst.buf_)->~F();
0225 }
0226
0227 static
0228 void
0229 invoke_req(storage& dst, request_type& req)
0230 {
0231 maybe_invoke<F, request_type>{}(
0232 *beast::detail::launder_cast<F*>(&dst.buf_), req);
0233 }
0234
0235 static
0236 void
0237 invoke_res(storage& dst, response_type& res)
0238 {
0239 maybe_invoke<F, response_type>{}(
0240 *beast::detail::launder_cast<F*>(&dst.buf_), res);
0241 }
0242
0243 static
0244 vtable
0245 const* get()
0246 {
0247 static constexpr vtable impl{
0248 &move,
0249 &destroy,
0250 &invoke_req,
0251 &invoke_res};
0252 return &impl;
0253 }
0254 };
0255
0256 template<class F>
0257 struct decorator::vtable_impl<F, false>
0258 {
0259 template<class Arg>
0260 static
0261 vtable const*
0262 construct(storage& dst, Arg&& arg)
0263 {
0264 dst.p_ = new F(std::forward<Arg>(arg));
0265 return get();
0266 }
0267
0268 static
0269 void
0270 move(storage& dst, storage& src) noexcept
0271 {
0272 dst.p_ = src.p_;
0273 }
0274
0275 static
0276 void
0277 destroy(storage& dst) noexcept
0278 {
0279 delete static_cast<F*>(dst.p_);
0280 }
0281
0282 static
0283 void
0284 invoke_req(
0285 storage& dst, request_type& req)
0286 {
0287 maybe_invoke<F, request_type>{}(
0288 *static_cast<F*>(dst.p_), req);
0289 }
0290
0291 static
0292 void
0293 invoke_res(
0294 storage& dst, response_type& res)
0295 {
0296 maybe_invoke<F, response_type>{}(
0297 *static_cast<F*>(dst.p_), res);
0298 }
0299
0300 static
0301 vtable const*
0302 get()
0303 {
0304 static constexpr vtable impl{&move,
0305 &destroy, &invoke_req, &invoke_res};
0306 return &impl;
0307 }
0308 };
0309
0310 }
0311 }
0312 }
0313 }
0314
0315 #endif