summaryrefslogtreecommitdiff
path: root/boost/asio/experimental/co_spawn.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'boost/asio/experimental/co_spawn.hpp')
-rw-r--r--boost/asio/experimental/co_spawn.hpp228
1 files changed, 228 insertions, 0 deletions
diff --git a/boost/asio/experimental/co_spawn.hpp b/boost/asio/experimental/co_spawn.hpp
new file mode 100644
index 0000000000..c900da11f0
--- /dev/null
+++ b/boost/asio/experimental/co_spawn.hpp
@@ -0,0 +1,228 @@
+//
+// 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