123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315 |
- //
- // 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 <boost/beast/websocket/rfc6455.hpp>
- #include <boost/core/exchange.hpp>
- #include <boost/type_traits/aligned_storage.hpp>
- #include <boost/type_traits/make_void.hpp>
- #include <algorithm>
- #include <memory>
- #include <new>
- #include <type_traits>
- #include <utility>
- 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<class T, class U, class = void>
- struct can_invoke_with : std::false_type
- {
- };
- template<class T, class U>
- struct can_invoke_with<T, U, boost::void_t<decltype(
- std::declval<T&>()(std::declval<U&>()))>>
- : std::true_type
- {
- };
- template<class T>
- using is_decorator = std::integral_constant<bool,
- can_invoke_with<T, request_type>::value ||
- can_invoke_with<T, response_type>::value>;
- class decorator
- {
- friend class decorator_test;
- struct incomplete;
- struct exemplar
- {
- void (incomplete::*mf)();
- std::shared_ptr<incomplete> sp;
- void* param;
- };
- union storage
- {
- void* p_;
- void (*fn_)();
- typename boost::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<class F, bool Inline =
- (sizeof(F) <= sizeof(storage) &&
- alignof(F) <= alignof(storage) &&
- std::is_nothrow_move_constructible<F>::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<class T, class U, class = void>
- struct maybe_invoke
- {
- void
- operator()(T&, U&)
- {
- }
- };
- template<class T, class U>
- struct maybe_invoke<T, U, boost::void_t<decltype(
- std::declval<T&>()(std::declval<U&>()))>>
- {
- 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<class F,
- class = typename std::enable_if<
- ! std::is_convertible<
- F, decorator>::value>::type>
- explicit
- decorator(F&& f)
- : vtable_(vtable_impl<
- typename std::decay<F>::type>::
- construct(storage_, std::forward<F>(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<class F>
- struct decorator::vtable_impl<F, true>
- {
- template<class Arg>
- static
- vtable const*
- construct(storage& dst, Arg&& arg)
- {
- ::new (static_cast<void*>(&dst.buf_)) F(
- std::forward<Arg>(arg));
- return get();
- }
- static
- void
- move(storage& dst, storage& src) noexcept
- {
- auto& f = *beast::detail::launder_cast<F*>(&src.buf_);
- ::new (&dst.buf_) F(std::move(f));
- }
- static
- void
- destroy(storage& dst) noexcept
- {
- beast::detail::launder_cast<F*>(&dst.buf_)->~F();
- }
- static
- void
- invoke_req(storage& dst, request_type& req)
- {
- maybe_invoke<F, request_type>{}(
- *beast::detail::launder_cast<F*>(&dst.buf_), req);
- }
- static
- void
- invoke_res(storage& dst, response_type& res)
- {
- maybe_invoke<F, response_type>{}(
- *beast::detail::launder_cast<F*>(&dst.buf_), res);
- }
- static
- vtable
- const* get()
- {
- static constexpr vtable impl{
- &move,
- &destroy,
- &invoke_req,
- &invoke_res};
- return &impl;
- }
- };
- template<class F>
- struct decorator::vtable_impl<F, false>
- {
- template<class Arg>
- static
- vtable const*
- construct(storage& dst, Arg&& arg)
- {
- dst.p_ = new F(std::forward<Arg>(arg));
- return get();
- }
- static
- void
- move(storage& dst, storage& src) noexcept
- {
- dst.p_ = src.p_;
- }
- static
- void
- destroy(storage& dst) noexcept
- {
- delete static_cast<F*>(dst.p_);
- }
- static
- void
- invoke_req(
- storage& dst, request_type& req)
- {
- maybe_invoke<F, request_type>{}(
- *static_cast<F*>(dst.p_), req);
- }
- static
- void
- invoke_res(
- storage& dst, response_type& res)
- {
- maybe_invoke<F, response_type>{}(
- *static_cast<F*>(dst.p_), res);
- }
- static
- vtable const*
- get()
- {
- static constexpr vtable impl{&move,
- &destroy, &invoke_req, &invoke_res};
- return &impl;
- }
- };
- } // detail
- } // websocket
- } // beast
- } // boost
- #endif
|