diff options
Diffstat (limited to 'lib/asio/experimental')
-rw-r--r-- | lib/asio/experimental/co_spawn.hpp | 226 | ||||
-rw-r--r-- | lib/asio/experimental/detached.hpp | 65 | ||||
-rw-r--r-- | lib/asio/experimental/impl/co_spawn.hpp | 876 | ||||
-rw-r--r-- | lib/asio/experimental/impl/detached.hpp | 91 | ||||
-rw-r--r-- | lib/asio/experimental/impl/redirect_error.hpp | 294 | ||||
-rw-r--r-- | lib/asio/experimental/redirect_error.hpp | 67 |
6 files changed, 1619 insertions, 0 deletions
diff --git a/lib/asio/experimental/co_spawn.hpp b/lib/asio/experimental/co_spawn.hpp new file mode 100644 index 0000000..cbf5bc5 --- /dev/null +++ b/lib/asio/experimental/co_spawn.hpp @@ -0,0 +1,226 @@ +// +// 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 ASIO_EXPERIMENTAL_CO_SPAWN_HPP +#define ASIO_EXPERIMENTAL_CO_SPAWN_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_CO_AWAIT) || defined(GENERATING_DOCUMENTATION) + +#include <experimental/coroutine> +#include "asio/executor.hpp" +#include "asio/strand.hpp" + +#include "asio/detail/push_options.hpp" + +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 + +#include "asio/detail/pop_options.hpp" + +#include "asio/experimental/impl/co_spawn.hpp" + +#endif // defined(ASIO_HAS_CO_AWAIT) || defined(GENERATING_DOCUMENTATION) + +#endif // ASIO_EXPERIMENTAL_CO_SPAWN_HPP diff --git a/lib/asio/experimental/detached.hpp b/lib/asio/experimental/detached.hpp new file mode 100644 index 0000000..d484f18 --- /dev/null +++ b/lib/asio/experimental/detached.hpp @@ -0,0 +1,65 @@ +// +// experimental/detached.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 ASIO_EXPERIMENTAL_DETACHED_HPP +#define ASIO_EXPERIMENTAL_DETACHED_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include <memory> + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace experimental { + +/// Class used to specify that an asynchronous operation is detached. +/** + + * The detached_t class is used to indicate that an asynchronous operation is + * detached. That is, there is no completion handler waiting for the + * operation's result. A detached_t object may be passed as a handler to an + * asynchronous operation, typically using the special value + * @c asio::experimental::detached. For example: + + * @code my_socket.async_send(my_buffer, asio::experimental::detached); + * @endcode + */ +class detached_t +{ +public: + /// Constructor. + ASIO_CONSTEXPR detached_t() + { + } +}; + +/// A special value, similar to std::nothrow. +/** + * See the documentation for asio::experimental::detached_t for a usage + * example. + */ +#if defined(ASIO_HAS_CONSTEXPR) || defined(GENERATING_DOCUMENTATION) +constexpr detached_t detached; +#elif defined(ASIO_MSVC) +__declspec(selectany) detached_t detached; +#endif + +} // namespace experimental +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#include "asio/experimental/impl/detached.hpp" + +#endif // ASIO_EXPERIMENTAL_DETACHED_HPP diff --git a/lib/asio/experimental/impl/co_spawn.hpp b/lib/asio/experimental/impl/co_spawn.hpp new file mode 100644 index 0000000..8263eff --- /dev/null +++ b/lib/asio/experimental/impl/co_spawn.hpp @@ -0,0 +1,876 @@ +// +// experimental/impl/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 ASIO_EXPERIMENTAL_IMPL_CO_SPAWN_HPP +#define ASIO_EXPERIMENTAL_IMPL_CO_SPAWN_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include <exception> +#include <functional> +#include <memory> +#include <new> +#include <tuple> +#include <utility> +#include "asio/async_result.hpp" +#include "asio/detail/thread_context.hpp" +#include "asio/detail/thread_info_base.hpp" +#include "asio/detail/type_traits.hpp" +#include "asio/dispatch.hpp" +#include "asio/post.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace experimental { +namespace detail { + +// Promise object for coroutine at top of thread-of-execution "stack". +template <typename Executor> +class awaiter +{ +public: + struct deleter + { + void operator()(awaiter* a) + { + if (a) + a->release(); + } + }; + + typedef std::unique_ptr<awaiter, deleter> ptr; + + typedef Executor executor_type; + + ~awaiter() + { + if (has_executor_) + static_cast<Executor*>(static_cast<void*>(executor_))->~Executor(); + } + + void set_executor(const Executor& ex) + { + new (&executor_) Executor(ex); + has_executor_ = true; + } + + executor_type get_executor() const noexcept + { + return *static_cast<const Executor*>(static_cast<const void*>(executor_)); + } + + awaiter* get_return_object() + { + return this; + } + + auto initial_suspend() + { + return std::experimental::suspend_always(); + } + + auto final_suspend() + { + return std::experimental::suspend_always(); + } + + void return_void() + { + } + + awaiter* add_ref() + { + ++ref_count_; + return this; + } + + void release() + { + if (--ref_count_ == 0) + coroutine_handle<awaiter>::from_promise(*this).destroy(); + } + + void unhandled_exception() + { + pending_exception_ = std::current_exception(); + } + + void rethrow_unhandled_exception() + { + if (pending_exception_) + { + std::exception_ptr ex = std::exchange(pending_exception_, nullptr); + std::rethrow_exception(ex); + } + } + +private: + std::size_t ref_count_ = 0; + std::exception_ptr pending_exception_ = nullptr; + alignas(Executor) unsigned char executor_[sizeof(Executor)]; + bool has_executor_ = false; +}; + +// Base promise for coroutines further down the thread-of-execution "stack". +template <typename Executor> +class awaitee_base +{ +public: +#if !defined(ASIO_DISABLE_AWAITEE_RECYCLING) + void* operator new(std::size_t size) + { + return asio::detail::thread_info_base::allocate( + asio::detail::thread_info_base::awaitee_tag(), + asio::detail::thread_context::thread_call_stack::top(), + size); + } + + void operator delete(void* pointer, std::size_t size) + { + asio::detail::thread_info_base::deallocate( + asio::detail::thread_info_base::awaitee_tag(), + asio::detail::thread_context::thread_call_stack::top(), + pointer, size); + } +#endif // !defined(ASIO_DISABLE_AWAITEE_RECYCLING) + + auto initial_suspend() + { + return std::experimental::suspend_never(); + } + + struct final_suspender + { + awaitee_base* this_; + + bool await_ready() const noexcept + { + return false; + } + + void await_suspend(coroutine_handle<void>) + { + this_->wake_caller(); + } + + void await_resume() const noexcept + { + } + }; + + auto final_suspend() + { + return final_suspender{this}; + } + + void set_except(std::exception_ptr e) + { + pending_exception_ = e; + } + + void unhandled_exception() + { + set_except(std::current_exception()); + } + + void rethrow_exception() + { + if (pending_exception_) + { + std::exception_ptr ex = std::exchange(pending_exception_, nullptr); + std::rethrow_exception(ex); + } + } + + awaiter<Executor>* top() + { + return awaiter_; + } + + coroutine_handle<void> caller() + { + return caller_; + } + + bool ready() const + { + return ready_; + } + + void wake_caller() + { + if (caller_) + caller_.resume(); + else + ready_ = true; + } + + class awaitable_executor + { + public: + explicit awaitable_executor(awaitee_base* a) + : this_(a) + { + } + + bool await_ready() const noexcept + { + return this_->awaiter_ != nullptr; + } + + template <typename U, typename Ex> + void await_suspend(coroutine_handle<detail::awaitee<U, Ex>> h) noexcept + { + this_->resume_on_attach_ = h; + } + + Executor await_resume() + { + return this_->awaiter_->get_executor(); + } + + private: + awaitee_base* this_; + }; + + awaitable_executor await_transform(this_coro::executor_t) noexcept + { + return awaitable_executor(this); + } + + class awaitable_token + { + public: + explicit awaitable_token(awaitee_base* a) + : this_(a) + { + } + + bool await_ready() const noexcept + { + return this_->awaiter_ != nullptr; + } + + template <typename U, typename Ex> + void await_suspend(coroutine_handle<detail::awaitee<U, Ex>> h) noexcept + { + this_->resume_on_attach_ = h; + } + + await_token<Executor> await_resume() + { + return await_token<Executor>(this_->awaiter_); + } + + private: + awaitee_base* this_; + }; + + awaitable_token await_transform(this_coro::token_t) noexcept + { + return awaitable_token(this); + } + + template <typename T> + awaitable<T, Executor> await_transform(awaitable<T, Executor>& t) const + { + return std::move(t); + } + + template <typename T> + awaitable<T, Executor> await_transform(awaitable<T, Executor>&& t) const + { + return std::move(t); + } + + std::experimental::suspend_always await_transform( + std::experimental::suspend_always) const + { + return std::experimental::suspend_always(); + } + + void attach_caller(coroutine_handle<awaiter<Executor>> h) + { + this->caller_ = h; + this->attach_callees(&h.promise()); + } + + template <typename U> + void attach_caller(coroutine_handle<awaitee<U, Executor>> h) + { + this->caller_ = h; + if (h.promise().awaiter_) + this->attach_callees(h.promise().awaiter_); + else + h.promise().unattached_callee_ = this; + } + + void attach_callees(awaiter<Executor>* a) + { + for (awaitee_base* curr = this; curr != nullptr; + curr = std::exchange(curr->unattached_callee_, nullptr)) + { + curr->awaiter_ = a; + if (curr->resume_on_attach_) + return std::exchange(curr->resume_on_attach_, nullptr).resume(); + } + } + +protected: + awaiter<Executor>* awaiter_ = nullptr; + coroutine_handle<void> caller_ = nullptr; + awaitee_base<Executor>* unattached_callee_ = nullptr; + std::exception_ptr pending_exception_ = nullptr; + coroutine_handle<void> resume_on_attach_ = nullptr; + bool ready_ = false; +}; + +// Promise object for coroutines further down the thread-of-execution "stack". +template <typename T, typename Executor> +class awaitee + : public awaitee_base<Executor> +{ +public: + awaitee() + { + } + + awaitee(awaitee&& other) noexcept + : awaitee_base<Executor>(std::move(other)) + { + } + + ~awaitee() + { + if (has_result_) + static_cast<T*>(static_cast<void*>(result_))->~T(); + } + + awaitable<T, Executor> get_return_object() + { + return awaitable<T, Executor>(this); + }; + + template <typename U> + void return_value(U&& u) + { + new (&result_) T(std::forward<U>(u)); + has_result_ = true; + } + + T get() + { + this->caller_ = nullptr; + this->rethrow_exception(); + return std::move(*static_cast<T*>(static_cast<void*>(result_))); + } + +private: + alignas(T) unsigned char result_[sizeof(T)]; + bool has_result_ = false; +}; + +// Promise object for coroutines further down the thread-of-execution "stack". +template <typename Executor> +class awaitee<void, Executor> + : public awaitee_base<Executor> +{ +public: + awaitable<void, Executor> get_return_object() + { + return awaitable<void, Executor>(this); + }; + + void return_void() + { + } + + void get() + { + this->caller_ = nullptr; + this->rethrow_exception(); + } +}; + +template <typename Executor> +class awaiter_task +{ +public: + typedef Executor executor_type; + + awaiter_task(awaiter<Executor>* a) + : awaiter_(a->add_ref()) + { + } + + awaiter_task(awaiter_task&& other) noexcept + : awaiter_(std::exchange(other.awaiter_, nullptr)) + { + } + + ~awaiter_task() + { + if (awaiter_) + { + // Coroutine "stack unwinding" must be performed through the executor. + executor_type ex(awaiter_->get_executor()); + (post)(ex, + [a = std::move(awaiter_)]() mutable + { + typename awaiter<Executor>::ptr(std::move(a)); + }); + } + } + + executor_type get_executor() const noexcept + { + return awaiter_->get_executor(); + } + +protected: + typename awaiter<Executor>::ptr awaiter_; +}; + +template <typename Executor> +class co_spawn_handler : public awaiter_task<Executor> +{ +public: + using awaiter_task<Executor>::awaiter_task; + + void operator()() + { + typename awaiter<Executor>::ptr ptr(std::move(this->awaiter_)); + coroutine_handle<awaiter<Executor>>::from_promise(*ptr.get()).resume(); + } +}; + +template <typename Executor, typename T> +class await_handler_base : public awaiter_task<Executor> +{ +public: + typedef awaitable<T, Executor> awaitable_type; + + await_handler_base(await_token<Executor> token) + : awaiter_task<Executor>(token.awaiter_), + awaitee_(nullptr) + { + } + + await_handler_base(await_handler_base&& other) noexcept + : awaiter_task<Executor>(std::move(other)), + awaitee_(std::exchange(other.awaitee_, nullptr)) + { + } + + void attach_awaitee(const awaitable<T, Executor>& a) + { + awaitee_ = a.awaitee_; + } + +protected: + awaitee<T, Executor>* awaitee_; +}; + +template <typename, typename...> class await_handler; + +template <typename Executor> +class await_handler<Executor, void> + : public await_handler_base<Executor, void> +{ +public: + using await_handler_base<Executor, void>::await_handler_base; + + void operator()() + { + typename awaiter<Executor>::ptr ptr(std::move(this->awaiter_)); + this->awaitee_->return_void(); + this->awaitee_->wake_caller(); + ptr->rethrow_unhandled_exception(); + } +}; + +template <typename Executor> +class await_handler<Executor, asio::error_code> + : public await_handler_base<Executor, void> +{ +public: + typedef void return_type; + + using await_handler_base<Executor, void>::await_handler_base; + + void operator()(const asio::error_code& ec) + { + typename awaiter<Executor>::ptr ptr(std::move(this->awaiter_)); + if (ec) + { + this->awaitee_->set_except( + std::make_exception_ptr(asio::system_error(ec))); + } + else + this->awaitee_->return_void(); + this->awaitee_->wake_caller(); + ptr->rethrow_unhandled_exception(); + } +}; + +template <typename Executor> +class await_handler<Executor, std::exception_ptr> + : public await_handler_base<Executor, void> +{ +public: + using await_handler_base<Executor, void>::await_handler_base; + + void operator()(std::exception_ptr ex) + { + typename awaiter<Executor>::ptr ptr(std::move(this->awaiter_)); + if (ex) + this->awaitee_->set_except(ex); + else + this->awaitee_->return_void(); + this->awaitee_->wake_caller(); + ptr->rethrow_unhandled_exception(); + } +}; + +template <typename Executor, typename T> +class await_handler<Executor, T> + : public await_handler_base<Executor, T> +{ +public: + using await_handler_base<Executor, T>::await_handler_base; + + template <typename Arg> + void operator()(Arg&& arg) + { + typename awaiter<Executor>::ptr ptr(std::move(this->awaiter_)); + this->awaitee_->return_value(std::forward<Arg>(arg)); + this->awaitee_->wake_caller(); + ptr->rethrow_unhandled_exception(); + } +}; + +template <typename Executor, typename T> +class await_handler<Executor, asio::error_code, T> + : public await_handler_base<Executor, T> +{ +public: + using await_handler_base<Executor, T>::await_handler_base; + + template <typename Arg> + void operator()(const asio::error_code& ec, Arg&& arg) + { + typename awaiter<Executor>::ptr ptr(std::move(this->awaiter_)); + if (ec) + { + this->awaitee_->set_except( + std::make_exception_ptr(asio::system_error(ec))); + } + else + this->awaitee_->return_value(std::forward<Arg>(arg)); + this->awaitee_->wake_caller(); + ptr->rethrow_unhandled_exception(); + } +}; + +template <typename Executor, typename T> +class await_handler<Executor, std::exception_ptr, T> + : public await_handler_base<Executor, T> +{ +public: + using await_handler_base<Executor, T>::await_handler_base; + + template <typename Arg> + void operator()(std::exception_ptr ex, Arg&& arg) + { + typename awaiter<Executor>::ptr ptr(std::move(this->awaiter_)); + if (ex) + this->awaitee_->set_except(ex); + else + this->awaitee_->return_value(std::forward<Arg>(arg)); + this->awaitee_->wake_caller(); + ptr->rethrow_unhandled_exception(); + } +}; + +template <typename Executor, typename... Ts> +class await_handler + : public await_handler_base<Executor, std::tuple<Ts...>> +{ +public: + using await_handler_base<Executor, std::tuple<Ts...>>::await_handler_base; + + template <typename... Args> + void operator()(Args&&... args) + { + typename awaiter<Executor>::ptr ptr(std::move(this->awaiter_)); + this->awaitee_->return_value( + std::forward_as_tuple(std::forward<Args>(args)...)); + this->awaitee_->wake_caller(); + ptr->rethrow_unhandled_exception(); + } +}; + +template <typename Executor, typename... Ts> +class await_handler<Executor, asio::error_code, Ts...> + : public await_handler_base<Executor, std::tuple<Ts...>> +{ +public: + using await_handler_base<Executor, std::tuple<Ts...>>::await_handler_base; + + template <typename... Args> + void operator()(const asio::error_code& ec, Args&&... args) + { + typename awaiter<Executor>::ptr ptr(std::move(this->awaiter_)); + if (ec) + { + this->awaitee_->set_except( + std::make_exception_ptr(asio::system_error(ec))); + } + else + { + this->awaitee_->return_value( + std::forward_as_tuple(std::forward<Args>(args)...)); + } + this->awaitee_->wake_caller(); + ptr->rethrow_unhandled_exception(); + } +}; + +template <typename Executor, typename... Ts> +class await_handler<Executor, std::exception_ptr, Ts...> + : public await_handler_base<Executor, std::tuple<Ts...>> +{ +public: + using await_handler_base<Executor, std::tuple<Ts...>>::await_handler_base; + + template <typename... Args> + void operator()(std::exception_ptr ex, Args&&... args) + { + typename awaiter<Executor>::ptr ptr(std::move(this->awaiter_)); + if (ex) + this->awaitee_->set_except(ex); + else + { + this->awaitee_->return_value( + std::forward_as_tuple(std::forward<Args>(args)...)); + } + this->awaitee_->wake_caller(); + ptr->rethrow_unhandled_exception(); + } +}; + +template <typename T> +struct awaitable_signature; + +template <typename T, typename Executor> +struct awaitable_signature<awaitable<T, Executor>> +{ + typedef void type(std::exception_ptr, T); +}; + +template <typename Executor> +struct awaitable_signature<awaitable<void, Executor>> +{ + typedef void type(std::exception_ptr); +}; + +template <typename T, typename Executor, typename F, typename Handler> +awaiter<Executor>* co_spawn_entry_point(awaitable<T, Executor>*, + executor_work_guard<Executor> work_guard, F f, Handler handler) +{ + bool done = false; + + try + { + T t = co_await f(); + + done = true; + + (dispatch)(work_guard.get_executor(), + [handler = std::move(handler), t = std::move(t)]() mutable + { + handler(std::exception_ptr(), std::move(t)); + }); + } + catch (...) + { + if (done) + throw; + + (dispatch)(work_guard.get_executor(), + [handler = std::move(handler), e = std::current_exception()]() mutable + { + handler(e, T()); + }); + } +} + +template <typename Executor, typename F, typename Handler> +awaiter<Executor>* co_spawn_entry_point(awaitable<void, Executor>*, + executor_work_guard<Executor> work_guard, F f, Handler handler) +{ + std::exception_ptr e = nullptr; + + try + { + co_await f(); + } + catch (...) + { + e = std::current_exception(); + } + + (dispatch)(work_guard.get_executor(), + [handler = std::move(handler), e]() mutable + { + handler(e); + }); +} + +template <typename Executor, typename F, typename CompletionToken> +auto co_spawn(const Executor& ex, F&& f, CompletionToken&& token) +{ + typedef typename result_of<F()>::type awaitable_type; + typedef typename awaitable_type::executor_type executor_type; + typedef typename awaitable_signature<awaitable_type>::type signature_type; + + async_completion<CompletionToken, signature_type> completion(token); + + executor_type ex2(ex); + auto work_guard = make_work_guard(completion.completion_handler, ex2); + + auto* a = (co_spawn_entry_point)( + static_cast<awaitable_type*>(nullptr), std::move(work_guard), + std::forward<F>(f), std::move(completion.completion_handler)); + + a->set_executor(ex2); + (post)(co_spawn_handler<executor_type>(a)); + + return completion.result.get(); +} + +#if defined(_MSC_VER) +# pragma warning(push) +# pragma warning(disable:4033) +#endif // defined(_MSC_VER) + +#if defined(_MSC_VER) +template <typename T> T dummy_return() +{ + return std::move(*static_cast<T*>(nullptr)); +} + +template <> +inline void dummy_return() +{ +} +#endif // defined(_MSC_VER) + +template <typename Awaitable> +inline Awaitable make_dummy_awaitable() +{ + for (;;) co_await std::experimental::suspend_always(); +#if defined(_MSC_VER) + co_return dummy_return<typename Awaitable::value_type>(); +#endif // defined(_MSC_VER) +} + +#if defined(_MSC_VER) +# pragma warning(pop) +#endif // defined(_MSC_VER) + +} // namespace detail +} // namespace experimental + +template <typename Executor, typename R, typename... Args> +class async_result<experimental::await_token<Executor>, R(Args...)> +{ +public: + typedef experimental::detail::await_handler< + Executor, typename decay<Args>::type...> completion_handler_type; + + typedef typename experimental::detail::await_handler< + Executor, Args...>::awaitable_type return_type; + + async_result(completion_handler_type& h) + : awaitable_(experimental::detail::make_dummy_awaitable<return_type>()) + { + h.attach_awaitee(awaitable_); + } + + return_type get() + { + return std::move(awaitable_); + } + +private: + return_type awaitable_; +}; + +#if !defined(ASIO_NO_DEPRECATED) + +template <typename Executor, typename R, typename... Args> +struct handler_type<experimental::await_token<Executor>, R(Args...)> +{ + typedef experimental::detail::await_handler< + Executor, typename decay<Args>::type...> type; +}; + +template <typename Executor, typename... Args> +class async_result<experimental::detail::await_handler<Executor, Args...>> +{ +public: + typedef typename experimental::detail::await_handler< + Executor, Args...>::awaitable_type type; + + async_result(experimental::detail::await_handler<Executor, Args...>& h) + : awaitable_(experimental::detail::make_dummy_awaitable<type>()) + { + h.attach_awaitee(awaitable_); + } + + type get() + { + return std::move(awaitable_); + } + +private: + type awaitable_; +}; + +#endif // !defined(ASIO_NO_DEPRECATED) + +} // namespace asio + +namespace std { namespace experimental { + +template <typename Executor, typename... Args> +struct coroutine_traits< + asio::experimental::detail::awaiter<Executor>*, Args...> +{ + typedef asio::experimental::detail::awaiter<Executor> promise_type; +}; + +template <typename T, typename Executor, typename... Args> +struct coroutine_traits< + asio::experimental::awaitable<T, Executor>, Args...> +{ + typedef asio::experimental::detail::awaitee<T, Executor> promise_type; +}; + +}} // namespace std::experimental + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_EXPERIMENTAL_IMPL_CO_SPAWN_HPP diff --git a/lib/asio/experimental/impl/detached.hpp b/lib/asio/experimental/impl/detached.hpp new file mode 100644 index 0000000..6ce8887 --- /dev/null +++ b/lib/asio/experimental/impl/detached.hpp @@ -0,0 +1,91 @@ +// +// experimental/impl/detached.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 ASIO_EXPERIMENTAL_IMPL_DETACHED_HPP +#define ASIO_EXPERIMENTAL_IMPL_DETACHED_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/async_result.hpp" +#include "asio/detail/variadic_templates.hpp" +#include "asio/handler_type.hpp" +#include "asio/system_error.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace experimental { +namespace detail { + + // Class to adapt a detached_t as a completion handler. + class detached_handler + { + public: + detached_handler(detached_t) + { + } + +#if defined(ASIO_HAS_VARIADIC_TEMPLATES) + + template <typename... Args> + void operator()(Args...) + { + } + +#else // defined(ASIO_HAS_VARIADIC_TEMPLATES) + + void operator()() + { + } + +#define ASIO_PRIVATE_DETACHED_DEF(n) \ + template <ASIO_VARIADIC_TPARAMS(n)> \ + void operator()(ASIO_VARIADIC_BYVAL_PARAMS(n)) \ + { \ + } \ + /**/ + ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_DETACHED_DEF) +#undef ASIO_PRIVATE_DETACHED_DEF + +#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES) + }; + +} // namespace detail +} // namespace experimental + +#if !defined(GENERATING_DOCUMENTATION) + +template <typename Signature> +struct async_result<experimental::detached_t, Signature> +{ + typedef asio::experimental::detail::detached_handler + completion_handler_type; + + typedef void return_type; + + explicit async_result(completion_handler_type&) + { + } + + void get() + { + } +}; + +#endif // !defined(GENERATING_DOCUMENTATION) + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_EXPERIMENTAL_IMPL_DETACHED_HPP diff --git a/lib/asio/experimental/impl/redirect_error.hpp b/lib/asio/experimental/impl/redirect_error.hpp new file mode 100644 index 0000000..d3b97fa --- /dev/null +++ b/lib/asio/experimental/impl/redirect_error.hpp @@ -0,0 +1,294 @@ +// +// experimental/impl/redirect_error.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 ASIO_EXPERIMENTAL_IMPL_REDIRECT_ERROR_HPP +#define ASIO_EXPERIMENTAL_IMPL_REDIRECT_ERROR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/associated_executor.hpp" +#include "asio/associated_allocator.hpp" +#include "asio/async_result.hpp" +#include "asio/detail/handler_alloc_helpers.hpp" +#include "asio/detail/handler_cont_helpers.hpp" +#include "asio/detail/handler_invoke_helpers.hpp" +#include "asio/detail/type_traits.hpp" +#include "asio/detail/variadic_templates.hpp" +#include "asio/handler_type.hpp" +#include "asio/system_error.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace experimental { +namespace detail { + +// Class to adapt a redirect_error_t as a completion handler. +template <typename Handler> +class redirect_error_handler +{ +public: + template <typename CompletionToken> + redirect_error_handler(redirect_error_t<CompletionToken> e) + : ec_(e.ec_), + handler_(ASIO_MOVE_CAST(CompletionToken)(e.token_)) + { + } + + void operator()() + { + handler_(); + } + +#if defined(ASIO_HAS_VARIADIC_TEMPLATES) + + template <typename Arg, typename... Args> + typename enable_if< + !is_same<typename decay<Arg>::type, asio::error_code>::value + >::type + operator()(ASIO_MOVE_ARG(Arg) arg, ASIO_MOVE_ARG(Args)... args) + { + handler_(ASIO_MOVE_CAST(Arg)(arg), + ASIO_MOVE_CAST(Args)(args)...); + } + + template <typename... Args> + void operator()(const asio::error_code& ec, + ASIO_MOVE_ARG(Args)... args) + { + ec_ = ec; + handler_(ASIO_MOVE_CAST(Args)(args)...); + } + +#else // defined(ASIO_HAS_VARIADIC_TEMPLATES) + + template <typename Arg> + typename enable_if< + !is_same<typename decay<Arg>::type, asio::error_code>::value + >::type + operator()(ASIO_MOVE_ARG(Arg) arg) + { + handler_(ASIO_MOVE_CAST(Arg)(arg)); + } + + void operator()(const asio::error_code& ec) + { + ec_ = ec; + handler_(); + } + +#define ASIO_PRIVATE_REDIRECT_ERROR_DEF(n) \ + template <typename Arg, ASIO_VARIADIC_TPARAMS(n)> \ + typename enable_if< \ + !is_same<typename decay<Arg>::type, asio::error_code>::value \ + >::type \ + operator()(ASIO_MOVE_ARG(Arg) arg, ASIO_VARIADIC_MOVE_PARAMS(n)) \ + { \ + handler_(ASIO_MOVE_CAST(Arg)(arg), \ + ASIO_VARIADIC_MOVE_ARGS(n)); \ + } \ + \ + template <ASIO_VARIADIC_TPARAMS(n)> \ + void operator()(const asio::error_code& ec, \ + ASIO_VARIADIC_MOVE_PARAMS(n)) \ + { \ + ec_ = ec; \ + handler_(ASIO_VARIADIC_MOVE_ARGS(n)); \ + } \ + /**/ + ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_REDIRECT_ERROR_DEF) +#undef ASIO_PRIVATE_REDIRECT_ERROR_DEF + +#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES) + +//private: + asio::error_code& ec_; + Handler handler_; +}; + +template <typename Handler> +inline void* asio_handler_allocate(std::size_t size, + redirect_error_handler<Handler>* this_handler) +{ + return asio_handler_alloc_helpers::allocate( + size, this_handler->handler_); +} + +template <typename Handler> +inline void asio_handler_deallocate(void* pointer, std::size_t size, + redirect_error_handler<Handler>* this_handler) +{ + asio_handler_alloc_helpers::deallocate( + pointer, size, this_handler->handler_); +} + +template <typename Handler> +inline bool asio_handler_is_continuation( + redirect_error_handler<Handler>* this_handler) +{ + return asio_handler_cont_helpers::is_continuation( + this_handler->handler_); +} + +template <typename Function, typename Handler> +inline void asio_handler_invoke(Function& function, + redirect_error_handler<Handler>* this_handler) +{ + asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); +} + +template <typename Function, typename Handler> +inline void asio_handler_invoke(const Function& function, + redirect_error_handler<Handler>* this_handler) +{ + asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); +} + +template <typename Signature> +struct redirect_error_signature +{ + typedef Signature type; +}; + +#if defined(ASIO_HAS_VARIADIC_TEMPLATES) + +template <typename R, typename... Args> +struct redirect_error_signature<R(asio::error_code, Args...)> +{ + typedef R type(Args...); +}; + +template <typename R, typename... Args> +struct redirect_error_signature<R(const asio::error_code&, Args...)> +{ + typedef R type(Args...); +}; + +#else // defined(ASIO_HAS_VARIADIC_TEMPLATES) + +template <typename R> +struct redirect_error_signature<R(asio::error_code)> +{ + typedef R type(); +}; + +template <typename R> +struct redirect_error_signature<R(const asio::error_code&)> +{ + typedef R type(); +}; + +#define ASIO_PRIVATE_REDIRECT_ERROR_DEF(n) \ + template <typename R, ASIO_VARIADIC_TPARAMS(n)> \ + struct redirect_error_signature< \ + R(asio::error_code, ASIO_VARIADIC_TARGS(n))> \ + { \ + typedef R type(ASIO_VARIADIC_TARGS(n)); \ + }; \ + \ + template <typename R, ASIO_VARIADIC_TPARAMS(n)> \ + struct redirect_error_signature< \ + R(const asio::error_code&, ASIO_VARIADIC_TARGS(n))> \ + { \ + typedef R type(ASIO_VARIADIC_TARGS(n)); \ + }; \ + /**/ + ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_REDIRECT_ERROR_DEF) +#undef ASIO_PRIVATE_REDIRECT_ERROR_DEF + +#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES) + +} // namespace detail +} // namespace experimental + +#if !defined(GENERATING_DOCUMENTATION) + +template <typename CompletionToken, typename Signature> +struct async_result<experimental::redirect_error_t<CompletionToken>, Signature> + : async_result<CompletionToken, + typename experimental::detail::redirect_error_signature<Signature>::type> +{ + typedef experimental::detail::redirect_error_handler< + typename async_result<CompletionToken, + typename experimental::detail::redirect_error_signature<Signature>::type> + ::completion_handler_type> completion_handler_type; + + explicit async_result(completion_handler_type& h) + : async_result<CompletionToken, + typename experimental::detail::redirect_error_signature< + Signature>::type>(h.handler_) + { + } +}; + +#if !defined(ASIO_NO_DEPRECATED) + +template <typename CompletionToken, typename Signature> +struct handler_type<experimental::redirect_error_t<CompletionToken>, Signature> +{ + typedef experimental::detail::redirect_error_handler< + typename async_result<CompletionToken, + typename experimental::detail::redirect_error_signature<Signature>::type> + ::completion_handler_type> type; +}; + +template <typename Handler> +struct async_result<experimental::detail::redirect_error_handler<Handler> > + : async_result<Handler> +{ + explicit async_result( + experimental::detail::redirect_error_handler<Handler>& h) + : async_result<Handler>(h.handler_) + { + } +}; + +#endif // !defined(ASIO_NO_DEPRECATED) + +template <typename Handler, typename Executor> +struct associated_executor< + experimental::detail::redirect_error_handler<Handler>, Executor> +{ + typedef typename associated_executor<Handler, Executor>::type type; + + static type get( + const experimental::detail::redirect_error_handler<Handler>& h, + const Executor& ex = Executor()) ASIO_NOEXCEPT + { + return associated_executor<Handler, Executor>::get(h.handler_, ex); + } +}; + +template <typename Handler, typename Allocator> +struct associated_allocator< + experimental::detail::redirect_error_handler<Handler>, Allocator> +{ + typedef typename associated_allocator<Handler, Allocator>::type type; + + static type get( + const experimental::detail::redirect_error_handler<Handler>& h, + const Allocator& a = Allocator()) ASIO_NOEXCEPT + { + return associated_allocator<Handler, Allocator>::get(h.handler_, a); + } +}; + +#endif // !defined(GENERATING_DOCUMENTATION) + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_EXPERIMENTAL_IMPL_REDIRECT_ERROR_HPP diff --git a/lib/asio/experimental/redirect_error.hpp b/lib/asio/experimental/redirect_error.hpp new file mode 100644 index 0000000..30e81cf --- /dev/null +++ b/lib/asio/experimental/redirect_error.hpp @@ -0,0 +1,67 @@ +// +// experimental/redirect_error.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 ASIO_EXPERIMENTAL_REDIRECT_ERROR_HPP +#define ASIO_EXPERIMENTAL_REDIRECT_ERROR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/type_traits.hpp" +#include "asio/error_code.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace experimental { + +/// Completion token type used to specify that an error produced by an +/// asynchronous operation is captured to an error_code variable. +/** + * The redirect_error_t class is used to indicate that any error_code produced + * by an asynchronous operation is captured to a specified variable. + */ +template <typename CompletionToken> +class redirect_error_t +{ +public: + /// Constructor. + template <typename T> + redirect_error_t(ASIO_MOVE_ARG(T) completion_token, + asio::error_code& ec) + : token_(ASIO_MOVE_CAST(T)(completion_token)), + ec_(ec) + { + } + +//private: + CompletionToken token_; + asio::error_code& ec_; +}; + +/// Create a completion token to capture error_code values to a variable. +template <typename CompletionToken> +inline redirect_error_t<typename decay<CompletionToken>::type> redirect_error( + CompletionToken&& completion_token, asio::error_code& ec) +{ + return redirect_error_t<typename decay<CompletionToken>::type>( + ASIO_MOVE_CAST(CompletionToken)(completion_token), ec); +} + +} // namespace experimental +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#include "asio/experimental/impl/redirect_error.hpp" + +#endif // ASIO_EXPERIMENTAL_REDIRECT_ERROR_HPP |