From e95946831f8ef53d29590735a2df661385edb008 Mon Sep 17 00:00:00 2001 From: "Matthias P. Braendli" Date: Mon, 6 Aug 2018 10:35:22 +0200 Subject: Replace boost by the standalone asio library --- lib/asio/impl/spawn.hpp | 535 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 535 insertions(+) create mode 100644 lib/asio/impl/spawn.hpp (limited to 'lib/asio/impl/spawn.hpp') diff --git a/lib/asio/impl/spawn.hpp b/lib/asio/impl/spawn.hpp new file mode 100644 index 0000000..5594ad9 --- /dev/null +++ b/lib/asio/impl/spawn.hpp @@ -0,0 +1,535 @@ +// +// impl/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_IMPL_SPAWN_HPP +#define ASIO_IMPL_SPAWN_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_allocator.hpp" +#include "asio/associated_executor.hpp" +#include "asio/async_result.hpp" +#include "asio/bind_executor.hpp" +#include "asio/detail/atomic_count.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/memory.hpp" +#include "asio/detail/noncopyable.hpp" +#include "asio/detail/type_traits.hpp" +#include "asio/system_error.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + + template + class coro_handler + { + public: + coro_handler(basic_yield_context ctx) + : coro_(ctx.coro_.lock()), + ca_(ctx.ca_), + handler_(ctx.handler_), + ready_(0), + ec_(ctx.ec_), + value_(0) + { + } + + void operator()(T value) + { + *ec_ = asio::error_code(); + *value_ = ASIO_MOVE_CAST(T)(value); + if (--*ready_ == 0) + (*coro_)(); + } + + void operator()(asio::error_code ec, T value) + { + *ec_ = ec; + *value_ = ASIO_MOVE_CAST(T)(value); + if (--*ready_ == 0) + (*coro_)(); + } + + //private: + shared_ptr::callee_type> coro_; + typename basic_yield_context::caller_type& ca_; + Handler handler_; + atomic_count* ready_; + asio::error_code* ec_; + T* value_; + }; + + template + class coro_handler + { + public: + coro_handler(basic_yield_context ctx) + : coro_(ctx.coro_.lock()), + ca_(ctx.ca_), + handler_(ctx.handler_), + ready_(0), + ec_(ctx.ec_) + { + } + + void operator()() + { + *ec_ = asio::error_code(); + if (--*ready_ == 0) + (*coro_)(); + } + + void operator()(asio::error_code ec) + { + *ec_ = ec; + if (--*ready_ == 0) + (*coro_)(); + } + + //private: + shared_ptr::callee_type> coro_; + typename basic_yield_context::caller_type& ca_; + Handler handler_; + atomic_count* ready_; + asio::error_code* ec_; + }; + + template + inline void* asio_handler_allocate(std::size_t size, + coro_handler* this_handler) + { + return asio_handler_alloc_helpers::allocate( + size, this_handler->handler_); + } + + template + inline void asio_handler_deallocate(void* pointer, std::size_t size, + coro_handler* this_handler) + { + asio_handler_alloc_helpers::deallocate( + pointer, size, this_handler->handler_); + } + + template + inline bool asio_handler_is_continuation(coro_handler*) + { + return true; + } + + template + inline void asio_handler_invoke(Function& function, + coro_handler* this_handler) + { + asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); + } + + template + inline void asio_handler_invoke(const Function& function, + coro_handler* this_handler) + { + asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); + } + + template + class coro_async_result + { + public: + typedef coro_handler completion_handler_type; + typedef T return_type; + + explicit coro_async_result(completion_handler_type& h) + : handler_(h), + ca_(h.ca_), + ready_(2) + { + h.ready_ = &ready_; + out_ec_ = h.ec_; + if (!out_ec_) h.ec_ = &ec_; + h.value_ = &value_; + } + + return_type get() + { + // Must not hold shared_ptr to coro while suspended. + handler_.coro_.reset(); + + if (--ready_ != 0) + ca_(); + if (!out_ec_ && ec_) throw asio::system_error(ec_); + return ASIO_MOVE_CAST(return_type)(value_); + } + + private: + completion_handler_type& handler_; + typename basic_yield_context::caller_type& ca_; + atomic_count ready_; + asio::error_code* out_ec_; + asio::error_code ec_; + return_type value_; + }; + + template + class coro_async_result + { + public: + typedef coro_handler completion_handler_type; + typedef void return_type; + + explicit coro_async_result(completion_handler_type& h) + : handler_(h), + ca_(h.ca_), + ready_(2) + { + h.ready_ = &ready_; + out_ec_ = h.ec_; + if (!out_ec_) h.ec_ = &ec_; + } + + void get() + { + // Must not hold shared_ptr to coro while suspended. + handler_.coro_.reset(); + + if (--ready_ != 0) + ca_(); + if (!out_ec_ && ec_) throw asio::system_error(ec_); + } + + private: + completion_handler_type& handler_; + typename basic_yield_context::caller_type& ca_; + atomic_count ready_; + asio::error_code* out_ec_; + asio::error_code ec_; + }; + +} // namespace detail + +#if !defined(GENERATING_DOCUMENTATION) + +template +class async_result, ReturnType()> + : public detail::coro_async_result +{ +public: + explicit async_result( + typename detail::coro_async_result::completion_handler_type& h) + : detail::coro_async_result(h) + { + } +}; + +template +class async_result, ReturnType(Arg1)> + : public detail::coro_async_result::type> +{ +public: + explicit async_result( + typename detail::coro_async_result::type>::completion_handler_type& h) + : detail::coro_async_result::type>(h) + { + } +}; + +template +class async_result, + ReturnType(asio::error_code)> + : public detail::coro_async_result +{ +public: + explicit async_result( + typename detail::coro_async_result::completion_handler_type& h) + : detail::coro_async_result(h) + { + } +}; + +template +class async_result, + ReturnType(asio::error_code, Arg2)> + : public detail::coro_async_result::type> +{ +public: + explicit async_result( + typename detail::coro_async_result::type>::completion_handler_type& h) + : detail::coro_async_result::type>(h) + { + } +}; + +#if !defined(ASIO_NO_DEPRECATED) + +template +struct handler_type, ReturnType()> +{ + typedef detail::coro_handler type; +}; + +template +struct handler_type, ReturnType(Arg1)> +{ + typedef detail::coro_handler::type> type; +}; + +template +struct handler_type, + ReturnType(asio::error_code)> +{ + typedef detail::coro_handler type; +}; + +template +struct handler_type, + ReturnType(asio::error_code, Arg2)> +{ + typedef detail::coro_handler::type> type; +}; + +template +class async_result > + : public detail::coro_async_result +{ +public: + typedef typename detail::coro_async_result::return_type type; + + explicit async_result( + typename detail::coro_async_result::completion_handler_type& h) + : detail::coro_async_result(h) + { + } +}; + +#endif // !defined(ASIO_NO_DEPRECATED) + +template +struct associated_allocator, Allocator> +{ + typedef typename associated_allocator::type type; + + static type get(const detail::coro_handler& h, + const Allocator& a = Allocator()) ASIO_NOEXCEPT + { + return associated_allocator::get(h.handler_, a); + } +}; + +template +struct associated_executor, Executor> +{ + typedef typename associated_executor::type type; + + static type get(const detail::coro_handler& h, + const Executor& ex = Executor()) ASIO_NOEXCEPT + { + return associated_executor::get(h.handler_, ex); + } +}; + +namespace detail { + + template + struct spawn_data : private noncopyable + { + template + spawn_data(ASIO_MOVE_ARG(Hand) handler, + bool call_handler, ASIO_MOVE_ARG(Func) function) + : handler_(ASIO_MOVE_CAST(Hand)(handler)), + call_handler_(call_handler), + function_(ASIO_MOVE_CAST(Func)(function)) + { + } + + weak_ptr::callee_type> coro_; + Handler handler_; + bool call_handler_; + Function function_; + }; + + template + struct coro_entry_point + { + void operator()(typename basic_yield_context::caller_type& ca) + { + shared_ptr > data(data_); +#if !defined(BOOST_COROUTINES_UNIDIRECT) && !defined(BOOST_COROUTINES_V2) + ca(); // Yield until coroutine pointer has been initialised. +#endif // !defined(BOOST_COROUTINES_UNIDIRECT) && !defined(BOOST_COROUTINES_V2) + const basic_yield_context yield( + data->coro_, ca, data->handler_); + + (data->function_)(yield); + if (data->call_handler_) + (data->handler_)(); + } + + shared_ptr > data_; + }; + + template + struct spawn_helper + { + void operator()() + { + typedef typename basic_yield_context::callee_type callee_type; + coro_entry_point entry_point = { data_ }; + shared_ptr coro(new callee_type(entry_point, attributes_)); + data_->coro_ = coro; + (*coro)(); + } + + shared_ptr > data_; + boost::coroutines::attributes attributes_; + }; + + template + inline void asio_handler_invoke(Function& function, + spawn_helper* this_handler) + { + asio_handler_invoke_helpers::invoke( + function, this_handler->data_->handler_); + } + + template + inline void asio_handler_invoke(const Function& function, + spawn_helper* this_handler) + { + asio_handler_invoke_helpers::invoke( + function, this_handler->data_->handler_); + } + + inline void default_spawn_handler() {} + +} // namespace detail + +template +inline void spawn(ASIO_MOVE_ARG(Function) function, + const boost::coroutines::attributes& attributes) +{ + typedef typename decay::type function_type; + + typename associated_executor::type ex( + (get_associated_executor)(function)); + + asio::spawn(ex, ASIO_MOVE_CAST(Function)(function), attributes); +} + +template +void spawn(ASIO_MOVE_ARG(Handler) handler, + ASIO_MOVE_ARG(Function) function, + const boost::coroutines::attributes& attributes, + typename enable_if::type>::value && + !is_convertible::value>::type*) +{ + typedef typename decay::type handler_type; + typedef typename decay::type function_type; + + typename associated_executor::type ex( + (get_associated_executor)(handler)); + + typename associated_allocator::type a( + (get_associated_allocator)(handler)); + + detail::spawn_helper helper; + helper.data_.reset( + new detail::spawn_data( + ASIO_MOVE_CAST(Handler)(handler), true, + ASIO_MOVE_CAST(Function)(function))); + helper.attributes_ = attributes; + + ex.dispatch(helper, a); +} + +template +void spawn(basic_yield_context ctx, + ASIO_MOVE_ARG(Function) function, + const boost::coroutines::attributes& attributes) +{ + typedef typename decay::type function_type; + + Handler handler(ctx.handler_); // Explicit copy that might be moved from. + + typename associated_executor::type ex( + (get_associated_executor)(handler)); + + typename associated_allocator::type a( + (get_associated_allocator)(handler)); + + detail::spawn_helper helper; + helper.data_.reset( + new detail::spawn_data( + ASIO_MOVE_CAST(Handler)(handler), false, + ASIO_MOVE_CAST(Function)(function))); + helper.attributes_ = attributes; + + ex.dispatch(helper, a); +} + +template +inline void spawn(const Executor& ex, + ASIO_MOVE_ARG(Function) function, + const boost::coroutines::attributes& attributes, + typename enable_if::value>::type*) +{ + asio::spawn(asio::strand(ex), + ASIO_MOVE_CAST(Function)(function), attributes); +} + +template +inline void spawn(const strand& ex, + ASIO_MOVE_ARG(Function) function, + const boost::coroutines::attributes& attributes) +{ + asio::spawn(asio::bind_executor( + ex, &detail::default_spawn_handler), + ASIO_MOVE_CAST(Function)(function), attributes); +} + +template +inline void spawn(const asio::io_context::strand& s, + ASIO_MOVE_ARG(Function) function, + const boost::coroutines::attributes& attributes) +{ + asio::spawn(asio::bind_executor( + s, &detail::default_spawn_handler), + ASIO_MOVE_CAST(Function)(function), attributes); +} + +template +inline void spawn(ExecutionContext& ctx, + ASIO_MOVE_ARG(Function) function, + const boost::coroutines::attributes& attributes, + typename enable_if::value>::type*) +{ + asio::spawn(ctx.get_executor(), + ASIO_MOVE_CAST(Function)(function), attributes); +} + +#endif // !defined(GENERATING_DOCUMENTATION) + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_IMPL_SPAWN_HPP -- cgit v1.2.3