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