From 3361df142cb5d0a11ebfa1350881b4bb58600b5f Mon Sep 17 00:00:00 2001 From: Vinnie Falco Date: Sat, 2 Dec 2017 11:22:51 -0800 Subject: [PATCH] pausation always allocates --- CHANGELOG.md | 5 +- .../beast/websocket/detail/pausation.hpp | 209 ++++++------------ include/boost/beast/websocket/impl/read.ipp | 6 +- include/boost/beast/websocket/impl/write.ipp | 2 +- 4 files changed, 78 insertions(+), 144 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0a7340d7..df471fc2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,9 @@ Version 149: * built-in r-value return values can't be assigned * Tidy up ssl_stream special members +* Fix CMakeLists.txt variable +* Protect calls from macros +* pausation always allocates -------------------------------------------------------------------------------- @@ -10,8 +13,6 @@ Version 148: * Install codecov on codecov CI targets only * Update reports for hybrid assessment * Handle invalid deflate frames -* Fix CMakeLists.txt variable -* Protect calls from macros -------------------------------------------------------------------------------- diff --git a/include/boost/beast/websocket/detail/pausation.hpp b/include/boost/beast/websocket/detail/pausation.hpp index f51ee103..e3870b03 100644 --- a/include/boost/beast/websocket/detail/pausation.hpp +++ b/include/boost/beast/websocket/detail/pausation.hpp @@ -10,13 +10,10 @@ #ifndef BOOST_BEAST_WEBSOCKET_DETAIL_PAUSATION_HPP #define BOOST_BEAST_WEBSOCKET_DETAIL_PAUSATION_HPP -#include +#include #include -#include #include -#include #include -#include #include namespace boost { @@ -30,124 +27,59 @@ namespace detail { // class pausation { - struct base + struct handler { - base() = default; - base(base &&) = delete; - base(base const&) = delete; - virtual ~base() = default; - virtual void operator()() = 0; + handler() = default; + handler(handler &&) = delete; + handler(handler const&) = delete; + virtual ~handler() = default; + virtual void destroy() = 0; + virtual void invoke() = 0; }; - template - struct holder : base + template + class impl : public handler { - F f; - - holder(holder&&) = default; - - template - explicit - holder(U&& u) - : f(std::forward(u)) - { - } - - void - operator()() override - { - F f_(std::move(f)); - this->~holder(); - // invocation of f_() can - // assign a new object to *this. - f_(); - } - }; - - struct exemplar : boost::asio::coroutine - { - struct H - { - void operator()(); - }; - - struct T - { - using handler_type = H; - }; - - handler_ptr hp; - - void operator()(); - }; - - template - class saved_op - { - Op* op_ = nullptr; + Handler h_; public: - ~saved_op() + template + impl(DeducedHandler&& h) + : h_(std::forward(h)) { - if(op_) - { - Op op(std::move(*op_)); - op_->~Op(); - typename std::allocator_traits< - boost::asio::associated_allocator_t>:: - template rebind_alloc alloc{ - boost::asio::get_associated_allocator(op)}; - std::allocator_traits< - decltype(alloc)>::deallocate(alloc, op_, 1); - } - } - - saved_op(saved_op&& other) - : op_(other.op_) - { - other.op_ = nullptr; - } - - saved_op& operator=(saved_op&& other) - { - BOOST_ASSERT(! op_); - op_ = other.op_; - other.op_ = 0; - return *this; - } - - explicit - saved_op(Op&& op) - { - typename std::allocator_traits< - boost::asio::associated_allocator_t>:: - template rebind_alloc alloc{ - boost::asio::get_associated_allocator(op)}; - auto const p = std::allocator_traits< - decltype(alloc)>::allocate(alloc, 1); - op_ = new(p) Op{std::move(op)}; } void - operator()() + destroy() override { - BOOST_ASSERT(op_); - Op op{std::move(*op_)}; - typename std::allocator_traits< - boost::asio::associated_allocator_t>:: - template rebind_alloc alloc{ - boost::asio::get_associated_allocator(op)}; - std::allocator_traits< - decltype(alloc)>::deallocate(alloc, op_, 1); - op_ = nullptr; - op(); + Handler h(std::move(h_)); + typename beast::detail::allocator_traits< + boost::asio::associated_allocator_t< + Handler>>::template rebind_alloc alloc{ + boost::asio::get_associated_allocator(h)}; + beast::detail::allocator_traits< + decltype(alloc)>::destroy(alloc, this); + beast::detail::allocator_traits< + decltype(alloc)>::deallocate(alloc, this, 1); + } + + void + invoke() override + { + Handler h(std::move(h_)); + typename beast::detail::allocator_traits< + boost::asio::associated_allocator_t< + Handler>>::template rebind_alloc alloc{ + boost::asio::get_associated_allocator(h)}; + beast::detail::allocator_traits< + decltype(alloc)>::destroy(alloc, this); + beast::detail::allocator_traits< + decltype(alloc)>::deallocate(alloc, this, 1); + h(); } }; - using buf_type = char[sizeof(holder)]; - - base* base_ = nullptr; - alignas(holder) buf_type buf_; + handler* h_ = nullptr; public: pausation() = default; @@ -156,69 +88,70 @@ public: ~pausation() { - if(base_) - base_->~base(); + if(h_) + h_->destroy(); } pausation(pausation&& other) { boost::ignore_unused(other); - BOOST_ASSERT(! other.base_); + BOOST_ASSERT(! other.h_); } pausation& operator=(pausation&& other) { boost::ignore_unused(other); - BOOST_ASSERT(! base_); - BOOST_ASSERT(! other.base_); + BOOST_ASSERT(! h_); + BOOST_ASSERT(! other.h_); return *this; } - template + template void - emplace(F&& f); - - template - void - save(F&& f); + emplace(CompletionHandler&& handler); explicit operator bool() const { - return base_ != nullptr; + return h_ != nullptr; } bool maybe_invoke() { - if(base_) + if(h_) { - auto const basep = base_; - base_ = nullptr; - (*basep)(); + auto const h = h_; + h_ = nullptr; + h->invoke(); return true; } return false; } }; -template +template void -pausation::emplace(F&& f) +pausation::emplace(CompletionHandler&& handler) { - using type = holder::type>; - static_assert(sizeof(buf_type) >= sizeof(type), - "buffer too small"); - BOOST_ASSERT(! base_); - base_ = ::new(buf_) type{std::forward(f)}; -} - -template -void -pausation::save(F&& f) -{ - emplace(saved_op{std::move(f)}); + BOOST_ASSERT(! h_); + typename beast::detail::allocator_traits< + boost::asio::associated_allocator_t< + CompletionHandler>>::template rebind_alloc< + impl> alloc{ + boost::asio::get_associated_allocator(handler)}; + using A = decltype(alloc); + auto const d = + [&alloc](impl* p) + { + beast::detail::allocator_traits::deallocate(alloc, p, 1); + }; + std::unique_ptr, decltype(d)> p{ + beast::detail::allocator_traits::allocate(alloc, 1), d}; + beast::detail::allocator_traits::construct( + alloc, p.get(), std::forward(handler)); + h_ = p.release(); } } // detail diff --git a/include/boost/beast/websocket/impl/read.ipp b/include/boost/beast/websocket/impl/read.ipp index 68d3168c..369d3977 100644 --- a/include/boost/beast/websocket/impl/read.ipp +++ b/include/boost/beast/websocket/impl/read.ipp @@ -152,7 +152,7 @@ operator()( // Suspend BOOST_ASSERT(ws_.rd_block_ != tok_); BOOST_ASIO_CORO_YIELD - ws_.paused_r_rd_.save(std::move(*this)); + ws_.paused_r_rd_.emplace(std::move(*this)); // Acquire the read block BOOST_ASSERT(! ws_.rd_block_); @@ -275,7 +275,7 @@ operator()( // Suspend BOOST_ASSERT(ws_.wr_block_ != tok_); BOOST_ASIO_CORO_YIELD - ws_.paused_rd_.save(std::move(*this)); + ws_.paused_rd_.emplace(std::move(*this)); // Acquire the write block BOOST_ASSERT(! ws_.wr_block_); @@ -580,7 +580,7 @@ operator()( // Suspend BOOST_ASSERT(ws_.wr_block_ != tok_); BOOST_ASIO_CORO_YIELD - ws_.paused_rd_.save(std::move(*this)); + ws_.paused_rd_.emplace(std::move(*this)); // Acquire the write block BOOST_ASSERT(! ws_.wr_block_); diff --git a/include/boost/beast/websocket/impl/write.ipp b/include/boost/beast/websocket/impl/write.ipp index a54064bc..c99bdf3b 100644 --- a/include/boost/beast/websocket/impl/write.ipp +++ b/include/boost/beast/websocket/impl/write.ipp @@ -208,7 +208,7 @@ operator()( // Suspend BOOST_ASSERT(ws_.wr_block_ != tok_); BOOST_ASIO_CORO_YIELD - ws_.paused_wr_.save(std::move(*this)); + ws_.paused_wr_.emplace(std::move(*this)); // Acquire the write block BOOST_ASSERT(! ws_.wr_block_);