Add detail::decorator

This commit is contained in:
Vinnie Falco
2019-02-17 13:22:14 -08:00
parent 79c777e776
commit e831e8b7ee
6 changed files with 368 additions and 6 deletions

View 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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -8,6 +8,7 @@
#
local SOURCES =
_detail_decorator.cpp
_detail_impl_base.cpp
_detail_prng.cpp
accept.cpp

View 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