diff --git a/doc/overview/token_adapters.qbk b/doc/overview/token_adapters.qbk index 6538092e..8afcdfd7 100644 --- a/doc/overview/token_adapters.qbk +++ b/doc/overview/token_adapters.qbk @@ -162,7 +162,8 @@ For example: { // ... }, - 42) + 42 + ) ); std::future f = timer.async_wait( @@ -186,7 +187,8 @@ For example: { // ... }, - 42) + 42 + ) ); std::future> f = timer.async_wait( @@ -196,6 +198,37 @@ For example: ) ); +[heading consign] + +The [link boost_asio.reference.consign `consign`] completion token adapter can be +used to attach additional values to a completion handler. This is typically used +to keep at least one copy of an object, such as a smart pointer, alive until the +completion handler is called. + +For example: + + auto timer1 = std::make_shared(my_io_context); + timer1->expires_after(std::chrono::seconds(1)); + timer1->async_wait( + boost::asio::consign( + [](boost::system::error_code ec) + { + // ... + }, + timer1 + ) + ); + + auto timer2 = std::make_shared(my_io_context); + timer2->expires_after(std::chrono::seconds(30)); + std::future f = + timer2->async_wait( + boost::asio::consign( + boost::asio::use_future, + timer2 + ) + ); + [heading See Also] [link boost_asio.reference.bind_executor bind_executor], diff --git a/doc/quickref.xml b/doc/quickref.xml index b6c181a7..2a14bf31 100644 --- a/doc/quickref.xml +++ b/doc/quickref.xml @@ -238,6 +238,7 @@ bind_cancellation_slot bind_executor co_spawn + consign dispatch defer get_associated_allocator @@ -267,6 +268,7 @@ basic_yield_context cancellation_filter cancellation_slot_binder + consign_t deferred_t executor_binder executor_work_guard diff --git a/include/boost/asio.hpp b/include/boost/asio.hpp index 222848ac..a7b01da3 100644 --- a/include/boost/asio.hpp +++ b/include/boost/asio.hpp @@ -66,6 +66,7 @@ #include #include #include +#include #include #include #include diff --git a/include/boost/asio/consign.hpp b/include/boost/asio/consign.hpp new file mode 100644 index 00000000..36c860b8 --- /dev/null +++ b/include/boost/asio/consign.hpp @@ -0,0 +1,88 @@ +// +// consign.hpp +// ~~~~~~~~~~ +// +// Copyright (c) 2003-2022 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) +// + +#ifndef BOOST_ASIO_CONSIGN_HPP +#define BOOST_ASIO_CONSIGN_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if (defined(BOOST_ASIO_HAS_STD_TUPLE) \ + && defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES)) \ + || defined(GENERATING_DOCUMENTATION) + +#include +#include + +#include + +namespace boost { +namespace asio { + +/// Completion token type used to specify that the completion handler should +/// carry additional values along with it. +/** + * This completion token adapter is typically used to keepat least one copy of + * an object, such as a smart pointer, alive until the completion handler is + * called. + */ +template +class consign_t +{ +public: + /// Constructor. + template + BOOST_ASIO_CONSTEXPR explicit consign_t( + BOOST_ASIO_MOVE_ARG(T) completion_token, + BOOST_ASIO_MOVE_ARG(V)... values) + : token_(BOOST_ASIO_MOVE_CAST(T)(completion_token)), + values_(BOOST_ASIO_MOVE_CAST(V)(values)...) + { + } + +//private: + CompletionToken token_; + std::tuple values_; +}; + +/// Completion token adapter used to specify that the completion handler should +/// carry additional values along with it. +/** + * This completion token adapter is typically used to keepat least one copy of + * an object, such as a smart pointer, alive until the completion handler is + * called. + */ +template +BOOST_ASIO_NODISCARD inline BOOST_ASIO_CONSTEXPR consign_t< + typename decay::type, typename decay::type...> +consign(BOOST_ASIO_MOVE_ARG(CompletionToken) completion_token, + BOOST_ASIO_MOVE_ARG(Values)... values) +{ + return consign_t< + typename decay::type, typename decay::type...>( + BOOST_ASIO_MOVE_CAST(CompletionToken)(completion_token), + BOOST_ASIO_MOVE_CAST(Values)(values)...); +} + +} // namespace asio +} // namespace boost + +#include + +#include + +#endif // (defined(BOOST_ASIO_HAS_STD_TUPLE) + // && defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES)) + // || defined(GENERATING_DOCUMENTATION) + +#endif // BOOST_ASIO_CONSIGN_HPP diff --git a/include/boost/asio/impl/consign.hpp b/include/boost/asio/impl/consign.hpp new file mode 100644 index 00000000..96a6811f --- /dev/null +++ b/include/boost/asio/impl/consign.hpp @@ -0,0 +1,204 @@ +// +// impl/consign.hpp +// ~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2022 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) +// + +#ifndef BOOST_ASIO_IMPL_CONSIGN_HPP +#define BOOST_ASIO_IMPL_CONSIGN_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +// Class to adapt a consign_t as a completion handler. +template +class consign_handler +{ +public: + typedef void result_type; + + template + consign_handler(BOOST_ASIO_MOVE_ARG(H) handler, std::tuple values) + : handler_(BOOST_ASIO_MOVE_CAST(H)(handler)), + values_(BOOST_ASIO_MOVE_CAST(std::tuple)(values)) + { + } + + template + void operator()(BOOST_ASIO_MOVE_ARG(Args)... args) + { + BOOST_ASIO_MOVE_OR_LVALUE(Handler)(handler_)( + BOOST_ASIO_MOVE_CAST(Args)(args)...); + } + +//private: + Handler handler_; + std::tuple values_; +}; + +template +inline asio_handler_allocate_is_deprecated +asio_handler_allocate(std::size_t size, + consign_handler* this_handler) +{ +#if defined(BOOST_ASIO_NO_DEPRECATED) + boost_asio_handler_alloc_helpers::allocate(size, this_handler->handler_); + return asio_handler_allocate_is_no_longer_used(); +#else // defined(BOOST_ASIO_NO_DEPRECATED) + return boost_asio_handler_alloc_helpers::allocate( + size, this_handler->handler_); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) +} + +template +inline asio_handler_deallocate_is_deprecated +asio_handler_deallocate(void* pointer, std::size_t size, + consign_handler* this_handler) +{ + boost_asio_handler_alloc_helpers::deallocate( + pointer, size, this_handler->handler_); +#if defined(BOOST_ASIO_NO_DEPRECATED) + return asio_handler_deallocate_is_no_longer_used(); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) +} + +template +inline bool asio_handler_is_continuation( + consign_handler* this_handler) +{ + return boost_asio_handler_cont_helpers::is_continuation( + this_handler->handler_); +} + +template +inline asio_handler_invoke_is_deprecated +asio_handler_invoke(Function& function, + consign_handler* this_handler) +{ + boost_asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); +#if defined(BOOST_ASIO_NO_DEPRECATED) + return asio_handler_invoke_is_no_longer_used(); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) +} + +template +inline asio_handler_invoke_is_deprecated +asio_handler_invoke(const Function& function, + consign_handler* this_handler) +{ + boost_asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); +#if defined(BOOST_ASIO_NO_DEPRECATED) + return asio_handler_invoke_is_no_longer_used(); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) +} + +} // namespace detail + +#if !defined(GENERATING_DOCUMENTATION) + +template +struct async_result< + consign_t, Signatures...> + : async_result +{ + template + struct init_wrapper + { + init_wrapper(Initiation init) + : initiation_(BOOST_ASIO_MOVE_CAST(Initiation)(init)) + { + } + + template + void operator()( + BOOST_ASIO_MOVE_ARG(Handler) handler, + std::tuple values, + BOOST_ASIO_MOVE_ARG(Args)... args) + { + BOOST_ASIO_MOVE_CAST(Initiation)(initiation_)( + detail::consign_handler< + typename decay::type, Values...>( + BOOST_ASIO_MOVE_CAST(Handler)(handler), + BOOST_ASIO_MOVE_CAST(std::tuple)(values)), + BOOST_ASIO_MOVE_CAST(Args)(args)...); + } + + Initiation initiation_; + }; + + template + static BOOST_ASIO_INITFN_DEDUCED_RESULT_TYPE(CompletionToken, Signatures..., + (async_initiate( + declval::type> >(), + declval(), + declval >(), + declval()...))) + initiate( + BOOST_ASIO_MOVE_ARG(Initiation) initiation, + BOOST_ASIO_MOVE_ARG(RawCompletionToken) token, + BOOST_ASIO_MOVE_ARG(Args)... args) + { + return async_initiate( + init_wrapper::type>( + BOOST_ASIO_MOVE_CAST(Initiation)(initiation)), + token.token_, + BOOST_ASIO_MOVE_CAST(std::tuple)(token.values_), + BOOST_ASIO_MOVE_CAST(Args)(args)...); + } +}; + +template