summaryrefslogtreecommitdiffstatshomepage
path: root/3rdparty/asio/include/asio/experimental/coro.hpp
diff options
context:
space:
mode:
Diffstat (limited to '3rdparty/asio/include/asio/experimental/coro.hpp')
-rw-r--r--3rdparty/asio/include/asio/experimental/coro.hpp293
1 files changed, 293 insertions, 0 deletions
diff --git a/3rdparty/asio/include/asio/experimental/coro.hpp b/3rdparty/asio/include/asio/experimental/coro.hpp
new file mode 100644
index 00000000000..de909d29a6b
--- /dev/null
+++ b/3rdparty/asio/include/asio/experimental/coro.hpp
@@ -0,0 +1,293 @@
+//
+// experimental/coro.hpp
+// ~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2021-2023 Klemens D. Morgenstern
+// (klemens dot morgenstern at gmx dot net)
+//
+// 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 ASIO_EXPERIMENTAL_CORO_HPP
+#define ASIO_EXPERIMENTAL_CORO_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/dispatch.hpp"
+#include "asio/error.hpp"
+#include "asio/error_code.hpp"
+#include "asio/experimental/coro_traits.hpp"
+#include "asio/experimental/detail/coro_promise_allocator.hpp"
+#include "asio/experimental/detail/partial_promise.hpp"
+#include "asio/post.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace experimental {
+namespace detail {
+
+template <typename Signature, typename Return,
+ typename Executor, typename Allocator>
+struct coro_promise;
+
+template <typename T, typename Coroutine>
+struct coro_with_arg;
+
+} // namespace detail
+
+/// The main type of a resumable coroutine.
+/**
+ * Template parameter @c Yield specifies type or signature used by co_yield,
+ * @c Return specifies the type used for co_return, and @c Executor specifies
+ * the underlying executor type.
+ */
+template <typename Yield = void, typename Return = void,
+ typename Executor = any_io_executor,
+ typename Allocator = std::allocator<void>>
+struct coro
+{
+ /// The traits of the coroutine. See asio::experimental::coro_traits
+ /// for details.
+ using traits = coro_traits<Yield, Return, Executor>;
+
+ /// The value that can be passed into a symmetrical cororoutine. @c void if
+ /// asymmetrical.
+ using input_type = typename traits::input_type;
+
+ /// The type that can be passed out through a co_yield.
+ using yield_type = typename traits::yield_type;
+
+ /// The type that can be passed out through a co_return.
+ using return_type = typename traits::return_type;
+
+ /// The type received by a co_await or async_resume. Its a combination of
+ /// yield and return.
+ using result_type = typename traits::result_type;
+
+ /// The signature used by the async_resume.
+ using signature_type = typename traits::signature_type;
+
+ /// Whether or not the coroutine is noexcept.
+ constexpr static bool is_noexcept = traits::is_noexcept;
+
+ /// The error type of the coroutine. Void for noexcept
+ using error_type = typename traits::error_type;
+
+ /// Completion handler type used by async_resume.
+ using completion_handler = typename traits::completion_handler;
+
+ /// The internal promise-type of the coroutine.
+ using promise_type = detail::coro_promise<Yield, Return, Executor, Allocator>;
+
+#if !defined(GENERATING_DOCUMENTATION)
+ template <typename T, typename Coroutine>
+ friend struct detail::coro_with_arg;
+#endif // !defined(GENERATING_DOCUMENTATION)
+
+ /// The executor type.
+ using executor_type = Executor;
+
+ /// The allocator type.
+ using allocator_type = Allocator;
+
+#if !defined(GENERATING_DOCUMENTATION)
+ friend struct detail::coro_promise<Yield, Return, Executor, Allocator>;
+#endif // !defined(GENERATING_DOCUMENTATION)
+
+ /// The default constructor, gives an invalid coroutine.
+ coro() = default;
+
+ /// Move constructor.
+ coro(coro&& lhs) noexcept
+ : coro_(std::exchange(lhs.coro_, nullptr))
+ {
+ }
+
+ coro(const coro&) = delete;
+
+ /// Move assignment.
+ coro& operator=(coro&& lhs) noexcept
+ {
+ std::swap(coro_, lhs.coro_);
+ return *this;
+ }
+
+ coro& operator=(const coro&) = delete;
+
+ /// Destructor. Destroys the coroutine, if it holds a valid one.
+ /**
+ * @note This does not cancel an active coroutine. Destructing a resumable
+ * coroutine, i.e. one with a call to async_resume that has not completed, is
+ * undefined behaviour.
+ */
+ ~coro()
+ {
+ if (coro_ != nullptr)
+ {
+ struct destroyer
+ {
+ detail::coroutine_handle<promise_type> handle;
+
+ destroyer(const detail::coroutine_handle<promise_type>& handle)
+ : handle(handle)
+ { }
+
+ destroyer(destroyer&& lhs)
+ : handle(std::exchange(lhs.handle, nullptr))
+ {
+ }
+
+ destroyer(const destroyer&) = delete;
+
+ void operator()() {}
+
+ ~destroyer()
+ {
+ if (handle)
+ handle.destroy();
+ }
+ };
+
+ auto handle =
+ detail::coroutine_handle<promise_type>::from_promise(*coro_);
+ if (handle)
+ asio::dispatch(coro_->get_executor(), destroyer{handle});
+ }
+ }
+
+ /// Get the used executor.
+ executor_type get_executor() const
+ {
+ if (coro_)
+ return coro_->get_executor();
+
+ if constexpr (std::is_default_constructible_v<Executor>)
+ return Executor{};
+ else
+ throw std::logic_error("Coroutine has no executor");
+ }
+
+ /// Get the used allocator.
+ allocator_type get_allocator() const
+ {
+ if (coro_)
+ return coro_->get_allocator();
+
+ if constexpr (std::is_default_constructible_v<Allocator>)
+ return Allocator{};
+ else
+ throw std::logic_error(
+ "Coroutine has no available allocator without a constructed promise");
+ }
+
+ /// Resume the coroutine.
+ /**
+ * @param token The completion token of the async resume.
+ *
+ * @attention Calling an invalid coroutine with a noexcept signature is
+ * undefined behaviour.
+ *
+ * @note This overload is only available for coroutines without an input
+ * value.
+ */
+ template <typename CompletionToken>
+ requires std::is_void_v<input_type>
+ auto async_resume(CompletionToken&& token) &
+ {
+ return async_initiate<CompletionToken,
+ typename traits::completion_handler>(
+ initiate_async_resume(this), token);
+ }
+
+ /// Resume the coroutine.
+ /**
+ * @param token The completion token of the async resume.
+ *
+ * @attention Calling an invalid coroutine with a noexcept signature is
+ * undefined behaviour.
+ *
+ * @note This overload is only available for coroutines with an input value.
+ */
+ template <typename CompletionToken, detail::convertible_to<input_type> T>
+ auto async_resume(T&& ip, CompletionToken&& token) &
+ {
+ return async_initiate<CompletionToken,
+ typename traits::completion_handler>(
+ initiate_async_resume(this), token, std::forward<T>(ip));
+ }
+
+ /// Operator used for coroutines without input value.
+ auto operator co_await() requires (std::is_void_v<input_type>)
+ {
+ return awaitable_t{*this};
+ }
+
+ /// Operator used for coroutines with input value.
+ /**
+ * @param ip The input value
+ *
+ * @returns An awaitable handle.
+ *
+ * @code
+ * coro<void> push_values(coro<double(int)> c)
+ * {
+ * std::optional<double> res = co_await c(42);
+ * }
+ * @endcode
+ */
+ template <detail::convertible_to<input_type> T>
+ auto operator()(T&& ip)
+ {
+ return detail::coro_with_arg<std::decay_t<T>, coro>{
+ std::forward<T>(ip), *this};
+ }
+
+ /// Check whether the coroutine is open, i.e. can be resumed.
+ bool is_open() const
+ {
+ if (coro_)
+ {
+ auto handle =
+ detail::coroutine_handle<promise_type>::from_promise(*coro_);
+ return handle && !handle.done();
+ }
+ else
+ return false;
+ }
+
+ /// Check whether the coroutine is open, i.e. can be resumed.
+ explicit operator bool() const { return is_open(); }
+
+private:
+ struct awaitable_t;
+
+ struct initiate_async_resume;
+
+ explicit coro(promise_type* const cr) : coro_(cr) {}
+
+ promise_type* coro_{nullptr};
+};
+
+/// A generator is a coro that returns void and yields value.
+template<typename T, typename Executor = asio::any_io_executor,
+ typename Allocator = std::allocator<void>>
+using generator = coro<T, void, Executor, Allocator>;
+
+/// A task is a coro that does not yield values
+template<typename T, typename Executor = asio::any_io_executor,
+ typename Allocator = std::allocator<void>>
+using task = coro<void(), T, Executor, Allocator>;
+
+} // namespace experimental
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#include "asio/experimental/impl/coro.hpp"
+
+#endif // ASIO_EXPERIMENTAL_CORO_HPP