Doc tidying

fix #521, fix #524
This commit is contained in:
Vinnie Falco
2017-07-20 08:15:28 -07:00
parent bd4d1cbe91
commit b2ab40f09c
19 changed files with 949 additions and 754 deletions
+135 -77
View File
@@ -13,13 +13,24 @@
//[example_core_echo_op_1
template<
class AsyncStream,
class CompletionToken>
auto
async_echo(AsyncStream& stream, CompletionToken&& token)
//]
-> beast::async_return_type<CompletionToken, void(beast::error_code)>;
//[example_core_echo_op_2
/** Asynchronously read a line and echo it back.
This function is used to asynchronously read a line ending
in a carriage-return linefeed ("CRLF") from the stream,
and then write it back. The function call always returns
immediately. The asynchronous operation will continue until
one of the following conditions is true:
in a carriage-return ("CR") from the stream, and then write
it back. The function call always returns immediately. The
asynchronous operation will continue until one of the
following conditions is true:
@li A line was read in and sent back on the stream
@@ -38,10 +49,10 @@
@param token The completion token to use. If this is a
completion handler, copies will be made as required.
The signature of the handler must be:
The equivalent signature of the handler must be:
@code
void handler(
error_code& ec // result of operation
error_code ec // result of operation
);
@endcode
Regardless of whether the asynchronous operation completes
@@ -61,7 +72,7 @@ async_echo(
//]
//[example_core_echo_op_3
//[example_core_echo_op_4
// This composed operation reads a line of input and echoes it back.
//
@@ -79,10 +90,11 @@ class echo_op
int step = 0;
// The buffer used to hold the input and output data.
// Note that we use a custom allocator for performance,
// this allows the implementation of the io_service to
// make efficient re-use of memory allocated by composed
// operations during continuations.
//
// We use a custom allocator for performance, this allows
// the implementation of the io_service to make efficient
// re-use of memory allocated by composed operations during
// a continuation.
//
boost::asio::basic_streambuf<beast::handler_alloc<char, Handler>> buffer;
@@ -98,11 +110,17 @@ class echo_op
}
};
// This smart pointer container allocates our state using the
// memory allocation hooks associated with the final completion
// handler, manages the lifetime of that handler for us, and
// enforces the destroy-before-invocation requirement on memory
// allocated using the hooks.
// The operation's data is kept in a cheap-to-copy smart
// pointer container called `handler_ptr`. This efficiently
// satisfies the CopyConstructible requirements of completion
// handlers.
//
// `handler_ptr` uses these memory allocation hooks associated
// with the final completion handler, in order to allocate the
// storage for `state`:
//
// asio_handler_allocate
// asio_handler_deallocate
//
beast::handler_ptr<state, Handler> p_;
@@ -123,65 +141,35 @@ public:
{
}
// Determines if the next asynchronous operation represents a
// continuation of the asynchronous flow of control associated
// with the final handler. If we are past step one, it means
// we have performed an asynchronous operation therefore any
// subsequent operation would represent a continuation.
// Otherwise, we propagate the handler's associated value of
// is_continuation. Getting this right means the implementation
// may schedule the invokation of the invoked functions more
// efficiently.
//
friend bool asio_handler_is_continuation(echo_op* op)
{
// This next call is structured to permit argument
// dependent lookup to take effect.
using boost::asio::asio_handler_is_continuation;
// Always use std::addressof to pass the pointer to the handler,
// otherwise an unwanted overload of operator& may be called instead.
return op->p_->step > 1 ||
asio_handler_is_continuation(std::addressof(op->p_.handler()));
}
// Handler hook forwarding. These free functions invoke the hooks
// associated with the final completion handler. In effect, they
// make the Asio implementation treat our composed operation the
// same way it would treat the final completion handler for the
// purpose of memory allocation and invocation.
//
// Our implementation just passes through the call to the hook
// associated with the final handler.
friend void* asio_handler_allocate(std::size_t size, echo_op* op)
{
using boost::asio::asio_handler_allocate;
return asio_handler_allocate(size, std::addressof(op->p_.handler()));
}
friend void asio_handler_deallocate(void* p, std::size_t size, echo_op* op)
{
using boost::asio::asio_handler_deallocate;
return asio_handler_deallocate(p, size, std::addressof(op->p_.handler()));
}
template<class Function>
friend void asio_handler_invoke(Function&& f, echo_op* op)
{
using boost::asio::asio_handler_invoke;
return asio_handler_invoke(f, std::addressof(op->p_.handler()));
}
// Our main entry point. This will get called as our
// intermediate operations complete. Definition below.
// The entry point for this handler. This will get called
// as our intermediate operations complete. Definition below.
//
void operator()(beast::error_code ec, std::size_t bytes_transferred);
// The next four functions are required for our class
// to meet the requirements for composed operations.
// Definitions and exposition will follow.
template<class AsyncStream_, class Handler_, class Function>
friend void asio_handler_invoke(
Function&& f, echo_op<AsyncStream_, Handler_>* op);
template<class AsyncStream_, class Handler_>
friend void* asio_handler_allocate(
std::size_t size, echo_op<AsyncStream_, Handler_>* op);
template<class AsyncStream_, class Handler_>
friend void asio_handler_deallocate(
void* p, std::size_t size, echo_op<AsyncStream_, Handler_>* op);
template<class AsyncStream_, class Handler_>
friend bool asio_handler_is_continuation(
echo_op<AsyncStream_, Handler_>* op);
};
//]
//[example_core_echo_op_4
//[example_core_echo_op_5
// echo_op is callable with the signature void(error_code, bytes_transferred),
// allowing `*this` to be used as both a ReadHandler and a WriteHandler.
@@ -202,7 +190,7 @@ operator()(beast::error_code ec, std::size_t bytes_transferred)
case 0:
// read up to the first newline
p.step = 1;
return boost::asio::async_read_until(p.stream, p.buffer, "\n", std::move(*this));
return boost::asio::async_read_until(p.stream, p.buffer, "\r", std::move(*this));
case 1:
// write everything back
@@ -217,10 +205,15 @@ operator()(beast::error_code ec, std::size_t bytes_transferred)
break;
}
// Invoke the final handler. If we wanted to pass any arguments
// which come from our state, they would have to be moved to the
// stack first, since the `handler_ptr` guarantees that the state
// is destroyed before the handler is invoked.
// Invoke the final handler. The implementation of `handler_ptr`
// will deallocate the storage for the state before the handler
// is invoked. This is necessary to provide the
// destroy-before-invocation guarantee on handler memory
// customizations.
//
// If we wanted to pass any arguments to the handler which come
// from the `state`, they would have to be moved to the stack
// first or else undefined behavior results.
//
p_.invoke(ec);
return;
@@ -228,7 +221,72 @@ operator()(beast::error_code ec, std::size_t bytes_transferred)
//]
//[example_core_echo_op_2
//[example_core_echo_op_6
// Handler hook forwarding. These free functions invoke the hooks
// associated with the final completion handler. In effect, they
// make the Asio implementation treat our composed operation the
// same way it would treat the final completion handler for the
// purpose of memory allocation and invocation.
//
// Our implementation just passes the call through to the hook
// associated with the final handler. The "using" statements are
// structured to permit argument dependent lookup. Always use
// `std::addressof` or its equivalent to pass the pointer to the
// handler, otherwise an unwanted overload of `operator&` may be
// called instead.
template<class AsyncStream, class Handler, class Function>
void asio_handler_invoke(
Function&& f, echo_op<AsyncStream, Handler>* op)
{
using boost::asio::asio_handler_invoke;
return asio_handler_invoke(f, std::addressof(op->p_.handler()));
}
template<class AsyncStream, class Handler>
void* asio_handler_allocate(
std::size_t size, echo_op<AsyncStream, Handler>* op)
{
using boost::asio::asio_handler_allocate;
return asio_handler_allocate(size, std::addressof(op->p_.handler()));
}
template<class AsyncStream, class Handler>
void asio_handler_deallocate(
void* p, std::size_t size, echo_op<AsyncStream, Handler>* op)
{
using boost::asio::asio_handler_deallocate;
return asio_handler_deallocate(p, size,
std::addressof(op->p_.handler()));
}
// Determines if the next asynchronous operation represents a
// continuation of the asynchronous flow of control associated
// with the final handler. If we are past step one, it means
// we have performed an asynchronous operation therefore any
// subsequent operation would represent a continuation.
// Otherwise, we propagate the handler's associated value of
// is_continuation. Getting this right means the implementation
// may schedule the invokation of the invoked functions more
// efficiently.
//
template<class AsyncStream, class Handler>
bool asio_handler_is_continuation(echo_op<AsyncStream, Handler>* op)
{
// This next call is structured to permit argument
// dependent lookup to take effect.
using boost::asio::asio_handler_is_continuation;
// Always use std::addressof to pass the pointer to the handler,
// otherwise an unwanted overload of operator& may be called instead.
return op->p_->step > 1 ||
asio_handler_is_continuation(std::addressof(op->p_.handler()));
}
//]
//[example_core_echo_op_3
template<class AsyncStream, class Handler>
class echo_op;
@@ -254,8 +312,8 @@ async_echo(AsyncStream& stream, CompletionToken&& token)
// Create the composed operation and launch it. This is a constructor
// call followed by invocation of operator(). We use handler_type
// to convert the completion token into the correct handler type,
// allowing user defined specializations of the async result template
// to take effect.
// allowing user-defined specializations of the async_result template
// to be used.
//
echo_op<AsyncStream, beast::handler_type<CompletionToken, void(beast::error_code)>>{
stream, init.completion_handler}(beast::error_code{}, 0);