diff options
Diffstat (limited to '3rdparty/asio/src/examples/cpp11/operations')
8 files changed, 520 insertions, 100 deletions
diff --git a/3rdparty/asio/src/examples/cpp11/operations/composed_1.cpp b/3rdparty/asio/src/examples/cpp11/operations/composed_1.cpp index cfec43c8e83..054dbdbbc88 100644 --- a/3rdparty/asio/src/examples/cpp11/operations/composed_1.cpp +++ b/3rdparty/asio/src/examples/cpp11/operations/composed_1.cpp @@ -2,12 +2,13 @@ // composed_1.cpp // ~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2021 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 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 <asio/deferred.hpp> #include <asio/io_context.hpp> #include <asio/ip/tcp.hpp> #include <asio/use_future.hpp> @@ -31,14 +32,25 @@ template <typename CompletionToken> auto async_write_message(tcp::socket& socket, const char* message, 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 void. However, - // when the completion token is asio::yield_context (used for stackful - // coroutines) the return type would be std::size_t, and when the completion - // token is asio::use_future it would be std::future<std::size_t>. - -> typename asio::async_result< - typename std::decay<CompletionToken>::type, - void(std::error_code, std::size_t)>::return_type + // of: + // + // - the CompletionToken type, + // - the completion handler signature, and + // - the asynchronous operation's initiation function object. + // + // When the completion token is a simple callback, the return type is void. + // However, when the completion token is asio::yield_context (used for + // stackful coroutines) the return type would be std::size_t, and when the + // completion token is asio::use_future it would be std::future<std::size_t>. + // When the completion token is asio::deferred, the return type differs for + // each asynchronous operation. + // + // In this example we are trivially delegating to an underlying asynchronous + // operation, so we can deduce the return type from that. + -> decltype( + asio::async_write(socket, + asio::buffer(message, std::strlen(message)), + std::forward<CompletionToken>(token))) { // When delegating to the underlying operation we must take care to perfectly // forward the completion token. This ensures that our operation works @@ -77,6 +89,39 @@ void test_callback() //------------------------------------------------------------------------------ +void test_deferred() +{ + asio::io_context io_context; + + tcp::acceptor acceptor(io_context, {tcp::v4(), 55555}); + tcp::socket socket = acceptor.accept(); + + // Test our asynchronous operation using the deferred completion token. This + // token causes the operation's initiating function to package up the + // operation and its arguments to return a function object, which may then be + // used to launch the asynchronous operation. + auto op = async_write_message(socket, + "Testing deferred\r\n", asio::deferred); + + // Launch the operation using a lambda as a callback. + std::move(op)( + [](const std::error_code& error, std::size_t n) + { + if (!error) + { + std::cout << n << " bytes transferred\n"; + } + else + { + std::cout << "Error: " << error.message() << "\n"; + } + }); + + io_context.run(); +} + +//------------------------------------------------------------------------------ + void test_future() { asio::io_context io_context; @@ -109,5 +154,6 @@ void test_future() int main() { test_callback(); + test_deferred(); test_future(); } diff --git a/3rdparty/asio/src/examples/cpp11/operations/composed_2.cpp b/3rdparty/asio/src/examples/cpp11/operations/composed_2.cpp index 62ddf8d9089..306d4b343b4 100644 --- a/3rdparty/asio/src/examples/cpp11/operations/composed_2.cpp +++ b/3rdparty/asio/src/examples/cpp11/operations/composed_2.cpp @@ -2,12 +2,13 @@ // composed_2.cpp // ~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2021 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 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 <asio/deferred.hpp> #include <asio/io_context.hpp> #include <asio/ip/tcp.hpp> #include <asio/use_future.hpp> @@ -20,6 +21,10 @@ using asio::ip::tcp; +// NOTE: This example requires the new asio::async_initiate function. For +// an example that works with the Networking TS style of completion tokens, +// please see an older version of asio. + //------------------------------------------------------------------------------ // This next simplest example of a composed asynchronous operation involves @@ -28,43 +33,102 @@ using asio::ip::tcp; // asynchronous operation requirements are met by delegating responsibility to // the underlying operations. +// In addition to determining the mechanism by which an asynchronous operation +// delivers its result, a completion token also determines the time when the +// operation commences. For example, when the completion token is a simple +// callback the operation commences before the initiating function returns. +// However, if the completion token's delivery mechanism uses a future, we +// might instead want to defer initiation of the operation until the returned +// future object is waited upon. +// +// To enable this, when implementing an asynchronous operation we must package +// the initiation step as a function object. +struct async_write_message_initiation +{ + // The initiation function object's call operator is passed the concrete + // completion handler produced by the completion token. This completion + // handler matches the asynchronous operation's completion handler signature, + // which in this example is: + // + // void(std::error_code error, std::size_t) + // + // The initiation function object also receives any additional arguments + // required to start the operation. (Note: We could have instead passed these + // arguments as members in the initiaton function object. However, we should + // prefer to propagate them as function call arguments as this allows the + // completion token to optimise how they are passed. For example, a lazy + // future which defers initiation would need to make a decay-copy of the + // arguments, but when using a simple callback the arguments can be trivially + // forwarded straight through.) + template <typename CompletionHandler> + void operator()(CompletionHandler&& completion_handler, tcp::socket& socket, + const char* message, bool allow_partial_write) const + { + if (allow_partial_write) + { + // When delegating to an underlying operation we must take care to + // perfectly forward the completion handler. This ensures that our + // operation works correctly with move-only function objects as + // callbacks. + return socket.async_write_some( + asio::buffer(message, std::strlen(message)), + std::forward<CompletionHandler>(completion_handler)); + } + else + { + // As above, we must perfectly forward the completion handler when calling + // the alternate underlying operation. + return asio::async_write(socket, + asio::buffer(message, std::strlen(message)), + std::forward<CompletionHandler>(completion_handler)); + } + } +}; + template <typename CompletionToken> auto async_write_message(tcp::socket& socket, 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 void. However, - // when the completion token is asio::yield_context (used for stackful - // coroutines) the return type would be std::size_t, and when the completion - // token is asio::use_future it would be std::future<std::size_t>. - -> typename asio::async_result< - typename std::decay<CompletionToken>::type, - void(std::error_code, std::size_t)>::return_type + // of: + // + // - the CompletionToken type, + // - the completion handler signature, and + // - the asynchronous operation's initiation function object. + // + // When the completion token is a simple callback, the return type is void. + // However, when the completion token is asio::yield_context (used for + // stackful coroutines) the return type would be std::size_t, and when the + // completion token is asio::use_future it would be std::future<std::size_t>. + // When the completion token is asio::deferred, the return type differs for + // each asynchronous operation. + // + // In C++11 we deduce the type from the call to asio::async_initiate. + -> decltype( + asio::async_initiate< + CompletionToken, void(std::error_code, std::size_t)>( + async_write_message_initiation(), + token, std::ref(socket), message, allow_partial_write)) { - // 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( - 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 asio::async_write(socket, - asio::buffer(message, std::strlen(message)), - std::forward<CompletionToken>(token)); - } + // The asio::async_initiate function takes: + // + // - our initiation function object, + // - the completion token, + // - the completion handler signature, and + // - any additional arguments we need to initiate the operation. + // + // It then asks the completion token to create a completion handler (i.e. a + // callback) with the specified signature, and invoke the initiation function + // object with this completion handler as well as the additional arguments. + // The return value of async_initiate is the result of our operation's + // initiating function. + // + // Note that we wrap non-const reference arguments in std::reference_wrapper + // to prevent incorrect decay-copies of these objects. + return asio::async_initiate< + CompletionToken, void(std::error_code, std::size_t)>( + async_write_message_initiation(), + token, std::ref(socket), message, allow_partial_write); } //------------------------------------------------------------------------------ @@ -95,6 +159,39 @@ void test_callback() //------------------------------------------------------------------------------ +void test_deferred() +{ + asio::io_context io_context; + + tcp::acceptor acceptor(io_context, {tcp::v4(), 55555}); + tcp::socket socket = acceptor.accept(); + + // Test our asynchronous operation using the deferred completion token. This + // token causes the operation's initiating function to package up the + // operation and its arguments to return a function object, which may then be + // used to launch the asynchronous operation. + auto op = async_write_message(socket, + "Testing deferred\r\n", false, asio::deferred); + + // Launch the operation using a lambda as a callback. + std::move(op)( + [](const std::error_code& error, std::size_t n) + { + if (!error) + { + std::cout << n << " bytes transferred\n"; + } + else + { + std::cout << "Error: " << error.message() << "\n"; + } + }); + + io_context.run(); +} + +//------------------------------------------------------------------------------ + void test_future() { asio::io_context io_context; @@ -127,5 +224,6 @@ void test_future() int main() { test_callback(); + test_deferred(); test_future(); } diff --git a/3rdparty/asio/src/examples/cpp11/operations/composed_3.cpp b/3rdparty/asio/src/examples/cpp11/operations/composed_3.cpp index c821041336f..e0b5ddca85b 100644 --- a/3rdparty/asio/src/examples/cpp11/operations/composed_3.cpp +++ b/3rdparty/asio/src/examples/cpp11/operations/composed_3.cpp @@ -2,13 +2,14 @@ // composed_3.cpp // ~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2021 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 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 <asio/bind_executor.hpp> +#include <asio/deferred.hpp> #include <asio/io_context.hpp> #include <asio/ip/tcp.hpp> #include <asio/use_future.hpp> @@ -96,15 +97,26 @@ template <typename CompletionToken> auto async_write_message(tcp::socket& socket, const char* message, 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 asio::yield_context - // (used for stackful coroutines) the return type would be also be void, as + // of: + // + // - the CompletionToken type, + // - the completion handler signature, and + // - the asynchronous operation's initiation function object. + // + // When the completion token is a simple callback, the return type is always + // void. In this example, when the completion token is asio::yield_context + // (used for stackful coroutines) the return type would also be void, as // there is no non-error argument to the completion handler. When the - // completion token is asio::use_future it would be std::future<void>. - -> typename asio::async_result< - typename std::decay<CompletionToken>::type, - void(std::error_code)>::return_type + // completion token is asio::use_future it would be std::future<void>. When + // the completion token is asio::deferred, the return type differs for each + // asynchronous operation. + // + // In C++11 we deduce the type from the call to asio::async_initiate. + -> decltype( + asio::async_initiate< + CompletionToken, void(std::error_code)>( + async_write_message_initiation(), + token, std::ref(socket), message)) { // The asio::async_initiate function takes: // @@ -155,6 +167,39 @@ void test_callback() //------------------------------------------------------------------------------ +void test_deferred() +{ + asio::io_context io_context; + + tcp::acceptor acceptor(io_context, {tcp::v4(), 55555}); + tcp::socket socket = acceptor.accept(); + + // Test our asynchronous operation using the deferred completion token. This + // token causes the operation's initiating function to package up the + // operation and its arguments to return a function object, which may then be + // used to launch the asynchronous operation. + auto op = async_write_message(socket, + "Testing deferred\r\n", asio::deferred); + + // Launch the operation using a lambda as a callback. + std::move(op)( + [](const std::error_code& error) + { + if (!error) + { + std::cout << "Message sent\n"; + } + else + { + std::cout << "Error: " << error.message() << "\n"; + } + }); + + io_context.run(); +} + +//------------------------------------------------------------------------------ + void test_future() { asio::io_context io_context; @@ -188,5 +233,6 @@ void test_future() int main() { test_callback(); + test_deferred(); test_future(); } diff --git a/3rdparty/asio/src/examples/cpp11/operations/composed_4.cpp b/3rdparty/asio/src/examples/cpp11/operations/composed_4.cpp index e4c6264b625..29fe26966e5 100644 --- a/3rdparty/asio/src/examples/cpp11/operations/composed_4.cpp +++ b/3rdparty/asio/src/examples/cpp11/operations/composed_4.cpp @@ -2,13 +2,14 @@ // composed_4.cpp // ~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2021 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 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 <asio/bind_executor.hpp> +#include <asio/deferred.hpp> #include <asio/io_context.hpp> #include <asio/ip/tcp.hpp> #include <asio/use_future.hpp> @@ -112,15 +113,26 @@ template <typename CompletionToken> auto async_write_message(tcp::socket& socket, const char* message, 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 asio::yield_context - // (used for stackful coroutines) the return type would be also be void, as + // of: + // + // - the CompletionToken type, + // - the completion handler signature, and + // - the asynchronous operation's initiation function object. + // + // When the completion token is a simple callback, the return type is always + // void. In this example, when the completion token is asio::yield_context + // (used for stackful coroutines) the return type would also be void, as // there is no non-error argument to the completion handler. When the - // completion token is asio::use_future it would be std::future<void>. - -> typename asio::async_result< - typename std::decay<CompletionToken>::type, - void(std::error_code)>::return_type + // completion token is asio::use_future it would be std::future<void>. When + // the completion token is asio::deferred, the return type differs for each + // asynchronous operation. + // + // In C++11 we deduce the type from the call to asio::async_initiate. + -> decltype( + asio::async_initiate< + CompletionToken, void(std::error_code)>( + async_write_message_initiation(), + token, std::ref(socket), message)) { // The asio::async_initiate function takes: // @@ -171,6 +183,38 @@ void test_callback() //------------------------------------------------------------------------------ +void test_deferred() +{ + asio::io_context io_context; + + tcp::acceptor acceptor(io_context, {tcp::v4(), 55555}); + tcp::socket socket = acceptor.accept(); + + // Test our asynchronous operation using the deferred completion token. This + // token causes the operation's initiating function to package up the + // operation and its arguments to return a function object, which may then be + // used to launch the asynchronous operation. + auto op = async_write_message(socket, "", asio::deferred); + + // Launch the operation using a lambda as a callback. + std::move(op)( + [](const std::error_code& error) + { + if (!error) + { + std::cout << "Message sent\n"; + } + else + { + std::cout << "Error: " << error.message() << "\n"; + } + }); + + io_context.run(); +} + +//------------------------------------------------------------------------------ + void test_future() { asio::io_context io_context; @@ -203,5 +247,6 @@ void test_future() int main() { test_callback(); + test_deferred(); test_future(); } diff --git a/3rdparty/asio/src/examples/cpp11/operations/composed_5.cpp b/3rdparty/asio/src/examples/cpp11/operations/composed_5.cpp index 9f7901da512..06a7af40f41 100644 --- a/3rdparty/asio/src/examples/cpp11/operations/composed_5.cpp +++ b/3rdparty/asio/src/examples/cpp11/operations/composed_5.cpp @@ -2,12 +2,13 @@ // composed_5.cpp // ~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2021 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 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 <asio/deferred.hpp> #include <asio/io_context.hpp> #include <asio/ip/tcp.hpp> #include <asio/use_future.hpp> @@ -142,15 +143,26 @@ template <typename T, typename CompletionToken> auto async_write_message(tcp::socket& socket, const T& message, 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 asio::yield_context - // (used for stackful coroutines) the return type would be also be void, as + // of: + // + // - the CompletionToken type, + // - the completion handler signature, and + // - the asynchronous operation's initiation function object. + // + // When the completion token is a simple callback, the return type is always + // void. In this example, when the completion token is asio::yield_context + // (used for stackful coroutines) the return type would also be void, as // there is no non-error argument to the completion handler. When the - // completion token is asio::use_future it would be std::future<void>. - -> typename asio::async_result< - typename std::decay<CompletionToken>::type, - void(std::error_code)>::return_type + // completion token is asio::use_future it would be std::future<void>. When + // the completion token is asio::deferred, the return type differs for each + // asynchronous operation. + // + // In C++11 we deduce the type from the call to asio::async_initiate. + -> decltype( + asio::async_initiate< + CompletionToken, void(std::error_code)>( + async_write_message_initiation(), token, + std::ref(socket), std::declval<std::unique_ptr<std::string>>())) { // Encode the message and copy it into an allocated buffer. The buffer will // be maintained for the lifetime of the asynchronous operation. @@ -207,6 +219,39 @@ void test_callback() //------------------------------------------------------------------------------ +void test_deferred() +{ + asio::io_context io_context; + + tcp::acceptor acceptor(io_context, {tcp::v4(), 55555}); + tcp::socket socket = acceptor.accept(); + + // Test our asynchronous operation using the deferred completion token. This + // token causes the operation's initiating function to package up the + // operation and its arguments to return a function object, which may then be + // used to launch the asynchronous operation. + auto op = async_write_message(socket, + std::string("abcdef"), asio::deferred); + + // Launch the operation using a lambda as a callback. + std::move(op)( + [](const std::error_code& error) + { + if (!error) + { + std::cout << "Message sent\n"; + } + else + { + std::cout << "Error: " << error.message() << "\n"; + } + }); + + io_context.run(); +} + +//------------------------------------------------------------------------------ + void test_future() { asio::io_context io_context; @@ -239,5 +284,6 @@ void test_future() int main() { test_callback(); + test_deferred(); test_future(); } diff --git a/3rdparty/asio/src/examples/cpp11/operations/composed_6.cpp b/3rdparty/asio/src/examples/cpp11/operations/composed_6.cpp index b55a553d07a..b948758d83a 100644 --- a/3rdparty/asio/src/examples/cpp11/operations/composed_6.cpp +++ b/3rdparty/asio/src/examples/cpp11/operations/composed_6.cpp @@ -2,12 +2,13 @@ // composed_6.cpp // ~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2021 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 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 <asio/deferred.hpp> #include <asio/executor_work_guard.hpp> #include <asio/io_context.hpp> #include <asio/ip/tcp.hpp> @@ -97,9 +98,7 @@ struct async_write_message_initiation // As our composed operation performs multiple underlying I/O operations, // we should maintain a work object against the I/O executor. This tells // the I/O executor that there is still more work to come in the future. - typename std::decay<decltype(asio::prefer( - std::declval<tcp::socket::executor_type>(), - asio::execution::outstanding_work.tracked))>::type io_work_; + asio::executor_work_guard<tcp::socket::executor_type> io_work_; // The user-supplied completion handler, called once only on completion // of the entire composed operation. @@ -136,6 +135,9 @@ struct async_write_message_initiation // This point is reached only on completion of the entire composed // operation. + // We no longer have any future work coming for the I/O executor. + io_work_.reset(); + // Deallocate the encoded message before calling the user-supplied // completion handler. encoded_message_.reset(); @@ -186,8 +188,7 @@ struct async_write_message_initiation socket, std::move(encoded_message), repeat_count, std::move(delay_timer), intermediate_completion_handler::starting, - asio::prefer(socket.get_executor(), - asio::execution::outstanding_work.tracked), + asio::make_work_guard(socket.get_executor()), std::forward<CompletionHandler>(completion_handler)}); } }; @@ -197,15 +198,27 @@ auto async_write_messages(tcp::socket& socket, const T& message, std::size_t repeat_count, 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 asio::yield_context - // (used for stackful coroutines) the return type would be also be void, as + // of: + // + // - the CompletionToken type, + // - the completion handler signature, and + // - the asynchronous operation's initiation function object. + // + // When the completion token is a simple callback, the return type is always + // void. In this example, when the completion token is asio::yield_context + // (used for stackful coroutines) the return type would also be void, as // there is no non-error argument to the completion handler. When the - // completion token is asio::use_future it would be std::future<void>. - -> typename asio::async_result< - typename std::decay<CompletionToken>::type, - void(std::error_code)>::return_type + // completion token is asio::use_future it would be std::future<void>. When + // the completion token is asio::deferred, the return type differs for each + // asynchronous operation. + // + // In C++11 we deduce the type from the call to asio::async_initiate. + -> decltype( + asio::async_initiate< + CompletionToken, void(std::error_code)>( + async_write_message_initiation(), token, std::ref(socket), + std::declval<std::unique_ptr<std::string>>(), repeat_count, + std::declval<std::unique_ptr<asio::steady_timer>>())) { // Encode the message and copy it into an allocated buffer. The buffer will // be maintained for the lifetime of the composed asynchronous operation. @@ -266,6 +279,39 @@ void test_callback() //------------------------------------------------------------------------------ +void test_deferred() +{ + asio::io_context io_context; + + tcp::acceptor acceptor(io_context, {tcp::v4(), 55555}); + tcp::socket socket = acceptor.accept(); + + // Test our asynchronous operation using the deferred completion token. This + // token causes the operation's initiating function to package up the + // operation and its arguments to return a function object, which may then be + // used to launch the asynchronous operation. + auto op = async_write_messages(socket, + "Testing deferred\r\n", 5, asio::deferred); + + // Launch the operation using a lambda as a callback. + std::move(op)( + [](const std::error_code& error) + { + if (!error) + { + std::cout << "Messages sent\n"; + } + else + { + std::cout << "Error: " << error.message() << "\n"; + } + }); + + io_context.run(); +} + +//------------------------------------------------------------------------------ + void test_future() { asio::io_context io_context; @@ -298,5 +344,6 @@ void test_future() int main() { test_callback(); + test_deferred(); test_future(); } diff --git a/3rdparty/asio/src/examples/cpp11/operations/composed_7.cpp b/3rdparty/asio/src/examples/cpp11/operations/composed_7.cpp index 92c8e321c01..8eb83dc7679 100644 --- a/3rdparty/asio/src/examples/cpp11/operations/composed_7.cpp +++ b/3rdparty/asio/src/examples/cpp11/operations/composed_7.cpp @@ -2,13 +2,14 @@ // composed_7.cpp // ~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2021 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 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 <asio/compose.hpp> +#include <asio/deferred.hpp> #include <asio/io_context.hpp> #include <asio/ip/tcp.hpp> #include <asio/steady_timer.hpp> @@ -118,15 +119,26 @@ auto async_write_messages(tcp::socket& socket, const T& message, std::size_t repeat_count, 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 asio::yield_context - // (used for stackful coroutines) the return type would be also be void, as + // of: + // + // - the CompletionToken type, + // - the completion handler signature, and + // - the asynchronous operation's initiation function object. + // + // When the completion token is a simple callback, the return type is always + // void. In this example, when the completion token is asio::yield_context + // (used for stackful coroutines) the return type would also be void, as // there is no non-error argument to the completion handler. When the - // completion token is asio::use_future it would be std::future<void>. - -> typename asio::async_result< - typename std::decay<CompletionToken>::type, - void(std::error_code)>::return_type + // completion token is asio::use_future it would be std::future<void>. When + // the completion token is asio::deferred, the return type differs for each + // asynchronous operation. + // + // In C++11 we deduce the type from the call to asio::async_compose. + -> decltype( + asio::async_compose< + CompletionToken, void(std::error_code)>( + std::declval<async_write_messages_implementation>(), + token, socket)) { // Encode the message and copy it into an allocated buffer. The buffer will // be maintained for the lifetime of the composed asynchronous operation. @@ -186,6 +198,39 @@ void test_callback() //------------------------------------------------------------------------------ +void test_deferred() +{ + asio::io_context io_context; + + tcp::acceptor acceptor(io_context, {tcp::v4(), 55555}); + tcp::socket socket = acceptor.accept(); + + // Test our asynchronous operation using the deferred completion token. This + // token causes the operation's initiating function to package up the + // operation and its arguments to return a function object, which may then be + // used to launch the asynchronous operation. + auto op = async_write_messages(socket, + "Testing deferred\r\n", 5, asio::deferred); + + // Launch the operation using a lambda as a callback. + std::move(op)( + [](const std::error_code& error) + { + if (!error) + { + std::cout << "Messages sent\n"; + } + else + { + std::cout << "Error: " << error.message() << "\n"; + } + }); + + io_context.run(); +} + +//------------------------------------------------------------------------------ + void test_future() { asio::io_context io_context; @@ -218,5 +263,6 @@ void test_future() int main() { test_callback(); + test_deferred(); test_future(); } diff --git a/3rdparty/asio/src/examples/cpp11/operations/composed_8.cpp b/3rdparty/asio/src/examples/cpp11/operations/composed_8.cpp index 7c24c7251c6..ce22a5b418d 100644 --- a/3rdparty/asio/src/examples/cpp11/operations/composed_8.cpp +++ b/3rdparty/asio/src/examples/cpp11/operations/composed_8.cpp @@ -2,13 +2,14 @@ // composed_8.cpp // ~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2021 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 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 <asio/compose.hpp> +#include <asio/deferred.hpp> #include <asio/io_context.hpp> #include <asio/ip/tcp.hpp> #include <asio/steady_timer.hpp> @@ -114,15 +115,26 @@ auto async_write_messages(tcp::socket& socket, const T& message, std::size_t repeat_count, 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 asio::yield_context - // (used for stackful coroutines) the return type would be also be void, as + // of: + // + // - the CompletionToken type, + // - the completion handler signature, and + // - the asynchronous operation's initiation function object. + // + // When the completion token is a simple callback, the return type is always + // void. In this example, when the completion token is asio::yield_context + // (used for stackful coroutines) the return type would also be void, as // there is no non-error argument to the completion handler. When the - // completion token is asio::use_future it would be std::future<void>. - -> typename asio::async_result< - typename std::decay<CompletionToken>::type, - void(std::error_code)>::return_type + // completion token is asio::use_future it would be std::future<void>. When + // the completion token is asio::deferred, the return type differs for each + // asynchronous operation. + // + // In C++11 we deduce the type from the call to asio::async_compose. + -> decltype( + asio::async_compose< + CompletionToken, void(std::error_code)>( + std::declval<async_write_messages_implementation>(), + token, socket)) { // Encode the message and copy it into an allocated buffer. The buffer will // be maintained for the lifetime of the composed asynchronous operation. @@ -181,6 +193,39 @@ void test_callback() //------------------------------------------------------------------------------ +void test_deferred() +{ + asio::io_context io_context; + + tcp::acceptor acceptor(io_context, {tcp::v4(), 55555}); + tcp::socket socket = acceptor.accept(); + + // Test our asynchronous operation using the deferred completion token. This + // token causes the operation's initiating function to package up the + // operation and its arguments to return a function object, which may then be + // used to launch the asynchronous operation. + auto op = async_write_messages(socket, + "Testing deferred\r\n", 5, asio::deferred); + + // Launch the operation using a lambda as a callback. + std::move(op)( + [](const std::error_code& error) + { + if (!error) + { + std::cout << "Messages sent\n"; + } + else + { + std::cout << "Error: " << error.message() << "\n"; + } + }); + + io_context.run(); +} + +//------------------------------------------------------------------------------ + void test_future() { asio::io_context io_context; @@ -213,5 +258,6 @@ void test_future() int main() { test_callback(); + test_deferred(); test_future(); } |