// // 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 #if defined(BOOST_ASIO_HAS_CO_AWAIT) || defined(GENERATING_DOCUMENTATION) #include #include #include #include namespace boost { namespace asio { namespace experimental { namespace detail { using std::experimental::coroutine_handle; template class awaiter; template class awaitee_base; template class awaitee; template class await_handler_base; template 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 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 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 friend class detail::awaitee_base; template friend class detail::await_handler_base; // Private constructor used by awaitee_base. explicit await_token(detail::awaiter* a) : awaiter_(a) { } detail::awaiter* awaiter_; }; /// The return type of a coroutine or asynchronous operation. template > 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>::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> h) { awaitee_->attach_caller(h); } // Support for co_await keyword. template void await_suspend(detail::coroutine_handle> h) { awaitee_->attach_caller(h); } // Support for co_await keyword. T await_resume() { return awaitee_->get(); } #endif // !defined(GENERATING_DOCUMENTATION) private: template friend class detail::awaitee; template 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* a) : awaitee_(a) {} detail::awaitee* awaitee_; }; /// Spawn a new thread of execution. template ::value>::type> inline auto co_spawn(const Executor& ex, F&& f, CompletionToken&& token) { return detail::co_spawn(ex, std::forward(f), std::forward(token)); } /// Spawn a new thread of execution. template ::value>::type> inline auto co_spawn(ExecutionContext& ctx, F&& f, CompletionToken&& token) { return detail::co_spawn(ctx.get_executor(), std::forward(f), std::forward(token)); } /// Spawn a new thread of execution. template inline auto co_spawn(const await_token& parent, F&& f, CompletionToken&& token) { return detail::co_spawn(parent.get_executor(), std::forward(f), std::forward(token)); } } // namespace experimental } // namespace asio } // namespace boost #include #include #endif // defined(BOOST_ASIO_HAS_CO_AWAIT) || defined(GENERATING_DOCUMENTATION) #endif // BOOST_ASIO_EXPERIMENTAL_CO_SPAWN_HPP