Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:29:08

0001 //
0002 // co_spawn.hpp
0003 // ~~~~~~~~~~~~
0004 //
0005 // Copyright (c) 2003-2023 Christopher M. Kohlhoff (chris at kohlhoff dot com)
0006 //
0007 // Distributed under the Boost Software License, Version 1.0. (See accompanying
0008 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
0009 //
0010 
0011 #ifndef BOOST_ASIO_CO_SPAWN_HPP
0012 #define BOOST_ASIO_CO_SPAWN_HPP
0013 
0014 #if defined(_MSC_VER) && (_MSC_VER >= 1200)
0015 # pragma once
0016 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
0017 
0018 #include <boost/asio/detail/config.hpp>
0019 
0020 #if defined(BOOST_ASIO_HAS_CO_AWAIT) || defined(GENERATING_DOCUMENTATION)
0021 
0022 #include <boost/asio/awaitable.hpp>
0023 #include <boost/asio/execution/executor.hpp>
0024 #include <boost/asio/execution_context.hpp>
0025 #include <boost/asio/is_executor.hpp>
0026 
0027 #include <boost/asio/detail/push_options.hpp>
0028 
0029 namespace boost {
0030 namespace asio {
0031 namespace detail {
0032 
0033 template <typename T>
0034 struct awaitable_signature;
0035 
0036 template <typename T, typename Executor>
0037 struct awaitable_signature<awaitable<T, Executor>>
0038 {
0039   typedef void type(std::exception_ptr, T);
0040 };
0041 
0042 template <typename Executor>
0043 struct awaitable_signature<awaitable<void, Executor>>
0044 {
0045   typedef void type(std::exception_ptr);
0046 };
0047 
0048 } // namespace detail
0049 
0050 /// Spawn a new coroutined-based thread of execution.
0051 /**
0052  * @param ex The executor that will be used to schedule the new thread of
0053  * execution.
0054  *
0055  * @param a The boost::asio::awaitable object that is the result of calling the
0056  * coroutine's entry point function.
0057  *
0058  * @param token The @ref completion_token that will handle the notification that
0059  * the thread of execution has completed. The function signature of the
0060  * completion handler must be:
0061  * @code void handler(std::exception_ptr, T); @endcode
0062  *
0063  * @par Completion Signature
0064  * @code void(std::exception_ptr, T) @endcode
0065  *
0066  * @par Example
0067  * @code
0068  * boost::asio::awaitable<std::size_t> echo(tcp::socket socket)
0069  * {
0070  *   std::size_t bytes_transferred = 0;
0071  *
0072  *   try
0073  *   {
0074  *     char data[1024];
0075  *     for (;;)
0076  *     {
0077  *       std::size_t n = co_await socket.async_read_some(
0078  *           boost::asio::buffer(data), boost::asio::use_awaitable);
0079  *
0080  *       co_await boost::asio::async_write(socket,
0081  *           boost::asio::buffer(data, n), boost::asio::use_awaitable);
0082  *
0083  *       bytes_transferred += n;
0084  *     }
0085  *   }
0086  *   catch (const std::exception&)
0087  *   {
0088  *   }
0089  *
0090  *   co_return bytes_transferred;
0091  * }
0092  *
0093  * // ...
0094  *
0095  * boost::asio::co_spawn(my_executor,
0096  *   echo(std::move(my_tcp_socket)),
0097  *   [](std::exception_ptr e, std::size_t n)
0098  *   {
0099  *     std::cout << "transferred " << n << "\n";
0100  *   });
0101  * @endcode
0102  *
0103  * @par Per-Operation Cancellation
0104  * The new thread of execution is created with a cancellation state that
0105  * supports @c cancellation_type::terminal values only. To change the
0106  * cancellation state, call boost::asio::this_coro::reset_cancellation_state.
0107  */
0108 template <typename Executor, typename T, typename AwaitableExecutor,
0109     BOOST_ASIO_COMPLETION_TOKEN_FOR(
0110       void(std::exception_ptr, T)) CompletionToken
0111         BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(Executor)>
0112 inline BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(
0113     CompletionToken, void(std::exception_ptr, T))
0114 co_spawn(const Executor& ex, awaitable<T, AwaitableExecutor> a,
0115     CompletionToken&& token
0116       BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(Executor),
0117     constraint_t<
0118       (is_executor<Executor>::value || execution::is_executor<Executor>::value)
0119         && is_convertible<Executor, AwaitableExecutor>::value
0120     > = 0);
0121 
0122 /// Spawn a new coroutined-based thread of execution.
0123 /**
0124  * @param ex The executor that will be used to schedule the new thread of
0125  * execution.
0126  *
0127  * @param a The boost::asio::awaitable object that is the result of calling the
0128  * coroutine's entry point function.
0129  *
0130  * @param token The @ref completion_token that will handle the notification that
0131  * the thread of execution has completed. The function signature of the
0132  * completion handler must be:
0133  * @code void handler(std::exception_ptr); @endcode
0134  *
0135  * @par Completion Signature
0136  * @code void(std::exception_ptr) @endcode
0137  *
0138  * @par Example
0139  * @code
0140  * boost::asio::awaitable<void> echo(tcp::socket socket)
0141  * {
0142  *   try
0143  *   {
0144  *     char data[1024];
0145  *     for (;;)
0146  *     {
0147  *       std::size_t n = co_await socket.async_read_some(
0148  *           boost::asio::buffer(data), boost::asio::use_awaitable);
0149  *
0150  *       co_await boost::asio::async_write(socket,
0151  *           boost::asio::buffer(data, n), boost::asio::use_awaitable);
0152  *     }
0153  *   }
0154  *   catch (const std::exception& e)
0155  *   {
0156  *     std::cerr << "Exception: " << e.what() << "\n";
0157  *   }
0158  * }
0159  *
0160  * // ...
0161  *
0162  * boost::asio::co_spawn(my_executor,
0163  *   echo(std::move(my_tcp_socket)),
0164  *   boost::asio::detached);
0165  * @endcode
0166  *
0167  * @par Per-Operation Cancellation
0168  * The new thread of execution is created with a cancellation state that
0169  * supports @c cancellation_type::terminal values only. To change the
0170  * cancellation state, call boost::asio::this_coro::reset_cancellation_state.
0171  */
0172 template <typename Executor, typename AwaitableExecutor,
0173     BOOST_ASIO_COMPLETION_TOKEN_FOR(
0174       void(std::exception_ptr)) CompletionToken
0175         BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(Executor)>
0176 inline BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(
0177     CompletionToken, void(std::exception_ptr))
0178 co_spawn(const Executor& ex, awaitable<void, AwaitableExecutor> a,
0179     CompletionToken&& token
0180       BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(Executor),
0181     constraint_t<
0182       (is_executor<Executor>::value || execution::is_executor<Executor>::value)
0183         && is_convertible<Executor, AwaitableExecutor>::value
0184     > = 0);
0185 
0186 /// Spawn a new coroutined-based thread of execution.
0187 /**
0188  * @param ctx An execution context that will provide the executor to be used to
0189  * schedule the new thread of execution.
0190  *
0191  * @param a The boost::asio::awaitable object that is the result of calling the
0192  * coroutine's entry point function.
0193  *
0194  * @param token The @ref completion_token that will handle the notification that
0195  * the thread of execution has completed. The function signature of the
0196  * completion handler must be:
0197  * @code void handler(std::exception_ptr); @endcode
0198  *
0199  * @par Completion Signature
0200  * @code void(std::exception_ptr, T) @endcode
0201  *
0202  * @par Example
0203  * @code
0204  * boost::asio::awaitable<std::size_t> echo(tcp::socket socket)
0205  * {
0206  *   std::size_t bytes_transferred = 0;
0207  *
0208  *   try
0209  *   {
0210  *     char data[1024];
0211  *     for (;;)
0212  *     {
0213  *       std::size_t n = co_await socket.async_read_some(
0214  *           boost::asio::buffer(data), boost::asio::use_awaitable);
0215  *
0216  *       co_await boost::asio::async_write(socket,
0217  *           boost::asio::buffer(data, n), boost::asio::use_awaitable);
0218  *
0219  *       bytes_transferred += n;
0220  *     }
0221  *   }
0222  *   catch (const std::exception&)
0223  *   {
0224  *   }
0225  *
0226  *   co_return bytes_transferred;
0227  * }
0228  *
0229  * // ...
0230  *
0231  * boost::asio::co_spawn(my_io_context,
0232  *   echo(std::move(my_tcp_socket)),
0233  *   [](std::exception_ptr e, std::size_t n)
0234  *   {
0235  *     std::cout << "transferred " << n << "\n";
0236  *   });
0237  * @endcode
0238  *
0239  * @par Per-Operation Cancellation
0240  * The new thread of execution is created with a cancellation state that
0241  * supports @c cancellation_type::terminal values only. To change the
0242  * cancellation state, call boost::asio::this_coro::reset_cancellation_state.
0243  */
0244 template <typename ExecutionContext, typename T, typename AwaitableExecutor,
0245     BOOST_ASIO_COMPLETION_TOKEN_FOR(
0246       void(std::exception_ptr, T)) CompletionToken
0247         BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(
0248           typename ExecutionContext::executor_type)>
0249 inline BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(
0250     CompletionToken, void(std::exception_ptr, T))
0251 co_spawn(ExecutionContext& ctx, awaitable<T, AwaitableExecutor> a,
0252     CompletionToken&& token
0253       BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(
0254         typename ExecutionContext::executor_type),
0255     constraint_t<
0256       is_convertible<ExecutionContext&, execution_context&>::value
0257         && is_convertible<typename ExecutionContext::executor_type,
0258           AwaitableExecutor>::value
0259     > = 0);
0260 
0261 /// Spawn a new coroutined-based thread of execution.
0262 /**
0263  * @param ctx An execution context that will provide the executor to be used to
0264  * schedule the new thread of execution.
0265  *
0266  * @param a The boost::asio::awaitable object that is the result of calling the
0267  * coroutine's entry point function.
0268  *
0269  * @param token The @ref completion_token that will handle the notification that
0270  * the thread of execution has completed. The function signature of the
0271  * completion handler must be:
0272  * @code void handler(std::exception_ptr); @endcode
0273  *
0274  * @par Completion Signature
0275  * @code void(std::exception_ptr) @endcode
0276  *
0277  * @par Example
0278  * @code
0279  * boost::asio::awaitable<void> echo(tcp::socket socket)
0280  * {
0281  *   try
0282  *   {
0283  *     char data[1024];
0284  *     for (;;)
0285  *     {
0286  *       std::size_t n = co_await socket.async_read_some(
0287  *           boost::asio::buffer(data), boost::asio::use_awaitable);
0288  *
0289  *       co_await boost::asio::async_write(socket,
0290  *           boost::asio::buffer(data, n), boost::asio::use_awaitable);
0291  *     }
0292  *   }
0293  *   catch (const std::exception& e)
0294  *   {
0295  *     std::cerr << "Exception: " << e.what() << "\n";
0296  *   }
0297  * }
0298  *
0299  * // ...
0300  *
0301  * boost::asio::co_spawn(my_io_context,
0302  *   echo(std::move(my_tcp_socket)),
0303  *   boost::asio::detached);
0304  * @endcode
0305  *
0306  * @par Per-Operation Cancellation
0307  * The new thread of execution is created with a cancellation state that
0308  * supports @c cancellation_type::terminal values only. To change the
0309  * cancellation state, call boost::asio::this_coro::reset_cancellation_state.
0310  */
0311 template <typename ExecutionContext, typename AwaitableExecutor,
0312     BOOST_ASIO_COMPLETION_TOKEN_FOR(
0313       void(std::exception_ptr)) CompletionToken
0314         BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(
0315           typename ExecutionContext::executor_type)>
0316 inline BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(
0317     CompletionToken, void(std::exception_ptr))
0318 co_spawn(ExecutionContext& ctx, awaitable<void, AwaitableExecutor> a,
0319     CompletionToken&& token
0320       BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(
0321         typename ExecutionContext::executor_type),
0322     constraint_t<
0323       is_convertible<ExecutionContext&, execution_context&>::value
0324         && is_convertible<typename ExecutionContext::executor_type,
0325           AwaitableExecutor>::value
0326     > = 0);
0327 
0328 /// Spawn a new coroutined-based thread of execution.
0329 /**
0330  * @param ex The executor that will be used to schedule the new thread of
0331  * execution.
0332  *
0333  * @param f A nullary function object with a return type of the form
0334  * @c boost::asio::awaitable<R,E> that will be used as the coroutine's entry
0335  * point.
0336  *
0337  * @param token The @ref completion_token that will handle the notification
0338  * that the thread of execution has completed. If @c R is @c void, the function
0339  * signature of the completion handler must be:
0340  *
0341  * @code void handler(std::exception_ptr); @endcode
0342  * Otherwise, the function signature of the completion handler must be:
0343  * @code void handler(std::exception_ptr, R); @endcode
0344  *
0345  * @par Completion Signature
0346  * @code void(std::exception_ptr, R) @endcode
0347  * where @c R is the first template argument to the @c awaitable returned by the
0348  * supplied function object @c F:
0349  * @code boost::asio::awaitable<R, AwaitableExecutor> F() @endcode
0350  *
0351  * @par Example
0352  * @code
0353  * boost::asio::awaitable<std::size_t> echo(tcp::socket socket)
0354  * {
0355  *   std::size_t bytes_transferred = 0;
0356  *
0357  *   try
0358  *   {
0359  *     char data[1024];
0360  *     for (;;)
0361  *     {
0362  *       std::size_t n = co_await socket.async_read_some(
0363  *           boost::asio::buffer(data), boost::asio::use_awaitable);
0364  *
0365  *       co_await boost::asio::async_write(socket,
0366  *           boost::asio::buffer(data, n), boost::asio::use_awaitable);
0367  *
0368  *       bytes_transferred += n;
0369  *     }
0370  *   }
0371  *   catch (const std::exception&)
0372  *   {
0373  *   }
0374  *
0375  *   co_return bytes_transferred;
0376  * }
0377  *
0378  * // ...
0379  *
0380  * boost::asio::co_spawn(my_executor,
0381  *   [socket = std::move(my_tcp_socket)]() mutable
0382  *     -> boost::asio::awaitable<void>
0383  *   {
0384  *     try
0385  *     {
0386  *       char data[1024];
0387  *       for (;;)
0388  *       {
0389  *         std::size_t n = co_await socket.async_read_some(
0390  *             boost::asio::buffer(data), boost::asio::use_awaitable);
0391  *
0392  *         co_await boost::asio::async_write(socket,
0393  *             boost::asio::buffer(data, n), boost::asio::use_awaitable);
0394  *       }
0395  *     }
0396  *     catch (const std::exception& e)
0397  *     {
0398  *       std::cerr << "Exception: " << e.what() << "\n";
0399  *     }
0400  *   }, boost::asio::detached);
0401  * @endcode
0402  *
0403  * @par Per-Operation Cancellation
0404  * The new thread of execution is created with a cancellation state that
0405  * supports @c cancellation_type::terminal values only. To change the
0406  * cancellation state, call boost::asio::this_coro::reset_cancellation_state.
0407  */
0408 template <typename Executor, typename F,
0409     BOOST_ASIO_COMPLETION_TOKEN_FOR(typename detail::awaitable_signature<
0410       result_of_t<F()>>::type) CompletionToken
0411         BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(Executor)>
0412 BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken,
0413     typename detail::awaitable_signature<result_of_t<F()>>::type)
0414 co_spawn(const Executor& ex, F&& f,
0415     CompletionToken&& token
0416       BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(Executor),
0417     constraint_t<
0418       is_executor<Executor>::value || execution::is_executor<Executor>::value
0419     > = 0);
0420 
0421 /// Spawn a new coroutined-based thread of execution.
0422 /**
0423  * @param ctx An execution context that will provide the executor to be used to
0424  * schedule the new thread of execution.
0425  *
0426  * @param f A nullary function object with a return type of the form
0427  * @c boost::asio::awaitable<R,E> that will be used as the coroutine's entry
0428  * point.
0429  *
0430  * @param token The @ref completion_token that will handle the notification
0431  * that the thread of execution has completed. If @c R is @c void, the function
0432  * signature of the completion handler must be:
0433  *
0434  * @code void handler(std::exception_ptr); @endcode
0435  * Otherwise, the function signature of the completion handler must be:
0436  * @code void handler(std::exception_ptr, R); @endcode
0437  *
0438  * @par Completion Signature
0439  * @code void(std::exception_ptr, R) @endcode
0440  * where @c R is the first template argument to the @c awaitable returned by the
0441  * supplied function object @c F:
0442  * @code boost::asio::awaitable<R, AwaitableExecutor> F() @endcode
0443  *
0444  * @par Example
0445  * @code
0446  * boost::asio::awaitable<std::size_t> echo(tcp::socket socket)
0447  * {
0448  *   std::size_t bytes_transferred = 0;
0449  *
0450  *   try
0451  *   {
0452  *     char data[1024];
0453  *     for (;;)
0454  *     {
0455  *       std::size_t n = co_await socket.async_read_some(
0456  *           boost::asio::buffer(data), boost::asio::use_awaitable);
0457  *
0458  *       co_await boost::asio::async_write(socket,
0459  *           boost::asio::buffer(data, n), boost::asio::use_awaitable);
0460  *
0461  *       bytes_transferred += n;
0462  *     }
0463  *   }
0464  *   catch (const std::exception&)
0465  *   {
0466  *   }
0467  *
0468  *   co_return bytes_transferred;
0469  * }
0470  *
0471  * // ...
0472  *
0473  * boost::asio::co_spawn(my_io_context,
0474  *   [socket = std::move(my_tcp_socket)]() mutable
0475  *     -> boost::asio::awaitable<void>
0476  *   {
0477  *     try
0478  *     {
0479  *       char data[1024];
0480  *       for (;;)
0481  *       {
0482  *         std::size_t n = co_await socket.async_read_some(
0483  *             boost::asio::buffer(data), boost::asio::use_awaitable);
0484  *
0485  *         co_await boost::asio::async_write(socket,
0486  *             boost::asio::buffer(data, n), boost::asio::use_awaitable);
0487  *       }
0488  *     }
0489  *     catch (const std::exception& e)
0490  *     {
0491  *       std::cerr << "Exception: " << e.what() << "\n";
0492  *     }
0493  *   }, boost::asio::detached);
0494  * @endcode
0495  *
0496  * @par Per-Operation Cancellation
0497  * The new thread of execution is created with a cancellation state that
0498  * supports @c cancellation_type::terminal values only. To change the
0499  * cancellation state, call boost::asio::this_coro::reset_cancellation_state.
0500  */
0501 template <typename ExecutionContext, typename F,
0502     BOOST_ASIO_COMPLETION_TOKEN_FOR(typename detail::awaitable_signature<
0503       result_of_t<F()>>::type) CompletionToken
0504         BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(
0505           typename ExecutionContext::executor_type)>
0506 BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken,
0507     typename detail::awaitable_signature<result_of_t<F()>>::type)
0508 co_spawn(ExecutionContext& ctx, F&& f,
0509     CompletionToken&& token
0510       BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(
0511         typename ExecutionContext::executor_type),
0512     constraint_t<
0513       is_convertible<ExecutionContext&, execution_context&>::value
0514     > = 0);
0515 
0516 } // namespace asio
0517 } // namespace boost
0518 
0519 #include <boost/asio/detail/pop_options.hpp>
0520 
0521 #include <boost/asio/impl/co_spawn.hpp>
0522 
0523 #endif // defined(BOOST_ASIO_HAS_CO_AWAIT) || defined(GENERATING_DOCUMENTATION)
0524 
0525 #endif // BOOST_ASIO_CO_SPAWN_HPP