From 01e1fa2dc94d4d2577fcc774e5caac0e729f60f9 Mon Sep 17 00:00:00 2001 From: Vinnie Falco Date: Mon, 2 Jan 2017 13:29:48 -0500 Subject: [PATCH] Implement asio dealloc-before-invoke guarantee: fix #215 This change guarantees that temporary memory allocated through the asio hooks by the Beast implementation is deallocated before invoking the final handler when performing composed operations. The change is accomplished by replacing std::shared_ptr with a thread-safe custom container handler_ptr to manage composed operation state. The container tracks other instances which manage the same object and resets them in a safe way before invoking the final handler. handler_ptr is provided as a public interface so that users of this library can utilize the same idiom to write their own composed operations. --- CHANGELOG.md | 1 + doc/quickref.xml | 1 + examples/http_async_server.hpp | 26 ++- include/beast/core/handler_ptr.hpp | 173 ++++++++++++++++++ .../beast/core/impl/dynabuf_readstream.ipp | 22 +-- include/beast/core/impl/handler_ptr.ipp | 137 ++++++++++++++ include/beast/http/impl/parse.ipp | 29 ++- include/beast/http/impl/read.ipp | 57 +++--- include/beast/http/impl/write.ipp | 71 +++---- include/beast/websocket/detail/invokable.hpp | 16 +- include/beast/websocket/impl/accept.ipp | 70 +++---- include/beast/websocket/impl/close.ipp | 26 ++- include/beast/websocket/impl/handshake.ipp | 26 ++- include/beast/websocket/impl/ping.ipp | 31 ++-- include/beast/websocket/impl/read.ipp | 57 +++--- include/beast/websocket/impl/ssl.ipp | 31 ++-- include/beast/websocket/impl/teardown.ipp | 36 ++-- include/beast/websocket/impl/write.ipp | 75 +++----- test/Jamfile | 1 + test/core/CMakeLists.txt | 1 + test/core/handler_ptr.cpp | 9 + 21 files changed, 574 insertions(+), 322 deletions(-) create mode 100644 include/beast/core/handler_ptr.hpp create mode 100644 include/beast/core/impl/handler_ptr.ipp create mode 100644 test/core/handler_ptr.cpp diff --git a/CHANGELOG.md b/CHANGELOG.md index d94d9132..113af4cb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ 1.0.0-b22 * Fix broken Intellisense +* Implement the Asio deallocation-before-invocation guarantee -------------------------------------------------------------------------------- diff --git a/doc/quickref.xml b/doc/quickref.xml index 443a55e7..3fe63b3e 100644 --- a/doc/quickref.xml +++ b/doc/quickref.xml @@ -174,6 +174,7 @@ error_code error_condition handler_alloc + handler_ptr static_streambuf static_streambuf_n static_string diff --git a/examples/http_async_server.hpp b/examples/http_async_server.hpp index 350f4a38..bfb5b9ba 100644 --- a/examples/http_async_server.hpp +++ b/examples/http_async_server.hpp @@ -12,6 +12,7 @@ #include "mime_type.hpp" #include +#include #include #include #include @@ -93,24 +94,21 @@ private: struct data { + bool cont; Stream& s; message m; - Handler h; - bool cont; - template - data(DeducedHandler&& h_, Stream& s_, + data(Handler& handler, Stream& s_, message&& m_) - : s(s_) + : cont(boost_asio_handler_cont_helpers:: + is_continuation(handler)) + , s(s_) , m(std::move(m_)) - , h(std::forward(h_)) - , cont(boost_asio_handler_cont_helpers:: - is_continuation(h)) { } }; - std::shared_ptr d_; + handler_ptr d_; public: write_op(write_op&&) = default; @@ -118,7 +116,7 @@ private: template write_op(DeducedHandler&& h, Stream& s, Args&&... args) - : d_(std::allocate_shared(alloc_type{h}, + : d_(make_handler_ptr( std::forward(h), s, std::forward(args)...)) { @@ -135,7 +133,7 @@ private: beast::http::async_write(d.s, d.m, std::move(*this)); return; } - d.h(ec); + d_.invoke(ec); } friend @@ -143,7 +141,7 @@ private: std::size_t size, write_op* op) { return boost_asio_handler_alloc_helpers:: - allocate(size, op->d_->h); + allocate(size, op->d_.handler()); } friend @@ -151,7 +149,7 @@ private: void* p, std::size_t size, write_op* op) { return boost_asio_handler_alloc_helpers:: - deallocate(p, size, op->d_->h); + deallocate(p, size, op->d_.handler()); } friend @@ -165,7 +163,7 @@ private: void asio_handler_invoke(Function&& f, write_op* op) { return boost_asio_handler_invoke_helpers:: - invoke(f, op->d_->h); + invoke(f, op->d_.handler()); } }; diff --git a/include/beast/core/handler_ptr.hpp b/include/beast/core/handler_ptr.hpp new file mode 100644 index 00000000..175be8bb --- /dev/null +++ b/include/beast/core/handler_ptr.hpp @@ -0,0 +1,173 @@ +// +// Copyright (c) 2013-2016 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) +// + +#ifndef BEAST_HANDLER_PTR_HPP +#define BEAST_HANDLER_PTR_HPP + +#include +#include +#include +#include + +namespace beast { + +/** A smart pointer container. + + This is a smart pointer that retains shared ownership of an + object through a pointer. Memory is managed using the allocation + and deallocation functions associated with a completion handler, + which is also stored in the object. The object is destroyed and + its memory deallocated when one of the following happens: + + @li The function @ref invoke is called. + + @li The function @ref release_handler is called + + @li The last remaining container owning the object is destroyed + + Objects of this type are used in the implementation of + composed operations. Typically the composed operation's shared + state is managed by the @ref handler_ptr and an allocator + associated with the final handler is used to create the managed + object. + + @note The reference count is stored using a 16 bit unsigned + integer. Making more than 2^16 copies of one object results + in undefined behavior. +*/ +template +class handler_ptr +{ + struct P + { + T* t; + std::atomic n; + + // There's no way to put the handler anywhere else + // without exposing ourselves to race conditions + // and all sorts of ugliness. + // See: + // https://github.com/vinniefalco/Beast/issues/215 + Handler handler; + + template + P(DeducedHandler&& handler, Args&&... args); + }; + + P* p_; + + template + handler_ptr(int, DeducedHandler&& handler, Args&&... args); + +public: + /// The type of handler this object stores + using handler_type = Handler; + + /// Copy assignment (disallowed). + handler_ptr& operator=(handler_ptr const&) = delete; + + /** Destructs the owned object if no more @ref handler_ptr link to it. + + If `*this` owns an object and it is the last @ref handler_ptr + owning it, the object is destroyed and the memory deallocated + using the associated deallocator. + */ + ~handler_ptr(); + + /** Move constructor. + + When this call returns, the moved-from container + will have no owned object. + */ + handler_ptr(handler_ptr&& other); + + /// Copy constructor + handler_ptr(handler_ptr const& other); + + /// Returns a reference to the handler + handler_type& + handler() const + { + return p_->handler; + } + + /// Returns a pointer to the owned object + T* + get() const + { + return p_->t; + } + + /// Return a reference to the owned object. + T& + operator*() const + { + return *get(); + } + + /// Return a pointer to the owned object. + T* + operator->() const + { + return get(); + } + + /** Release ownership of the handler + + If `*this` owns an object, it is first destroyed. + + @return The released handler. + */ + handler_type + release_handler(); + + /** Invoke the handler in the owned object. + + This function invokes the handler in the owned object + with a forwarded argument list. Before the invocation, + the owned object is destroyed, satisfying the + deallocation-before-invocation Asio guarantee. All + instances of @ref handler_ptr which refer to the + same owned object will be reset, including this instance. + */ + template + void + invoke(Args&&... args); + + // VFALCO The free function interface works around + // a horrible Visual Studio 15 Update 3 bug + + /** Construct a new `handler_ptr`. + + @param handler The handler. The allocator associated with + the handler will be used to allocate memory for the owned + object. This argument will be forwarded to the owned object's + constructor. + + @param args Optional arguments forwarded to + the owned object's constructor. + */ + /** @{ */ + template + friend + handler_ptr + make_handler_ptr( + CompletionHandler&& handler, Args&&... args); + + template + friend + handler_ptr + make_handler_ptr( + CompletionHandler const& handler, Args&&... args); + /** @} */ +}; + +} // beast + +#include + +#endif diff --git a/include/beast/core/impl/dynabuf_readstream.ipp b/include/beast/core/impl/dynabuf_readstream.ipp index 5403536e..43790f07 100644 --- a/include/beast/core/impl/dynabuf_readstream.ipp +++ b/include/beast/core/impl/dynabuf_readstream.ipp @@ -12,6 +12,7 @@ #include #include #include +#include namespace beast { @@ -23,25 +24,22 @@ class dynabuf_readstream< using alloc_type = handler_alloc; + // VFALCO What about bool cont for is_continuation? struct data { dynabuf_readstream& srs; MutableBufferSequence bs; - Handler h; int state = 0; - template - data(DeducedHandler&& h_, - dynabuf_readstream& srs_, + data(Handler&, dynabuf_readstream& srs_, MutableBufferSequence const& bs_) : srs(srs_) , bs(bs_) - , h(std::forward(h_)) { } }; - std::shared_ptr d_; + handler_ptr d_; public: read_some_op(read_some_op&&) = default; @@ -50,7 +48,7 @@ public: template read_some_op(DeducedHandler&& h, dynabuf_readstream& srs, Args&&... args) - : d_(std::allocate_shared(alloc_type{h}, + : d_(make_handler_ptr( std::forward(h), srs, std::forward(args)...)) { @@ -66,7 +64,7 @@ public: std::size_t size, read_some_op* op) { return boost_asio_handler_alloc_helpers:: - allocate(size, op->d_->h); + allocate(size, op->d_.handler()); } friend @@ -74,14 +72,14 @@ public: void* p, std::size_t size, read_some_op* op) { return boost_asio_handler_alloc_helpers:: - deallocate(p, size, op->d_->h); + deallocate(p, size, op->d_.handler()); } friend bool asio_handler_is_continuation(read_some_op* op) { return boost_asio_handler_cont_helpers:: - is_continuation(op->d_->h); + is_continuation(op->d_.handler()); } template @@ -89,7 +87,7 @@ public: void asio_handler_invoke(Function&& f, read_some_op* op) { return boost_asio_handler_invoke_helpers:: - invoke(f, op->d_->h); + invoke(f, op->d_.handler()); } }; @@ -149,7 +147,7 @@ read_some_op::operator()( break; } } - d.h(ec, bytes_transferred); + d_.invoke(ec, bytes_transferred); } //------------------------------------------------------------------------------ diff --git a/include/beast/core/impl/handler_ptr.ipp b/include/beast/core/impl/handler_ptr.ipp new file mode 100644 index 00000000..152628c4 --- /dev/null +++ b/include/beast/core/impl/handler_ptr.ipp @@ -0,0 +1,137 @@ +// +// Copyright (c) 2013-2016 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) +// + +#ifndef BEAST_IMPL_HANDLER_PTR_HPP +#define BEAST_IMPL_HANDLER_PTR_HPP + +#include +#include +#include + +namespace beast { + +template +template +inline +handler_ptr::P:: +P(DeducedHandler&& h, Args&&... args) + : n(1) + , handler(std::forward(h)) +{ + t = reinterpret_cast( + boost_asio_handler_alloc_helpers:: + allocate(sizeof(T), handler)); + try + { + t = new(t) T{handler, + std::forward(args)...}; + } + catch(...) + { + boost_asio_handler_alloc_helpers:: + deallocate(t, sizeof(T), handler); + throw; + } +} + +template +template +handler_ptr:: +handler_ptr(int, DeducedHandler&& handler, Args&&... args) + : p_(new P(std::forward(handler), + std::forward(args)...)) +{ +} + +template +handler_ptr:: +~handler_ptr() +{ + if(! p_) + return; + if(--p_->n) + return; + if(p_->t) + { + p_->t->~T(); + boost_asio_handler_alloc_helpers:: + deallocate(p_->t, sizeof(T), p_->handler); + } + delete p_; +} + +template +handler_ptr:: +handler_ptr(handler_ptr&& other) + : p_(other.p_) +{ + other.p_ = nullptr; +} + +template +handler_ptr:: +handler_ptr(handler_ptr const& other) + : p_(other.p_) +{ + if(p_) + ++p_->n; +} + +template +auto +handler_ptr:: +release_handler() -> + handler_type +{ + BOOST_ASSERT(p_); + BOOST_ASSERT(p_->t); + p_->t->~T(); + boost_asio_handler_alloc_helpers:: + deallocate(p_->t, sizeof(T), p_->handler); + p_->t = nullptr; + return std::move(p_->handler); +} + +template +template +void +handler_ptr:: +invoke(Args&&... args) +{ + BOOST_ASSERT(p_); + BOOST_ASSERT(p_->t); + p_->t->~T(); + boost_asio_handler_alloc_helpers:: + deallocate(p_->t, sizeof(T), p_->handler); + p_->t = nullptr; + p_->handler(std::forward(args)...); +} + +template< + class T, class CompletionHandler, class... Args> +handler_ptr +make_handler_ptr( + CompletionHandler&& handler, Args&&... args) +{ + return handler_ptr{0, + std::move(handler), + std::forward(args)...}; +} + +template< + class T, class CompletionHandler, class... Args> +handler_ptr +make_handler_ptr( + CompletionHandler const& handler, Args&&... args) +{ + return handler_ptr{0, + handler, std::forward(args)...}; +} + +} // beast + +#endif diff --git a/include/beast/http/impl/parse.ipp b/include/beast/http/impl/parse.ipp index 6a717de5..ab38c143 100644 --- a/include/beast/http/impl/parse.ipp +++ b/include/beast/http/impl/parse.ipp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include @@ -23,34 +24,28 @@ template class parse_op { - using alloc_type = - handler_alloc; - struct data { + bool cont; Stream& s; DynamicBuffer& db; Parser& p; - Handler h; bool got_some = false; - bool cont; int state = 0; - template - data(DeducedHandler&& h_, Stream& s_, + data(Handler& handler, Stream& s_, DynamicBuffer& sb_, Parser& p_) - : s(s_) + : cont(boost_asio_handler_cont_helpers:: + is_continuation(handler)) + , s(s_) , db(sb_) , p(p_) - , h(std::forward(h_)) - , cont(boost_asio_handler_cont_helpers:: - is_continuation(h)) { BOOST_ASSERT(! p.complete()); } }; - std::shared_ptr d_; + handler_ptr d_; public: parse_op(parse_op&&) = default; @@ -58,7 +53,7 @@ public: template parse_op(DeducedHandler&& h, Stream& s, Args&&... args) - : d_(std::allocate_shared(alloc_type{h}, + : d_(make_handler_ptr( std::forward(h), s, std::forward(args)...)) { @@ -74,7 +69,7 @@ public: std::size_t size, parse_op* op) { return boost_asio_handler_alloc_helpers:: - allocate(size, op->d_->h); + allocate(size, op->d_.handler()); } friend @@ -82,7 +77,7 @@ public: void* p, std::size_t size, parse_op* op) { return boost_asio_handler_alloc_helpers:: - deallocate(p, size, op->d_->h); + deallocate(p, size, op->d_.handler()); } friend @@ -96,7 +91,7 @@ public: void asio_handler_invoke(Function&& f, parse_op* op) { return boost_asio_handler_invoke_helpers:: - invoke(f, op->d_->h); + invoke(f, op->d_.handler()); } }; @@ -214,7 +209,7 @@ operator()(error_code ec, std::size_t bytes_transferred, bool again) } } } - d.h(ec); + d_.invoke(ec); } } // detail diff --git a/include/beast/http/impl/read.ipp b/include/beast/http/impl/read.ipp index 6a96355a..d569c2e8 100644 --- a/include/beast/http/impl/read.ipp +++ b/include/beast/http/impl/read.ipp @@ -14,6 +14,7 @@ #include #include #include +#include #include #include @@ -27,9 +28,6 @@ template class read_header_op { - using alloc_type = - handler_alloc; - using parser_type = header_parser_v1; @@ -38,29 +36,26 @@ class read_header_op struct data { + bool cont; Stream& s; DynamicBuffer& db; message_type& m; parser_type p; - Handler h; bool started = false; - bool cont; int state = 0; - template - data(DeducedHandler&& h_, Stream& s_, + data(Handler& handler, Stream& s_, DynamicBuffer& sb_, message_type& m_) - : s(s_) + : cont(boost_asio_handler_cont_helpers:: + is_continuation(handler)) + , s(s_) , db(sb_) , m(m_) - , h(std::forward(h_)) - , cont(boost_asio_handler_cont_helpers:: - is_continuation(h)) { } }; - std::shared_ptr d_; + handler_ptr d_; public: read_header_op(read_header_op&&) = default; @@ -69,7 +64,7 @@ public: template read_header_op( DeducedHandler&& h, Stream& s, Args&&... args) - : d_(std::allocate_shared(alloc_type{h}, + : d_(make_handler_ptr( std::forward(h), s, std::forward(args)...)) { @@ -84,7 +79,7 @@ public: std::size_t size, read_header_op* op) { return boost_asio_handler_alloc_helpers:: - allocate(size, op->d_->h); + allocate(size, op->d_.handler()); } friend @@ -92,7 +87,7 @@ public: void* p, std::size_t size, read_header_op* op) { return boost_asio_handler_alloc_helpers:: - deallocate(p, size, op->d_->h); + deallocate(p, size, op->d_.handler()); } friend @@ -106,7 +101,7 @@ public: void asio_handler_invoke(Function&& f, read_header_op* op) { return boost_asio_handler_invoke_helpers:: - invoke(f, op->d_->h); + invoke(f, op->d_.handler()); } }; @@ -135,7 +130,7 @@ operator()(error_code ec, bool again) break; } } - d.h(ec); + d_.invoke(ec); } } // detail @@ -206,9 +201,6 @@ template class read_op { - using alloc_type = - handler_alloc; - using parser_type = parser_v1; @@ -217,29 +209,26 @@ class read_op struct data { + bool cont; Stream& s; DynamicBuffer& db; message_type& m; parser_type p; - Handler h; bool started = false; - bool cont; int state = 0; - template - data(DeducedHandler&& h_, Stream& s_, + data(Handler& handler, Stream& s_, DynamicBuffer& sb_, message_type& m_) - : s(s_) + : cont(boost_asio_handler_cont_helpers:: + is_continuation(handler)) + , s(s_) , db(sb_) , m(m_) - , h(std::forward(h_)) - , cont(boost_asio_handler_cont_helpers:: - is_continuation(h)) { } }; - std::shared_ptr d_; + handler_ptr d_; public: read_op(read_op&&) = default; @@ -247,7 +236,7 @@ public: template read_op(DeducedHandler&& h, Stream& s, Args&&... args) - : d_(std::allocate_shared(alloc_type{h}, + : d_(make_handler_ptr( std::forward(h), s, std::forward(args)...)) { @@ -262,7 +251,7 @@ public: std::size_t size, read_op* op) { return boost_asio_handler_alloc_helpers:: - allocate(size, op->d_->h); + allocate(size, op->d_.handler()); } friend @@ -270,7 +259,7 @@ public: void* p, std::size_t size, read_op* op) { return boost_asio_handler_alloc_helpers:: - deallocate(p, size, op->d_->h); + deallocate(p, size, op->d_.handler()); } friend @@ -284,7 +273,7 @@ public: void asio_handler_invoke(Function&& f, read_op* op) { return boost_asio_handler_invoke_helpers:: - invoke(f, op->d_->h); + invoke(f, op->d_.handler()); } }; @@ -313,7 +302,7 @@ operator()(error_code ec, bool again) break; } } - d.h(ec); + d_.invoke(ec); } } // detail diff --git a/include/beast/http/impl/write.ipp b/include/beast/http/impl/write.ipp index e5b83ab2..87e63e1f 100644 --- a/include/beast/http/impl/write.ipp +++ b/include/beast/http/impl/write.ipp @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -99,30 +100,24 @@ namespace detail { template class write_streambuf_op { - using alloc_type = - handler_alloc; - struct data { + bool cont; Stream& s; streambuf sb; - Handler h; - bool cont; int state = 0; - template - data(DeducedHandler&& h_, Stream& s_, + data(Handler& handler, Stream& s_, streambuf&& sb_) - : s(s_) + : cont(boost_asio_handler_cont_helpers:: + is_continuation(handler)) + , s(s_) , sb(std::move(sb_)) - , h(std::forward(h_)) - , cont(boost_asio_handler_cont_helpers:: - is_continuation(h)) { } }; - std::shared_ptr d_; + handler_ptr d_; public: write_streambuf_op(write_streambuf_op&&) = default; @@ -131,19 +126,13 @@ public: template write_streambuf_op(DeducedHandler&& h, Stream& s, Args&&... args) - : d_(std::allocate_shared(alloc_type{h}, - std::forward(h), s, - std::forward(args)...)) + : d_(make_handler_ptr( + std::forward(h), + s, std::forward(args)...)) { (*this)(error_code{}, 0, false); } - explicit - write_streambuf_op(std::shared_ptr d) - : d_(std::move(d)) - { - } - void operator()(error_code ec, std::size_t bytes_transferred, bool again = true); @@ -153,7 +142,7 @@ public: std::size_t size, write_streambuf_op* op) { return boost_asio_handler_alloc_helpers:: - allocate(size, op->d_->h); + allocate(size, op->d_.handler()); } friend @@ -161,7 +150,7 @@ public: void* p, std::size_t size, write_streambuf_op* op) { return boost_asio_handler_alloc_helpers:: - deallocate(p, size, op->d_->h); + deallocate(p, size, op->d_.handler()); } friend @@ -175,7 +164,7 @@ public: void asio_handler_invoke(Function&& f, write_streambuf_op* op) { return boost_asio_handler_invoke_helpers:: - invoke(f, op->d_->h); + invoke(f, op->d_.handler()); } }; @@ -199,7 +188,7 @@ operator()(error_code ec, std::size_t, bool again) } } } - d.h(ec); + d_.invoke(ec); } } // detail @@ -301,29 +290,23 @@ template class write_op { - using alloc_type = - handler_alloc; - struct data { + bool cont; Stream& s; // VFALCO How do we use handler_alloc in write_preparation? write_preparation< isRequest, Body, Fields> wp; - Handler h; resume_context resume; resume_context copy; - bool cont; int state = 0; - template - data(DeducedHandler&& h_, Stream& s_, + data(Handler& handler, Stream& s_, message const& m_) - : s(s_) + : cont(boost_asio_handler_cont_helpers:: + is_continuation(handler)) + , s(s_) , wp(m_) - , h(std::forward(h_)) - , cont(boost_asio_handler_cont_helpers:: - is_continuation(h)) { } }; @@ -382,7 +365,7 @@ class write_op } }; - std::shared_ptr d_; + handler_ptr d_; public: write_op(write_op&&) = default; @@ -390,7 +373,7 @@ public: template write_op(DeducedHandler&& h, Stream& s, Args&&... args) - : d_(std::allocate_shared(alloc_type{h}, + : d_(make_handler_ptr( std::forward(h), s, std::forward(args)...)) { @@ -410,7 +393,7 @@ public: } explicit - write_op(std::shared_ptr d) + write_op(handler_ptr d) : d_(std::move(d)) { } @@ -424,7 +407,7 @@ public: std::size_t size, write_op* op) { return boost_asio_handler_alloc_helpers:: - allocate(size, op->d_->h); + allocate(size, op->d_.handler()); } friend @@ -432,7 +415,7 @@ public: void* p, std::size_t size, write_op* op) { return boost_asio_handler_alloc_helpers:: - deallocate(p, size, op->d_->h); + deallocate(p, size, op->d_.handler()); } friend @@ -446,7 +429,7 @@ public: void asio_handler_invoke(Function&& f, write_op* op) { return boost_asio_handler_invoke_helpers:: - invoke(f, op->d_->h); + invoke(f, op->d_.handler()); } }; @@ -552,9 +535,9 @@ operator()(error_code ec, std::size_t, bool again) break; } } - d.h(ec); - d.resume = {}; d.copy = {}; + d.resume = {}; + d_.invoke(ec); } template diff --git a/include/beast/websocket/detail/invokable.hpp b/include/beast/websocket/detail/invokable.hpp index fb19d0c9..7fcfc2cf 100644 --- a/include/beast/websocket/detail/invokable.hpp +++ b/include/beast/websocket/detail/invokable.hpp @@ -8,6 +8,7 @@ #ifndef BEAST_WEBSOCKET_DETAIL_INVOKABLE_HPP #define BEAST_WEBSOCKET_DETAIL_INVOKABLE_HPP +#include #include #include #include @@ -64,8 +65,19 @@ class invokable struct exemplar { - std::shared_ptr _; - void operator()(){} + struct H + { + void operator()(); + }; + + struct T + { + using handler_type = H; + }; + + handler_ptr hp; + + void operator()(); }; using buf_type = char[sizeof(holder)]; diff --git a/include/beast/websocket/impl/accept.ipp b/include/beast/websocket/impl/accept.ipp index 1ce54d32..2d0e13d4 100644 --- a/include/beast/websocket/impl/accept.ipp +++ b/include/beast/websocket/impl/accept.ipp @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -30,27 +31,21 @@ template template class stream::response_op { - using alloc_type = - handler_alloc; - struct data { + bool cont; stream& ws; http::response resp; - Handler h; error_code final_ec; - bool cont; int state = 0; - template - data(DeducedHandler&& h_, stream& ws_, + template + data(Handler&, stream& ws_, http::request const& req, bool cont_) - : ws(ws_) + : cont(cont_) + , ws(ws_) , resp(ws_.build_response(req)) - , h(std::forward(h_)) - , cont(cont_) { // can't call stream::reset() here // otherwise accept_op will malfunction @@ -60,7 +55,7 @@ class stream::response_op } }; - std::shared_ptr d_; + handler_ptr d_; public: response_op(response_op&&) = default; @@ -69,7 +64,7 @@ public: template response_op(DeducedHandler&& h, stream& ws, Args&&... args) - : d_(std::allocate_shared(alloc_type{h}, + : d_(make_handler_ptr( std::forward(h), ws, std::forward(args)...)) { @@ -84,7 +79,7 @@ public: std::size_t size, response_op* op) { return boost_asio_handler_alloc_helpers:: - allocate(size, op->d_->h); + allocate(size, op->d_.handler()); } friend @@ -92,7 +87,7 @@ public: void* p, std::size_t size, response_op* op) { return boost_asio_handler_alloc_helpers:: - deallocate(p, size, op->d_->h); + deallocate(p, size, op->d_.handler()); } friend @@ -106,7 +101,7 @@ public: void asio_handler_invoke(Function&& f, response_op* op) { return boost_asio_handler_invoke_helpers:: - invoke(f, op->d_->h); + invoke(f, op->d_.handler()); } }; @@ -138,7 +133,7 @@ operator()(error_code ec, bool again) break; } } - d.h(ec); + d_.invoke(ec); } //------------------------------------------------------------------------------ @@ -149,24 +144,19 @@ template template class stream::accept_op { - using alloc_type = - handler_alloc; - struct data { + bool cont; stream& ws; http::request req; - Handler h; - bool cont; int state = 0; - template - data(DeducedHandler&& h_, stream& ws_, + template + data(Handler& handler, stream& ws_, Buffers const& buffers) - : ws(ws_) - , h(std::forward(h_)) - , cont(boost_asio_handler_cont_helpers:: - is_continuation(h)) + : cont(boost_asio_handler_cont_helpers:: + is_continuation(handler)) + , ws(ws_) { using boost::asio::buffer_copy; using boost::asio::buffer_size; @@ -177,7 +167,7 @@ class stream::accept_op } }; - std::shared_ptr d_; + handler_ptr d_; public: accept_op(accept_op&&) = default; @@ -186,7 +176,7 @@ public: template accept_op(DeducedHandler&& h, stream& ws, Args&&... args) - : d_(std::allocate_shared(alloc_type{h}, + : d_(make_handler_ptr( std::forward(h), ws, std::forward(args)...)) { @@ -206,7 +196,7 @@ public: std::size_t size, accept_op* op) { return boost_asio_handler_alloc_helpers:: - allocate(size, op->d_->h); + allocate(size, op->d_.handler()); } friend @@ -214,7 +204,7 @@ public: void* p, std::size_t size, accept_op* op) { return boost_asio_handler_alloc_helpers:: - deallocate(p, size, op->d_->h); + deallocate(p, size, op->d_.handler()); } friend @@ -228,7 +218,7 @@ public: void asio_handler_invoke(Function&& f, accept_op* op) { return boost_asio_handler_invoke_helpers:: - invoke(f, op->d_->h); + invoke(f, op->d_.handler()); } }; @@ -256,19 +246,17 @@ operator()(error_code const& ec, // got message case 1: + { // respond to request -#if 1 - // VFALCO I have no idea why passing std::move(*this) crashes - d.state = 99; - d.ws.async_accept(d.req, *this); -#else + auto& ws = d.ws; + auto req = std::move(d.req); response_op{ - std::move(d.h), d.ws, d.req, true}; -#endif + d_.release_handler(), ws, req, true}; return; } + } } - d.h(ec); + d_.invoke(ec); } template diff --git a/include/beast/websocket/impl/close.ipp b/include/beast/websocket/impl/close.ipp index d426907a..e821e24f 100644 --- a/include/beast/websocket/impl/close.ipp +++ b/include/beast/websocket/impl/close.ipp @@ -9,6 +9,7 @@ #define BEAST_WEBSOCKET_IMPL_CLOSE_IPP #include +#include #include #include #include @@ -30,28 +31,25 @@ class stream::close_op struct data : op { + bool cont; stream& ws; close_reason cr; - Handler h; fb_type fb; - bool cont; int state = 0; - template - data(DeducedHandler&& h_, stream& ws_, + data(Handler& handler, stream& ws_, close_reason const& cr_) - : ws(ws_) + : cont(boost_asio_handler_cont_helpers:: + is_continuation(handler)) + , ws(ws_) , cr(cr_) - , h(std::forward(h_)) - , cont(boost_asio_handler_cont_helpers:: - is_continuation(h)) { ws.template write_close< static_streambuf>(fb, cr); } }; - std::shared_ptr d_; + handler_ptr d_; public: close_op(close_op&&) = default; @@ -60,7 +58,7 @@ public: template close_op(DeducedHandler&& h, stream& ws, Args&&... args) - : d_(std::allocate_shared(alloc_type{h}, + : d_(make_handler_ptr( std::forward(h), ws, std::forward(args)...)) { @@ -83,7 +81,7 @@ public: std::size_t size, close_op* op) { return boost_asio_handler_alloc_helpers:: - allocate(size, op->d_->h); + allocate(size, op->d_.handler()); } friend @@ -91,7 +89,7 @@ public: void* p, std::size_t size, close_op* op) { return boost_asio_handler_alloc_helpers:: - deallocate(p, size, op->d_->h); + deallocate(p, size, op->d_.handler()); } friend @@ -105,7 +103,7 @@ public: void asio_handler_invoke(Function&& f, close_op* op) { return boost_asio_handler_invoke_helpers:: - invoke(f, op->d_->h); + invoke(f, op->d_.handler()); } }; @@ -188,7 +186,7 @@ upcall: if(d.ws.wr_block_ == &d) d.ws.wr_block_ = nullptr; d.ws.rd_op_.maybe_invoke(); - d.h(ec); + d_.invoke(ec); } template diff --git a/include/beast/websocket/impl/handshake.ipp b/include/beast/websocket/impl/handshake.ipp index ba96de20..3fc29e32 100644 --- a/include/beast/websocket/impl/handshake.ipp +++ b/include/beast/websocket/impl/handshake.ipp @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -33,29 +34,26 @@ class stream::handshake_op struct data { + bool cont; stream& ws; - Handler h; std::string key; http::request req; http::response resp; - bool cont; int state = 0; - template - data(DeducedHandler&& h_, stream& ws_, + data(Handler& handler, stream& ws_, boost::string_ref const& host, boost::string_ref const& resource) - : ws(ws_) - , h(std::forward(h_)) + : cont(boost_asio_handler_cont_helpers:: + is_continuation(handler)) + , ws(ws_) , req(ws.build_request(host, resource, key)) - , cont(boost_asio_handler_cont_helpers:: - is_continuation(h)) { ws.reset(); } }; - std::shared_ptr d_; + handler_ptr d_; public: handshake_op(handshake_op&&) = default; @@ -64,7 +62,7 @@ public: template handshake_op(DeducedHandler&& h, stream& ws, Args&&... args) - : d_(std::allocate_shared(alloc_type{h}, + : d_(make_handler_ptr( std::forward(h), ws, std::forward(args)...)) { @@ -79,7 +77,7 @@ public: std::size_t size, handshake_op* op) { return boost_asio_handler_alloc_helpers:: - allocate(size, op->d_->h); + allocate(size, op->d_.handler()); } friend @@ -87,7 +85,7 @@ public: void* p, std::size_t size, handshake_op* op) { return boost_asio_handler_alloc_helpers:: - deallocate(p, size, op->d_->h); + deallocate(p, size, op->d_.handler()); } friend @@ -101,7 +99,7 @@ public: void asio_handler_invoke(Function&& f, handshake_op* op) { return boost_asio_handler_invoke_helpers:: - invoke(f, op->d_->h); + invoke(f, op->d_.handler()); } }; @@ -147,7 +145,7 @@ operator()(error_code ec, bool again) } } } - d.h(ec); + d_.invoke(ec); } template diff --git a/include/beast/websocket/impl/ping.ipp b/include/beast/websocket/impl/ping.ipp index cfe91277..f81f107b 100644 --- a/include/beast/websocket/impl/ping.ipp +++ b/include/beast/websocket/impl/ping.ipp @@ -10,6 +10,7 @@ #include #include +#include #include #include #include @@ -25,24 +26,18 @@ template template class stream::ping_op { - using alloc_type = - handler_alloc; - struct data : op { - stream& ws; - Handler h; - detail::frame_streambuf fb; bool cont; + stream& ws; + detail::frame_streambuf fb; int state = 0; - template - data(DeducedHandler&& h_, stream& ws_, + data(Handler& handler, stream& ws_, opcode op_, ping_data const& payload) - : ws(ws_) - , h(std::forward(h_)) - , cont(boost_asio_handler_cont_helpers:: - is_continuation(h)) + : cont(boost_asio_handler_cont_helpers:: + is_continuation(handler)) + , ws(ws_) { using boost::asio::buffer; using boost::asio::buffer_copy; @@ -51,7 +46,7 @@ class stream::ping_op } }; - std::shared_ptr d_; + handler_ptr d_; public: ping_op(ping_op&&) = default; @@ -60,7 +55,7 @@ public: template ping_op(DeducedHandler&& h, stream& ws, Args&&... args) - : d_(std::make_shared( + : d_(make_handler_ptr( std::forward(h), ws, std::forward(args)...)) { @@ -81,7 +76,7 @@ public: std::size_t size, ping_op* op) { return boost_asio_handler_alloc_helpers:: - allocate(size, op->d_->h); + allocate(size, op->d_.handler()); } friend @@ -89,7 +84,7 @@ public: void* p, std::size_t size, ping_op* op) { return boost_asio_handler_alloc_helpers:: - deallocate(p, size, op->d_->h); + deallocate(p, size, op->d_.handler()); } friend @@ -103,7 +98,7 @@ public: void asio_handler_invoke(Function&& f, ping_op* op) { return boost_asio_handler_invoke_helpers:: - invoke(f, op->d_->h); + invoke(f, op->d_.handler()); } }; @@ -187,7 +182,7 @@ upcall: if(d.ws.wr_block_ == &d) d.ws.wr_block_ = nullptr; d.ws.rd_op_.maybe_invoke(); - d.h(ec); + d_.invoke(ec); } template diff --git a/include/beast/websocket/impl/read.ipp b/include/beast/websocket/impl/read.ipp index 02ddd3c2..2469b96f 100644 --- a/include/beast/websocket/impl/read.ipp +++ b/include/beast/websocket/impl/read.ipp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -31,9 +32,6 @@ template template class stream::read_frame_op { - using alloc_type = - handler_alloc; - using fb_type = detail::frame_streambuf; @@ -45,30 +43,27 @@ class stream::read_frame_op struct data : op { + bool cont; stream& ws; frame_info& fi; DynamicBuffer& db; - Handler h; fb_type fb; boost::optional dmb; boost::optional fmb; - bool cont; int state = 0; - template - data(DeducedHandler&& h_, stream& ws_, + data(Handler& handler, stream& ws_, frame_info& fi_, DynamicBuffer& sb_) - : ws(ws_) + : cont(boost_asio_handler_cont_helpers:: + is_continuation(handler)) + , ws(ws_) , fi(fi_) , db(sb_) - , h(std::forward(h_)) - , cont(boost_asio_handler_cont_helpers:: - is_continuation(h)) { } }; - std::shared_ptr d_; + handler_ptr d_; public: read_frame_op(read_frame_op&&) = default; @@ -77,7 +72,7 @@ public: template read_frame_op(DeducedHandler&& h, stream& ws, Args&&... args) - : d_(std::allocate_shared(alloc_type{h}, + : d_(make_handler_ptr( std::forward(h), ws, std::forward(args)...)) { @@ -105,7 +100,7 @@ public: std::size_t size, read_frame_op* op) { return boost_asio_handler_alloc_helpers:: - allocate(size, op->d_->h); + allocate(size, op->d_.handler()); } friend @@ -113,7 +108,7 @@ public: void* p, std::size_t size, read_frame_op* op) { return boost_asio_handler_alloc_helpers:: - deallocate(p, size, op->d_->h); + deallocate(p, size, op->d_.handler()); } friend @@ -127,7 +122,7 @@ public: void asio_handler_invoke(Function&& f, read_frame_op* op) { return boost_asio_handler_invoke_helpers:: - invoke(f, op->d_->h); + invoke(f, op->d_.handler()); } }; @@ -545,7 +540,7 @@ upcall: if(d.ws.wr_block_ == &d) d.ws.wr_block_ = nullptr; d.ws.wr_op_.maybe_invoke(); - d.h(ec); + d_.invoke(ec); } template @@ -734,34 +729,28 @@ template template class stream::read_op { - using alloc_type = - handler_alloc; - struct data { + bool cont; stream& ws; opcode& op; DynamicBuffer& db; - Handler h; frame_info fi; - bool cont; int state = 0; - template - data(DeducedHandler&& h_, + data(Handler& handler, stream& ws_, opcode& op_, DynamicBuffer& sb_) - : ws(ws_) + : cont(boost_asio_handler_cont_helpers:: + is_continuation(handler)) + , ws(ws_) , op(op_) , db(sb_) - , h(std::forward(h_)) - , cont(boost_asio_handler_cont_helpers:: - is_continuation(h)) { } }; - std::shared_ptr d_; + handler_ptr d_; public: read_op(read_op&&) = default; @@ -770,7 +759,7 @@ public: template read_op(DeducedHandler&& h, stream& ws, Args&&... args) - : d_(std::allocate_shared(alloc_type{h}, + : d_(make_handler_ptr( std::forward(h), ws, std::forward(args)...)) { @@ -785,7 +774,7 @@ public: std::size_t size, read_op* op) { return boost_asio_handler_alloc_helpers:: - allocate(size, op->d_->h); + allocate(size, op->d_.handler()); } friend @@ -793,7 +782,7 @@ public: void* p, std::size_t size, read_op* op) { return boost_asio_handler_alloc_helpers:: - deallocate(p, size, op->d_->h); + deallocate(p, size, op->d_.handler()); } friend @@ -807,7 +796,7 @@ public: void asio_handler_invoke(Function&& f, read_op* op) { return boost_asio_handler_invoke_helpers:: - invoke(f, op->d_->h); + invoke(f, op->d_.handler()); } }; @@ -847,7 +836,7 @@ operator()(error_code const& ec, bool again) } } upcall: - d.h(ec); + d_.invoke(ec); } template diff --git a/include/beast/websocket/impl/ssl.ipp b/include/beast/websocket/impl/ssl.ipp index 07570e5c..09a95cec 100644 --- a/include/beast/websocket/impl/ssl.ipp +++ b/include/beast/websocket/impl/ssl.ipp @@ -9,7 +9,9 @@ #define BEAST_WEBSOCKET_IMPL_SSL_IPP_INCLUDED #include +#include #include +#include namespace beast { namespace websocket { @@ -38,31 +40,28 @@ class teardown_ssl_op struct data { - stream_type& stream; - Handler h; bool cont; + stream_type& stream; int state = 0; - template - data(DeducedHandler&& h_, - stream_type& stream_) - : stream(stream_) - , h(std::forward(h_)) - , cont(boost_asio_handler_cont_helpers:: - is_continuation(h)) + data(Handler& handler, stream_type& stream_) + : cont(boost_asio_handler_cont_helpers:: + is_continuation(handler)) + , stream(stream_) { } }; - std::shared_ptr d_; + handler_ptr d_; public: template explicit teardown_ssl_op( DeducedHandler&& h, stream_type& stream) - : d_(std::make_shared( - std::forward(h), stream)) + : d_(make_handler_ptr( + std::forward( + h), stream)) { (*this)(error_code{}, false); } @@ -75,7 +74,7 @@ public: teardown_ssl_op* op) { return boost_asio_handler_alloc_helpers:: - allocate(size, op->d_->h); + allocate(size, op->d_.handler()); } friend @@ -83,7 +82,7 @@ public: std::size_t size, teardown_ssl_op* op) { return boost_asio_handler_alloc_helpers:: - deallocate(p, size, op->d_->h); + deallocate(p, size, op->d_.handler()); } friend @@ -99,7 +98,7 @@ public: teardown_ssl_op* op) { return boost_asio_handler_invoke_helpers:: - invoke(f, op->d_->h); + invoke(f, op->d_.handler()); } }; @@ -120,7 +119,7 @@ operator()(error_code ec, bool again) return; } } - d.h(ec); + d_.invoke(ec); } } // detail diff --git a/include/beast/websocket/impl/teardown.ipp b/include/beast/websocket/impl/teardown.ipp index 4de5444b..e757d739 100644 --- a/include/beast/websocket/impl/teardown.ipp +++ b/include/beast/websocket/impl/teardown.ipp @@ -9,7 +9,9 @@ #define BEAST_WEBSOCKET_IMPL_TEARDOWN_IPP #include +#include #include +#include #include namespace beast { @@ -20,37 +22,37 @@ namespace detail { template class teardown_tcp_op { + using alloc_type = + handler_alloc; + using socket_type = boost::asio::ip::tcp::socket; struct data { - socket_type& socket; - Handler h; - char buf[8192]; bool cont; + socket_type& socket; + char buf[2048]; int state = 0; - template - data(DeducedHandler&& h_, socket_type& socket_) - : socket(socket_) - , h(std::forward(h_)) - , cont(boost_asio_handler_cont_helpers:: - is_continuation(h)) + data(Handler& handler, socket_type& socket_) + : cont(boost_asio_handler_cont_helpers:: + is_continuation(handler)) + , socket(socket_) { } }; - std::shared_ptr d_; + handler_ptr d_; public: template teardown_tcp_op( DeducedHandler&& h, socket_type& socket) - : d_(std::make_shared( - std::forward(h), - socket)) + : d_(make_handler_ptr( + std::forward( + h), socket)) { (*this)(error_code{}, 0, false); } @@ -63,7 +65,7 @@ public: teardown_tcp_op* op) { return boost_asio_handler_alloc_helpers:: - allocate(size, op->d_->h); + allocate(size, op->d_.handler()); } friend @@ -71,7 +73,7 @@ public: std::size_t size, teardown_tcp_op* op) { return boost_asio_handler_alloc_helpers:: - deallocate(p, size, op->d_->h); + deallocate(p, size, op->d_.handler()); } friend @@ -86,7 +88,7 @@ public: teardown_tcp_op* op) { return boost_asio_handler_invoke_helpers:: - invoke(f, op->d_->h); + invoke(f, op->d_.handler()); } }; @@ -119,7 +121,7 @@ operator()(error_code ec, std::size_t, bool again) d.socket.close(ec); ec = error_code{}; } - d.h(ec); + d_.invoke(ec); } } // detail diff --git a/include/beast/websocket/impl/write.ipp b/include/beast/websocket/impl/write.ipp index 0f84692b..884e7c7d 100644 --- a/include/beast/websocket/impl/write.ipp +++ b/include/beast/websocket/impl/write.ipp @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -97,31 +98,27 @@ template template class stream::write_frame_op { - using alloc_type = - handler_alloc; - struct data : op { + Handler& handler; + bool cont; stream& ws; consuming_buffers cb; - Handler h; detail::frame_header fh; detail::fh_streambuf fh_buf; detail::prepared_key_type key; void* tmp; std::size_t tmp_size; std::uint64_t remain; - bool cont; int state = 0; - template - data(DeducedHandler&& h_, stream& ws_, + data(Handler& handler_, stream& ws_, bool fin, Buffers const& bs) - : ws(ws_) - , cb(bs) - , h(std::forward(h_)) + : handler(handler_) , cont(boost_asio_handler_cont_helpers:: - is_continuation(h)) + is_continuation(handler)) + , ws(ws_) + , cb(bs) { using beast::detail::clamp; fh.op = ws.wr_.cont ? @@ -139,7 +136,7 @@ class stream::write_frame_op detail::prepare_key(key, fh.key); tmp_size = clamp(fh.len, ws.wr_buf_size_); tmp = boost_asio_handler_alloc_helpers:: - allocate(tmp_size, h); + allocate(tmp_size, handler); remain = fh.len; } else @@ -153,11 +150,11 @@ class stream::write_frame_op { if(tmp) boost_asio_handler_alloc_helpers:: - deallocate(tmp, tmp_size, h); + deallocate(tmp, tmp_size, handler); } }; - std::shared_ptr d_; + handler_ptr d_; public: write_frame_op(write_frame_op&&) = default; @@ -166,9 +163,9 @@ public: template write_frame_op(DeducedHandler&& h, stream& ws, Args&&... args) - : d_(std::make_shared( - std::forward(h), ws, - std::forward(args)...)) + : d_(make_handler_ptr( + std::forward(h), + ws, std::forward(args)...)) { (*this)(error_code{}, false); } @@ -187,7 +184,7 @@ public: std::size_t size, write_frame_op* op) { return boost_asio_handler_alloc_helpers:: - allocate(size, op->d_->h); + allocate(size, op->d_.handler()); } friend @@ -195,7 +192,7 @@ public: void* p, std::size_t size, write_frame_op* op) { return boost_asio_handler_alloc_helpers:: - deallocate(p, size, op->d_->h); + deallocate(p, size, op->d_.handler()); } friend @@ -209,7 +206,7 @@ public: void asio_handler_invoke(Function&& f, write_frame_op* op) { return boost_asio_handler_invoke_helpers:: - invoke(f, op->d_->h); + invoke(f, op->d_.handler()); } }; @@ -333,16 +330,10 @@ operator()(error_code ec, bool again) } } upcall: - if(d.tmp) - { - boost_asio_handler_alloc_helpers:: - deallocate(d.tmp, d.tmp_size, d.h); - d.tmp = nullptr; - } if(d.ws.wr_block_ == &d) d.ws.wr_block_ = nullptr; d.ws.rd_op_.maybe_invoke(); - d.h(ec); + d_.invoke(ec); } template @@ -532,32 +523,26 @@ template template class stream::write_op { - using alloc_type = - handler_alloc; - struct data : op { + bool cont; stream& ws; consuming_buffers cb; - Handler h; std::size_t remain; - bool cont; int state = 0; - template - data(DeducedHandler&& h_, - stream& ws_, Buffers const& bs) - : ws(ws_) + data(Handler& handler, stream& ws_, + Buffers const& bs) + : cont(boost_asio_handler_cont_helpers:: + is_continuation(handler)) + , ws(ws_) , cb(bs) - , h(std::forward(h_)) , remain(boost::asio::buffer_size(cb)) - , cont(boost_asio_handler_cont_helpers:: - is_continuation(h)) { } }; - std::shared_ptr d_; + handler_ptr d_; public: write_op(write_op&&) = default; @@ -567,7 +552,7 @@ public: explicit write_op(DeducedHandler&& h, stream& ws, Args&&... args) - : d_(std::allocate_shared(alloc_type{h}, + : d_(make_handler_ptr( std::forward(h), ws, std::forward(args)...)) { @@ -581,7 +566,7 @@ public: std::size_t size, write_op* op) { return boost_asio_handler_alloc_helpers:: - allocate(size, op->d_->h); + allocate(size, op->d_.handler()); } friend @@ -589,7 +574,7 @@ public: void* p, std::size_t size, write_op* op) { return boost_asio_handler_alloc_helpers:: - deallocate(p, size, op->d_->h); + deallocate(p, size, op->d_.handler()); } friend @@ -603,7 +588,7 @@ public: void asio_handler_invoke(Function&& f, write_op* op) { return boost_asio_handler_invoke_helpers:: - invoke(f, op->d_->h); + invoke(f, op->d_.handler()); } }; @@ -637,7 +622,7 @@ operator()(error_code ec, bool again) break; } } - d.h(ec); + d_.invoke(ec); } template diff --git a/test/Jamfile b/test/Jamfile index f05a0922..a023b5fd 100644 --- a/test/Jamfile +++ b/test/Jamfile @@ -27,6 +27,7 @@ unit-test core-tests : core/error.cpp core/handler_alloc.cpp core/handler_concepts.cpp + core/handler_ptr.cpp core/placeholders.cpp core/prepare_buffers.cpp core/static_streambuf.cpp diff --git a/test/core/CMakeLists.txt b/test/core/CMakeLists.txt index c0904fd2..d96d5324 100644 --- a/test/core/CMakeLists.txt +++ b/test/core/CMakeLists.txt @@ -22,6 +22,7 @@ add_executable (core-tests error.cpp handler_alloc.cpp handler_concepts.cpp + handler_ptr.cpp placeholders.cpp prepare_buffers.cpp static_streambuf.cpp diff --git a/test/core/handler_ptr.cpp b/test/core/handler_ptr.cpp new file mode 100644 index 00000000..8cd2a8d6 --- /dev/null +++ b/test/core/handler_ptr.cpp @@ -0,0 +1,9 @@ +// +// Copyright (c) 2013-2016 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) +// + +// Test that header file is self-contained. +#include