mirror of
https://github.com/boostorg/beast.git
synced 2025-08-02 14:24:31 +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/detail/config.hpp>
|
||||||
#include <boost/beast/core/static_string.hpp>
|
#include <boost/beast/core/static_string.hpp>
|
||||||
#include <boost/beast/core/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/message.hpp>
|
||||||
|
#include <boost/beast/http/string_body.hpp>
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
|
||||||
@@ -21,6 +23,12 @@ namespace boost {
|
|||||||
namespace beast {
|
namespace beast {
|
||||||
namespace websocket {
|
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.
|
/** Returns `true` if the specified HTTP request is a WebSocket Upgrade.
|
||||||
|
|
||||||
This function returns `true` when the passed HTTP Request
|
This function returns `true` when the passed HTTP Request
|
||||||
|
@@ -37,12 +37,6 @@ namespace boost {
|
|||||||
namespace beast {
|
namespace beast {
|
||||||
namespace websocket {
|
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.
|
/** The type of received control frame.
|
||||||
|
|
||||||
Values of this type are passed to the control frame
|
Values of this type are passed to the control frame
|
||||||
|
@@ -16,6 +16,7 @@ add_executable (tests-beast-websocket
|
|||||||
${EXTRAS_FILES}
|
${EXTRAS_FILES}
|
||||||
${TEST_MAIN}
|
${TEST_MAIN}
|
||||||
Jamfile
|
Jamfile
|
||||||
|
_detail_decorator.cpp
|
||||||
_detail_prng.cpp
|
_detail_prng.cpp
|
||||||
_detail_impl_base.cpp
|
_detail_impl_base.cpp
|
||||||
test.hpp
|
test.hpp
|
||||||
|
@@ -8,6 +8,7 @@
|
|||||||
#
|
#
|
||||||
|
|
||||||
local SOURCES =
|
local SOURCES =
|
||||||
|
_detail_decorator.cpp
|
||||||
_detail_impl_base.cpp
|
_detail_impl_base.cpp
|
||||||
_detail_prng.cpp
|
_detail_prng.cpp
|
||||||
accept.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