// // Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // // Official repository: https://github.com/boostorg/beast // #ifndef BOOST_BEAST_WEBSOCKET_DETAIL_DECORATOR_HPP #define BOOST_BEAST_WEBSOCKET_DETAIL_DECORATOR_HPP #include #include #include #include #include #include #include #include namespace boost { namespace beast { namespace websocket { namespace detail { // VFALCO NOTE: When this is two traits, one for // request and one for response, // Visual Studio 2015 fails. template struct can_invoke_with : std::false_type { }; template struct can_invoke_with()(std::declval()))>> : std::true_type { }; template using is_decorator = std::integral_constant::value || can_invoke_with::value>; class decorator { friend class decorator_test; struct incomplete; struct exemplar { void (incomplete::*mf)(); std::shared_ptr sp; void* param; }; union storage { void* p_; void (*fn_)(); typename std::aligned_storage< sizeof(exemplar), alignof(exemplar)>::type buf_; }; struct vtable { void (*move)( storage& dst, storage& src) noexcept; void (*destroy)(storage& dst) noexcept; void (*invoke_req)( storage& dst, request_type& req); void (*invoke_res)( storage& dst, response_type& req); static void move_fn( storage&, storage&) noexcept { } static void destroy_fn( storage&) noexcept { } static void invoke_req_fn( storage&, request_type&) { } static void invoke_res_fn( storage&, response_type&) { } static vtable const* get_default() { static const vtable impl{ &move_fn, &destroy_fn, &invoke_req_fn, &invoke_res_fn }; return &impl; } }; template::value)> struct vtable_impl; storage storage_; vtable const* vtable_ = vtable::get_default(); // VFALCO NOTE: When this is two traits, one for // request and one for response, // Visual Studio 2015 fails. template struct maybe_invoke { void operator()(T&, U&) { } }; template struct maybe_invoke()(std::declval()))>> { void operator()(T& t, U& u) { t(u); } }; public: decorator() = default; decorator(decorator const&) = delete; decorator& operator=(decorator const&) = delete; ~decorator() { vtable_->destroy(storage_); } decorator(decorator&& other) noexcept : vtable_(boost::exchange( other.vtable_, vtable::get_default())) { vtable_->move( storage_, other.storage_); } template::value>::type> explicit decorator(F&& f) : vtable_(vtable_impl< typename std::decay::type>:: construct(storage_, std::forward(f))) { } decorator& operator=(decorator&& other) noexcept { vtable_->destroy(storage_); vtable_ = boost::exchange( other.vtable_, vtable::get_default()); vtable_->move(storage_, other.storage_); return *this; } void operator()(request_type& req) { vtable_->invoke_req(storage_, req); } void operator()(response_type& res) { vtable_->invoke_res(storage_, res); } }; template struct decorator::vtable_impl { template static vtable const* construct(storage& dst, Arg&& arg) { ::new (static_cast(&dst.buf_)) F( std::forward(arg)); return get(); } static void move(storage& dst, storage& src) noexcept { auto& f = *beast::detail::launder_cast(&src.buf_); ::new (&dst.buf_) F(std::move(f)); } static void destroy(storage& dst) noexcept { beast::detail::launder_cast(&dst.buf_)->~F(); } static void invoke_req(storage& dst, request_type& req) { maybe_invoke{}( *beast::detail::launder_cast(&dst.buf_), req); } static void invoke_res(storage& dst, response_type& res) { maybe_invoke{}( *beast::detail::launder_cast(&dst.buf_), res); } static vtable const* get() { static constexpr vtable impl{ &move, &destroy, &invoke_req, &invoke_res}; return &impl; } }; template struct decorator::vtable_impl { template static vtable const* construct(storage& dst, Arg&& arg) { dst.p_ = new F(std::forward(arg)); return get(); } static void move(storage& dst, storage& src) noexcept { dst.p_ = src.p_; } static void destroy(storage& dst) noexcept { delete static_cast(dst.p_); } static void invoke_req( storage& dst, request_type& req) { maybe_invoke{}( *static_cast(dst.p_), req); } static void invoke_res( storage& dst, response_type& res) { maybe_invoke{}( *static_cast(dst.p_), res); } static vtable const* get() { static constexpr vtable impl{&move, &destroy, &invoke_req, &invoke_res}; return &impl; } }; } // detail } // websocket } // beast } // boost #endif