123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228 |
- //
- // experimental/co_spawn.hpp
- // ~~~~~~~~~~~~~~~~~~~~~~~~~
- //
- // Copyright (c) 2003-2018 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_EXPERIMENTAL_CO_SPAWN_HPP
- #define BOOST_ASIO_EXPERIMENTAL_CO_SPAWN_HPP
- #if defined(_MSC_VER) && (_MSC_VER >= 1200)
- # pragma once
- #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
- #include <boost/asio/detail/config.hpp>
- #if defined(BOOST_ASIO_HAS_CO_AWAIT) || defined(GENERATING_DOCUMENTATION)
- #include <experimental/coroutine>
- #include <boost/asio/executor.hpp>
- #include <boost/asio/strand.hpp>
- #include <boost/asio/detail/push_options.hpp>
- namespace boost {
- namespace asio {
- namespace experimental {
- namespace detail {
- using std::experimental::coroutine_handle;
- template <typename> class awaiter;
- template <typename> class awaitee_base;
- template <typename, typename> class awaitee;
- template <typename, typename> class await_handler_base;
- template <typename Executor, typename F, typename CompletionToken>
- auto co_spawn(const Executor& ex, F&& f, CompletionToken&& token);
- } // namespace detail
- namespace this_coro {
- /// Awaitable type that returns a completion token for the current coroutine.
- struct token_t {};
- /// Awaitable object that returns a completion token for the current coroutine.
- constexpr inline token_t token() { return {}; }
- /// Awaitable type that returns the executor of the current coroutine.
- struct executor_t {};
- /// Awaitable object that returns the executor of the current coroutine.
- constexpr inline executor_t executor() { return {}; }
- } // namespace this_coro
- /// A completion token that represents the currently executing coroutine.
- /**
- * The await_token class is used to represent the currently executing
- * coroutine. An await_token may be passed as a handler to an asynchronous
- * operation. For example:
- *
- * @code awaitable<void> my_coroutine()
- * {
- * await_token token = co_await this_coro::token();
- * ...
- * std::size_t n = co_await my_socket.async_read_some(buffer, token);
- * ...
- * } @endcode
- *
- * The initiating function (async_read_some in the above example) suspends the
- * current coroutine. The coroutine is resumed when the asynchronous operation
- * completes, and the result of the operation is returned.
- */
- template <typename Executor>
- class await_token
- {
- public:
- /// The associated executor type.
- typedef Executor executor_type;
- /// Copy constructor.
- await_token(const await_token& other) noexcept
- : awaiter_(other.awaiter_)
- {
- }
- /// Move constructor.
- await_token(await_token&& other) noexcept
- : awaiter_(std::exchange(other.awaiter_, nullptr))
- {
- }
- /// Get the associated executor.
- executor_type get_executor() const noexcept
- {
- return awaiter_->get_executor();
- }
- private:
- // No assignment allowed.
- await_token& operator=(const await_token&) = delete;
- template <typename> friend class detail::awaitee_base;
- template <typename, typename> friend class detail::await_handler_base;
- // Private constructor used by awaitee_base.
- explicit await_token(detail::awaiter<Executor>* a)
- : awaiter_(a)
- {
- }
- detail::awaiter<Executor>* awaiter_;
- };
- /// The return type of a coroutine or asynchronous operation.
- template <typename T, typename Executor = strand<executor>>
- class awaitable
- {
- public:
- /// The type of the awaited value.
- typedef T value_type;
- /// The executor type that will be used for the coroutine.
- typedef Executor executor_type;
- /// Move constructor.
- awaitable(awaitable&& other) noexcept
- : awaitee_(std::exchange(other.awaitee_, nullptr))
- {
- }
- /// Destructor
- ~awaitable()
- {
- if (awaitee_)
- {
- detail::coroutine_handle<
- detail::awaitee<T, Executor>>::from_promise(
- *awaitee_).destroy();
- }
- }
- #if !defined(GENERATING_DOCUMENTATION)
- // Support for co_await keyword.
- bool await_ready() const noexcept
- {
- return awaitee_->ready();
- }
- // Support for co_await keyword.
- void await_suspend(detail::coroutine_handle<detail::awaiter<Executor>> h)
- {
- awaitee_->attach_caller(h);
- }
- // Support for co_await keyword.
- template <class U>
- void await_suspend(detail::coroutine_handle<detail::awaitee<U, Executor>> h)
- {
- awaitee_->attach_caller(h);
- }
- // Support for co_await keyword.
- T await_resume()
- {
- return awaitee_->get();
- }
- #endif // !defined(GENERATING_DOCUMENTATION)
- private:
- template <typename, typename> friend class detail::awaitee;
- template <typename, typename> friend class detail::await_handler_base;
- // Not copy constructible or copy assignable.
- awaitable(const awaitable&) = delete;
- awaitable& operator=(const awaitable&) = delete;
- // Construct the awaitable from a coroutine's promise object.
- explicit awaitable(detail::awaitee<T, Executor>* a) : awaitee_(a) {}
- detail::awaitee<T, Executor>* awaitee_;
- };
- /// Spawn a new thread of execution.
- template <typename Executor, typename F, typename CompletionToken,
- typename = typename enable_if<is_executor<Executor>::value>::type>
- inline auto co_spawn(const Executor& ex, F&& f, CompletionToken&& token)
- {
- return detail::co_spawn(ex, std::forward<F>(f),
- std::forward<CompletionToken>(token));
- }
- /// Spawn a new thread of execution.
- template <typename ExecutionContext, typename F, typename CompletionToken,
- typename = typename enable_if<
- is_convertible<ExecutionContext&, execution_context&>::value>::type>
- inline auto co_spawn(ExecutionContext& ctx, F&& f, CompletionToken&& token)
- {
- return detail::co_spawn(ctx.get_executor(), std::forward<F>(f),
- std::forward<CompletionToken>(token));
- }
- /// Spawn a new thread of execution.
- template <typename Executor, typename F, typename CompletionToken>
- inline auto co_spawn(const await_token<Executor>& parent,
- F&& f, CompletionToken&& token)
- {
- return detail::co_spawn(parent.get_executor(), std::forward<F>(f),
- std::forward<CompletionToken>(token));
- }
- } // namespace experimental
- } // namespace asio
- } // namespace boost
- #include <boost/asio/detail/pop_options.hpp>
- #include <boost/asio/experimental/impl/co_spawn.hpp>
- #endif // defined(BOOST_ASIO_HAS_CO_AWAIT) || defined(GENERATING_DOCUMENTATION)
- #endif // BOOST_ASIO_EXPERIMENTAL_CO_SPAWN_HPP
|