summaryrefslogtreecommitdiff
path: root/doc/html/boost_asio/example/cpp11/operations/composed_2.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'doc/html/boost_asio/example/cpp11/operations/composed_2.cpp')
-rw-r--r--doc/html/boost_asio/example/cpp11/operations/composed_2.cpp105
1 files changed, 44 insertions, 61 deletions
diff --git a/doc/html/boost_asio/example/cpp11/operations/composed_2.cpp b/doc/html/boost_asio/example/cpp11/operations/composed_2.cpp
index d03fece9d5..d214d164fb 100644
--- a/doc/html/boost_asio/example/cpp11/operations/composed_2.cpp
+++ b/doc/html/boost_asio/example/cpp11/operations/composed_2.cpp
@@ -2,19 +2,17 @@
// composed_2.cpp
// ~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff 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)
//
-#include <boost/asio/bind_executor.hpp>
#include <boost/asio/io_context.hpp>
#include <boost/asio/ip/tcp.hpp>
#include <boost/asio/use_future.hpp>
#include <boost/asio/write.hpp>
#include <cstring>
-#include <functional>
#include <iostream>
#include <string>
#include <type_traits>
@@ -24,63 +22,49 @@ using boost::asio::ip::tcp;
//------------------------------------------------------------------------------
-// In this composed operation we repackage an existing operation, but with a
-// different completion handler signature. The asynchronous operation
-// requirements are met by delegating responsibility to the underlying
-// operation.
+// This next simplest example of a composed asynchronous operation involves
+// repackaging multiple operations but choosing to invoke just one of them. All
+// of these underlying operations have the same completion signature. The
+// asynchronous operation requirements are met by delegating responsibility to
+// the underlying operations.
+
template <typename CompletionToken>
auto async_write_message(tcp::socket& socket,
- const char* message, CompletionToken&& token)
+ const char* message, bool allow_partial_write,
+ CompletionToken&& token)
// The return type of the initiating function is deduced from the combination
// of CompletionToken type and the completion handler's signature. When the
- // completion token is a simple callback, the return type is always void.
- // In this example, when the completion token is boost::asio::yield_context
- // (used for stackful coroutines) the return type would be also be void, as
- // there is no non-error argument to the completion handler. When the
- // completion token is boost::asio::use_future it would be std::future<void>.
+ // completion token is a simple callback, the return type is void. However,
+ // when the completion token is boost::asio::yield_context (used for stackful
+ // coroutines) the return type would be std::size_t, and when the completion
+ // token is boost::asio::use_future it would be std::future<std::size_t>.
-> typename boost::asio::async_result<
typename std::decay<CompletionToken>::type,
- void(boost::system::error_code)>::return_type
+ void(boost::system::error_code, std::size_t)>::return_type
{
- // The boost::asio::async_completion object takes the completion token and
- // from it creates:
- //
- // - completion.completion_handler:
- // A completion handler (i.e. a callback) with the specified signature.
- //
- // - completion.result:
- // An object from which we obtain the result of the initiating function.
- boost::asio::async_completion<CompletionToken,
- void(boost::system::error_code)> completion(token);
-
- // The async_write operation has a completion handler signature of:
- //
- // void(boost::system::error_code error, std::size n)
- //
- // This differs from our operation's signature in that it is also passed the
- // number of bytes transferred as an argument of type std::size_t. We will
- // adapt our completion handler to this signature by using std::bind, which
- // drops the additional argument.
- //
- // However, it is essential to the correctness of our composed operation that
- // we preserve the executor of the user-supplied completion handler. The
- // std::bind function will not do this for us, so we must do this by first
- // obtaining the completion handler's associated executor (defaulting to the
- // I/O executor - in this case the executor of the socket - if the completion
- // handler does not have its own) ...
- auto executor = boost::asio::get_associated_executor(
- completion.completion_handler, socket.get_executor());
-
- // ... and then binding this executor to our adapted completion handler using
- // the boost::asio::bind_executor function.
- boost::asio::async_write(socket,
- boost::asio::buffer(message, std::strlen(message)),
- boost::asio::bind_executor(executor,
- std::bind(std::move(completion.completion_handler),
- std::placeholders::_1)));
-
- // Finally, we return the result of the initiating function.
- return completion.result.get();
+ // As the return type of the initiating function is deduced solely from the
+ // CompletionToken and completion signature, we know that two different
+ // asynchronous operations having the same completion signature will produce
+ // the same return type, when passed the same CompletionToken. This allows us
+ // to trivially delegate to alternate implementations.
+ if (allow_partial_write)
+ {
+ // When delegating to an underlying operation we must take care to
+ // perfectly forward the completion token. This ensures that our operation
+ // works correctly with move-only function objects as callbacks, as well as
+ // other completion token types.
+ return socket.async_write_some(
+ boost::asio::buffer(message, std::strlen(message)),
+ std::forward<CompletionToken>(token));
+ }
+ else
+ {
+ // As above, we must perfectly forward the completion token when calling
+ // the alternate underlying operation.
+ return boost::asio::async_write(socket,
+ boost::asio::buffer(message, std::strlen(message)),
+ std::forward<CompletionToken>(token));
+ }
}
//------------------------------------------------------------------------------
@@ -93,12 +77,12 @@ void test_callback()
tcp::socket socket = acceptor.accept();
// Test our asynchronous operation using a lambda as a callback.
- async_write_message(socket, "Testing callback\r\n",
- [](const boost::system::error_code& error)
+ async_write_message(socket, "Testing callback\r\n", false,
+ [](const boost::system::error_code& error, std::size_t n)
{
if (!error)
{
- std::cout << "Message sent\n";
+ std::cout << n << " bytes transferred\n";
}
else
{
@@ -121,17 +105,16 @@ void test_future()
// Test our asynchronous operation using the use_future completion token.
// This token causes the operation's initiating function to return a future,
// which may be used to synchronously wait for the result of the operation.
- std::future<void> f = async_write_message(
- socket, "Testing future\r\n", boost::asio::use_future);
+ std::future<std::size_t> f = async_write_message(
+ socket, "Testing future\r\n", false, boost::asio::use_future);
io_context.run();
- // Get the result of the operation.
try
{
// Get the result of the operation.
- f.get();
- std::cout << "Message sent\n";
+ std::size_t n = f.get();
+ std::cout << n << " bytes transferred\n";
}
catch (const std::exception& e)
{