mirror of
https://github.com/boostorg/beast.git
synced 2025-07-31 21:34:46 +02:00
Add detail::decorator
This commit is contained in:
225
include/boost/beast/websocket/detail/decorator.hpp
Normal file
225
include/boost/beast/websocket/detail/decorator.hpp
Normal file
@@ -0,0 +1,225 @@
|
||||
//
|
||||
// Copyright (c) 2016-2017 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/beast/core/detail/type_traits.hpp>
|
||||
#include <boost/core/empty_value.hpp>
|
||||
#include <boost/core/exchange.hpp>
|
||||
#include <boost/type_traits/make_void.hpp>
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <new>
|
||||
#include <utility>
|
||||
|
||||
namespace boost {
|
||||
namespace beast {
|
||||
namespace websocket {
|
||||
namespace detail {
|
||||
|
||||
class decorator
|
||||
{
|
||||
struct incomplete;
|
||||
|
||||
static std::size_t constexpr Bytes =
|
||||
beast::detail::max_sizeof<
|
||||
void*,
|
||||
void const*,
|
||||
void(*)(),
|
||||
void(incomplete::*)(),
|
||||
decltype(std::bind(
|
||||
std::declval<void(incomplete::*)()>(),
|
||||
std::declval<std::shared_ptr<incomplete>>()))
|
||||
>();
|
||||
|
||||
struct none
|
||||
{
|
||||
};
|
||||
|
||||
struct base
|
||||
{
|
||||
virtual ~base() = default;
|
||||
|
||||
virtual
|
||||
base*
|
||||
move(void* to) = 0;
|
||||
|
||||
virtual
|
||||
void
|
||||
invoke(request_type&) = 0;
|
||||
|
||||
virtual
|
||||
void
|
||||
invoke(response_type&) = 0;
|
||||
};
|
||||
|
||||
template<class T, class = void>
|
||||
struct is_req_op : std::false_type
|
||||
{
|
||||
};
|
||||
|
||||
template<class T>
|
||||
struct is_req_op<T, boost::void_t<decltype(
|
||||
std::declval<T&>()(std::declval<request_type&>())
|
||||
)>> : std::true_type
|
||||
{
|
||||
};
|
||||
|
||||
template<class T, class = void>
|
||||
struct is_res_op : std::false_type
|
||||
{
|
||||
};
|
||||
|
||||
template<class T>
|
||||
struct is_res_op<T, boost::void_t<decltype(
|
||||
std::declval<T&>()(std::declval<response_type&>())
|
||||
)>> : std::true_type
|
||||
{
|
||||
};
|
||||
|
||||
template<class F>
|
||||
struct impl : base,
|
||||
boost::empty_value<F>
|
||||
{
|
||||
impl(impl&&) = default;
|
||||
|
||||
template<class F_>
|
||||
explicit
|
||||
impl(F_&& f)
|
||||
: boost::empty_value<F>(
|
||||
boost::empty_init_t{},
|
||||
std::forward<F_>(f))
|
||||
{
|
||||
}
|
||||
|
||||
base*
|
||||
move(void* to) override
|
||||
{
|
||||
return ::new(to) impl(
|
||||
std::move(this->get()));
|
||||
}
|
||||
|
||||
void
|
||||
invoke(request_type& req) override
|
||||
{
|
||||
this->invoke(req, is_req_op<F>{});
|
||||
}
|
||||
|
||||
void
|
||||
invoke(request_type& req, std::true_type)
|
||||
{
|
||||
this->get()(req);
|
||||
}
|
||||
|
||||
void
|
||||
invoke(request_type&, std::false_type)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
invoke(response_type& res) override
|
||||
{
|
||||
this->invoke(res, is_res_op<F>{});
|
||||
}
|
||||
|
||||
void
|
||||
invoke(response_type& res, std::true_type)
|
||||
{
|
||||
this->get()(res);
|
||||
}
|
||||
|
||||
void
|
||||
invoke(response_type&, std::false_type)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
using type = typename
|
||||
std::aligned_storage<Bytes>::type;
|
||||
|
||||
type buf_;
|
||||
base* base_;
|
||||
|
||||
public:
|
||||
decorator()
|
||||
: decorator(none{})
|
||||
{
|
||||
}
|
||||
|
||||
decorator(
|
||||
decorator&& other)
|
||||
{
|
||||
if(other.is_inline())
|
||||
{
|
||||
base_ = other.base_->move(&buf_);
|
||||
other.base_->~base();
|
||||
}
|
||||
else
|
||||
{
|
||||
base_ = other.base_;
|
||||
}
|
||||
other.base_ = ::new(&other.buf_)
|
||||
impl<none>(none{});
|
||||
}
|
||||
|
||||
template<class F>
|
||||
explicit
|
||||
decorator(F&& f)
|
||||
: base_(sizeof(F) <= sizeof(buf_) ?
|
||||
::new(&buf_) impl<
|
||||
typename std::decay<F>::type>(
|
||||
std::forward<F>(f)) :
|
||||
new impl<
|
||||
typename std::decay<F>::type>(
|
||||
std::forward<F>(f)))
|
||||
{
|
||||
}
|
||||
|
||||
~decorator()
|
||||
{
|
||||
if(is_inline())
|
||||
base_->~base();
|
||||
else
|
||||
delete base_;
|
||||
}
|
||||
|
||||
bool
|
||||
is_inline() const noexcept
|
||||
{
|
||||
return
|
||||
! std::less<void const*>()(
|
||||
reinterpret_cast<void const*>(base_),
|
||||
reinterpret_cast<void const*>(&buf_)) &&
|
||||
std::less<void const*>()(
|
||||
reinterpret_cast<void const*>(base_),
|
||||
reinterpret_cast<void const*>(&buf_ + 1));
|
||||
}
|
||||
|
||||
void
|
||||
operator()(request_type& req)
|
||||
{
|
||||
base_->invoke(req);
|
||||
}
|
||||
|
||||
void
|
||||
operator()(response_type& res)
|
||||
{
|
||||
base_->invoke(res);
|
||||
}
|
||||
};
|
||||
|
||||
} // detail
|
||||
} // websocket
|
||||
} // beast
|
||||
} // boost
|
||||
|
||||
#endif
|
@@ -13,7 +13,9 @@
|
||||
#include <boost/beast/core/detail/config.hpp>
|
||||
#include <boost/beast/core/static_string.hpp>
|
||||
#include <boost/beast/core/string.hpp>
|
||||
#include <boost/beast/http/empty_body.hpp>
|
||||
#include <boost/beast/http/message.hpp>
|
||||
#include <boost/beast/http/string_body.hpp>
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
|
||||
@@ -21,6 +23,12 @@ namespace boost {
|
||||
namespace beast {
|
||||
namespace websocket {
|
||||
|
||||
/// The type of object holding HTTP Upgrade requests
|
||||
using request_type = http::request<http::empty_body>;
|
||||
|
||||
/// The type of object holding HTTP Upgrade responses
|
||||
using response_type = http::response<http::string_body>;
|
||||
|
||||
/** Returns `true` if the specified HTTP request is a WebSocket Upgrade.
|
||||
|
||||
This function returns `true` when the passed HTTP Request
|
||||
|
@@ -37,12 +37,6 @@ namespace boost {
|
||||
namespace beast {
|
||||
namespace websocket {
|
||||
|
||||
/// The type of object holding HTTP Upgrade requests
|
||||
using request_type = http::request<http::empty_body>;
|
||||
|
||||
/// The type of object holding HTTP Upgrade responses
|
||||
using response_type = http::response<http::string_body>;
|
||||
|
||||
/** The type of received control frame.
|
||||
|
||||
Values of this type are passed to the control frame
|
||||
|
@@ -16,6 +16,7 @@ add_executable (tests-beast-websocket
|
||||
${EXTRAS_FILES}
|
||||
${TEST_MAIN}
|
||||
Jamfile
|
||||
_detail_decorator.cpp
|
||||
_detail_prng.cpp
|
||||
_detail_impl_base.cpp
|
||||
test.hpp
|
||||
|
@@ -8,6 +8,7 @@
|
||||
#
|
||||
|
||||
local SOURCES =
|
||||
_detail_decorator.cpp
|
||||
_detail_impl_base.cpp
|
||||
_detail_prng.cpp
|
||||
accept.cpp
|
||||
|
133
test/beast/websocket/_detail_decorator.cpp
Normal file
133
test/beast/websocket/_detail_decorator.cpp
Normal file
@@ -0,0 +1,133 @@
|
||||
//
|
||||
// Copyright (c) 2016-2017 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
|
||||
//
|
||||
|
||||
// Test that header file is self-contained.
|
||||
#include <boost/beast/websocket/detail/decorator.hpp>
|
||||
|
||||
#include <boost/beast/_experimental/unit_test/suite.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace beast {
|
||||
namespace websocket {
|
||||
namespace detail {
|
||||
|
||||
class decorator_test : public unit_test::suite
|
||||
{
|
||||
public:
|
||||
struct req_t
|
||||
{
|
||||
bool pass_ = false;
|
||||
|
||||
req_t() = default;
|
||||
|
||||
~req_t()
|
||||
{
|
||||
BEAST_EXPECT(pass_);
|
||||
}
|
||||
|
||||
req_t(req_t&& other)
|
||||
: pass_(boost::exchange(other.pass_, true))
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
operator()(request_type&)
|
||||
{
|
||||
BEAST_EXPECT(! pass_);
|
||||
pass_ = true;
|
||||
}
|
||||
};
|
||||
|
||||
struct res_t
|
||||
{
|
||||
bool pass_ = false;
|
||||
|
||||
res_t() = default;
|
||||
|
||||
~res_t()
|
||||
{
|
||||
BEAST_EXPECT(pass_);
|
||||
}
|
||||
|
||||
res_t(res_t&& other)
|
||||
: pass_(boost::exchange(other.pass_, true))
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
operator()(response_type&)
|
||||
{
|
||||
BEAST_EXPECT(! pass_);
|
||||
pass_ = true;
|
||||
}
|
||||
};
|
||||
|
||||
struct both_t : res_t , req_t
|
||||
{
|
||||
};
|
||||
|
||||
struct big_t : both_t
|
||||
{
|
||||
char buf[2048];
|
||||
};
|
||||
|
||||
void
|
||||
dec_req(request_type&)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
testDecorator()
|
||||
{
|
||||
request_type req;
|
||||
response_type res;
|
||||
|
||||
decorator{}(req);
|
||||
decorator{}(res);
|
||||
decorator{req_t{}}(req);
|
||||
decorator{res_t{}}(res);
|
||||
|
||||
{
|
||||
decorator d(both_t{});
|
||||
d(req);
|
||||
d(res);
|
||||
}
|
||||
|
||||
{
|
||||
decorator d(big_t{});
|
||||
d(req);
|
||||
d(res);
|
||||
}
|
||||
|
||||
{
|
||||
decorator d1{req_t{}};
|
||||
decorator d2{std::move(d1)};
|
||||
d2(req);
|
||||
}
|
||||
|
||||
{
|
||||
decorator d(std::bind(
|
||||
&decorator_test::dec_req, this));
|
||||
BEAST_EXPECT(d.is_inline());
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
run() override
|
||||
{
|
||||
testDecorator();
|
||||
}
|
||||
};
|
||||
|
||||
BEAST_DEFINE_TESTSUITE(beast,websocket,decorator);
|
||||
|
||||
} // detail
|
||||
} // websocket
|
||||
} // beast
|
||||
} // boost
|
Reference in New Issue
Block a user