| // |
| // impl/go.hpp |
| // ~~~~~~~~~~~ |
| // |
| // Copyright (c) 2003-2013 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_GO_HPP |
| #define ASIO_IMPL_GO_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/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/type_traits.hpp" |
| #include "asio/handler_type.hpp" |
| |
| #include "asio/detail/push_options.hpp" |
| |
| namespace asio { |
| namespace detail { |
| |
| template <typename Handler, typename Signature> |
| class stackless_impl_base |
| { |
| protected: |
| template <typename Handler1> |
| explicit stackless_impl_base(ASIO_MOVE_ARG(Handler1) handler, |
| void (*resume_fn)(const basic_stackless_context<Handler, Signature>&), |
| void (*destroy_fn)(stackless_impl_base*)) |
| : handler_(ASIO_MOVE_CAST(Handler1)(handler)), |
| ref_count_(1), |
| result_ec_(&throw_ec_), |
| result_value_(0), |
| resume_(resume_fn), |
| destroy_(destroy_fn), |
| completed_(false) |
| { |
| } |
| |
| public: |
| static stackless_impl_base* add_ref(stackless_impl_base* impl); |
| static stackless_impl_base* move_ref(stackless_impl_base*& impl); |
| static void release_ref(stackless_impl_base* impl); |
| static void resume(stackless_impl_base*& impl); |
| |
| //private: |
| typename handler_type<Handler, Signature>::type handler_; |
| asio::detail::atomic_count ref_count_; |
| asio::coroutine coroutine_; |
| asio::error_code throw_ec_; |
| asio::error_code* result_ec_; |
| void* result_value_; |
| void (*resume_)(const basic_stackless_context<Handler, Signature>&); |
| void (*destroy_)(stackless_impl_base*); |
| bool completed_; |
| }; |
| |
| template <typename Handler, typename Signature> |
| stackless_impl_base<Handler, Signature>* |
| stackless_impl_base<Handler, Signature>::add_ref( |
| stackless_impl_base<Handler, Signature>* impl) |
| { |
| if (impl) |
| ++impl->ref_count_; |
| return impl; |
| } |
| |
| template <typename Handler, typename Signature> |
| inline stackless_impl_base<Handler, Signature>* |
| stackless_impl_base<Handler, Signature>::move_ref( |
| stackless_impl_base<Handler, Signature>*& impl) |
| { |
| stackless_impl_base* tmp = impl; |
| impl = 0; |
| return tmp; |
| } |
| |
| template <typename Handler, typename Signature> |
| void stackless_impl_base<Handler, Signature>::release_ref( |
| stackless_impl_base<Handler, Signature>* impl) |
| { |
| if (impl) |
| { |
| if (--impl->ref_count_ == 0) |
| impl->destroy_(impl); |
| } |
| } |
| |
| template <typename Signature> |
| struct call_completed_handler |
| { |
| template <typename Handler> |
| static void call(Handler&) {} |
| }; |
| |
| template <> |
| struct call_completed_handler<void ()> |
| { |
| template <typename Handler> |
| static void call(Handler& h) { h(); } |
| }; |
| |
| template <typename Handler, typename Signature> |
| void stackless_impl_base<Handler, Signature>::resume( |
| stackless_impl_base<Handler, Signature>*& impl) |
| { |
| impl->result_value_ = 0; |
| basic_stackless_context<Handler, Signature> ctx |
| = { &impl, &impl->throw_ec_ }; |
| impl->resume_(ctx); |
| |
| if (impl && impl->coroutine_.is_complete() && !impl->completed_) |
| { |
| impl->completed_ = true; |
| call_completed_handler<Signature>::call(impl->handler_); |
| } |
| } |
| |
| template <typename Handler, typename Signature, typename Function> |
| class stackless_impl : |
| public stackless_impl_base<Handler, Signature> |
| { |
| public: |
| template <typename Handler1, typename Function1> |
| stackless_impl(ASIO_MOVE_ARG(Handler1) handler, |
| ASIO_MOVE_ARG(Function1) function) |
| : stackless_impl_base<Handler, Signature>( |
| ASIO_MOVE_CAST(Handler1)(handler), |
| &stackless_impl::do_resume, |
| &stackless_impl::do_destroy), |
| function_(ASIO_MOVE_CAST(Function1)(function)) |
| { |
| } |
| |
| private: |
| static void do_resume( |
| const basic_stackless_context<Handler, Signature>& ctx) |
| { |
| stackless_impl_base<Handler, Signature>* base = *ctx.impl_; |
| static_cast<stackless_impl*>(base)->function_(ctx); |
| } |
| |
| static void do_destroy(stackless_impl_base<Handler, Signature>* impl) |
| { |
| delete static_cast<stackless_impl*>(impl); |
| } |
| |
| Function function_; |
| }; |
| |
| template <typename Handler, typename Signature, typename T> |
| class stackless_handler |
| { |
| public: |
| stackless_handler(const basic_stackless_context<Handler, Signature>& ctx) |
| : impl_(stackless_impl_base<Handler, Signature>::move_ref(*ctx.impl_)) |
| { |
| impl_->result_ec_ = ctx.ec_; |
| } |
| |
| stackless_handler(const stackless_handler& other) |
| : impl_(stackless_impl_base<Handler, Signature>::add_ref(other.impl_)) |
| { |
| } |
| |
| #if defined(ASIO_HAS_MOVE) |
| stackless_handler(stackless_handler&& other) |
| : impl_(stackless_impl_base<Handler, Signature>::move_ref(other.impl_)) |
| { |
| } |
| #endif // defined(ASIO_HAS_MOVE) |
| |
| ~stackless_handler() |
| { |
| stackless_impl_base<Handler, Signature>::release_ref(impl_); |
| } |
| |
| void operator()(T value) |
| { |
| *impl_->result_ec_ = asio::error_code(); |
| if (impl_->result_value_) |
| *static_cast<T*>(impl_->result_value_) = value; |
| stackless_impl_base<Handler, Signature>::resume(impl_); |
| } |
| |
| void operator()(asio::error_code ec, T value) |
| { |
| *impl_->result_ec_ = ec; |
| if (impl_->result_value_) |
| *static_cast<T*>(impl_->result_value_) = value; |
| stackless_impl_base<Handler, Signature>::resume(impl_); |
| } |
| |
| //private: |
| stackless_impl_base<Handler, Signature>* impl_; |
| |
| private: |
| stackless_handler& operator=(const stackless_handler&); |
| }; |
| |
| template <typename Handler, typename Signature> |
| class stackless_handler<Handler, Signature, void> |
| { |
| public: |
| stackless_handler(const basic_stackless_context<Handler, Signature>& ctx) |
| : impl_(stackless_impl_base<Handler, Signature>::move_ref(*ctx.impl_)) |
| { |
| impl_->result_ec_ = ctx.ec_; |
| } |
| |
| stackless_handler(const stackless_handler& other) |
| : impl_(stackless_impl_base<Handler, Signature>::add_ref(other.impl_)) |
| { |
| } |
| |
| #if defined(ASIO_HAS_MOVE) |
| stackless_handler(stackless_handler&& other) |
| : impl_(stackless_impl_base<Handler, Signature>::move_ref(other.impl_)) |
| { |
| } |
| #endif // defined(ASIO_HAS_MOVE) |
| |
| ~stackless_handler() |
| { |
| stackless_impl_base<Handler, Signature>::release_ref(impl_); |
| } |
| |
| void operator()() |
| { |
| *impl_->result_ec_ = asio::error_code(); |
| stackless_impl_base<Handler, Signature>::resume(impl_); |
| } |
| |
| void operator()(asio::error_code ec) |
| { |
| *impl_->result_ec_ = ec; |
| stackless_impl_base<Handler, Signature>::resume(impl_); |
| } |
| |
| //private: |
| stackless_impl_base<Handler, Signature>* impl_; |
| |
| private: |
| stackless_handler& operator=(const stackless_handler&); |
| }; |
| |
| template <typename Handler, typename Signature, typename T> |
| inline void* asio_handler_allocate(std::size_t size, |
| stackless_handler<Handler, Signature, T>* this_handler) |
| { |
| return asio_handler_alloc_helpers::allocate( |
| size, this_handler->impl_->handler_); |
| } |
| |
| template <typename Handler, typename Signature, typename T> |
| inline void asio_handler_deallocate(void* pointer, std::size_t size, |
| stackless_handler<Handler, Signature, T>* this_handler) |
| { |
| asio_handler_alloc_helpers::deallocate( |
| pointer, size, this_handler->impl_->handler_); |
| } |
| |
| template <typename Handler, typename Signature, typename T> |
| inline bool asio_handler_is_continuation( |
| stackless_handler<Handler, Signature, T>*) |
| { |
| return true; |
| } |
| |
| template <typename Function, typename Handler, typename Signature, typename T> |
| inline void asio_handler_invoke(Function& function, |
| stackless_handler<Handler, Signature, T>* this_handler) |
| { |
| asio_handler_invoke_helpers::invoke( |
| function, this_handler->impl_->handler_); |
| } |
| |
| template <typename Function, typename Handler, typename Signature, typename T> |
| inline void asio_handler_invoke(const Function& function, |
| stackless_handler<Handler, Signature, T>* this_handler) |
| { |
| asio_handler_invoke_helpers::invoke( |
| function, this_handler->impl_->handler_); |
| } |
| |
| template <typename Handler, typename Signature, typename Function> |
| struct go_helper |
| { |
| template <typename Handler1, typename Function1> |
| go_helper(ASIO_MOVE_ARG(Handler1) handler, |
| ASIO_MOVE_ARG(Function1) function) |
| : impl_(new stackless_impl<Handler, Signature, Function>( |
| ASIO_MOVE_CAST(Handler1)(handler), |
| ASIO_MOVE_CAST(Function1)(function))) |
| { |
| } |
| |
| go_helper(const go_helper& other) |
| : impl_(stackless_impl_base<Handler, Signature>::add_ref(other.impl_)) |
| { |
| } |
| |
| #if defined(ASIO_HAS_MOVE) |
| go_helper(go_helper&& other) |
| : impl_(stackless_impl_base<Handler, Signature>::move_ref(other.impl_)) |
| { |
| } |
| #endif // defined(ASIO_HAS_MOVE) |
| |
| ~go_helper() |
| { |
| stackless_impl_base<Handler, Signature>::release_ref(impl_); |
| } |
| |
| void operator()() |
| { |
| stackless_impl_base<Handler, Signature>::resume(impl_); |
| } |
| |
| stackless_impl_base<Handler, Signature>* impl_; |
| |
| private: |
| go_helper& operator=(const go_helper&); |
| }; |
| |
| inline void default_go_handler() {} |
| |
| } // namespace detail |
| |
| #if !defined(GENERATING_DOCUMENTATION) |
| |
| template <typename Handler, typename Signature, typename ReturnType> |
| struct handler_type<basic_stackless_context<Handler, Signature>, ReturnType()> |
| { |
| typedef detail::stackless_handler<Handler, Signature, void> type; |
| }; |
| |
| template <typename Handler, typename Signature, |
| typename ReturnType, typename Arg1> |
| struct handler_type<basic_stackless_context<Handler, Signature>, |
| ReturnType(Arg1)> |
| { |
| typedef detail::stackless_handler<Handler, Signature, Arg1> type; |
| }; |
| |
| template <typename Handler, typename Signature, typename ReturnType> |
| struct handler_type<basic_stackless_context<Handler, Signature>, |
| ReturnType(asio::error_code)> |
| { |
| typedef detail::stackless_handler<Handler, Signature, void> type; |
| }; |
| |
| template <typename Handler, typename Signature, |
| typename ReturnType, typename Arg2> |
| struct handler_type<basic_stackless_context<Handler, Signature>, |
| ReturnType(asio::error_code, Arg2)> |
| { |
| typedef detail::stackless_handler<Handler, Signature, Arg2> type; |
| }; |
| |
| template <typename Handler, typename Signature, typename T> |
| class async_result<detail::stackless_handler<Handler, Signature, T> > |
| { |
| public: |
| typedef awaitable<T> type; |
| |
| explicit async_result(detail::stackless_handler<Handler, Signature, T>&) |
| { |
| } |
| |
| type get() |
| { |
| return type(); |
| } |
| }; |
| |
| template <typename Handler, typename Signature> |
| inline coroutine& get_coroutine( |
| basic_stackless_context<Handler, Signature>& c) |
| { |
| return (*c.impl_)->coroutine_; |
| } |
| |
| template <typename Handler, typename Signature> |
| inline coroutine& get_coroutine( |
| basic_stackless_context<Handler, Signature>* c) |
| { |
| return (*c->impl_)->coroutine_; |
| } |
| |
| template <typename Handler, typename Signature> |
| inline const asio::error_code* get_coroutine_error( |
| basic_stackless_context<Handler, Signature>& c) |
| { |
| return &(*c.impl_)->throw_ec_; |
| } |
| |
| template <typename Handler, typename Signature> |
| inline const asio::error_code* get_coroutine_error( |
| basic_stackless_context<Handler, Signature>* c) |
| { |
| return &(*c->impl_)->throw_ec_; |
| } |
| |
| template <typename Handler, typename Signature> |
| inline void** get_coroutine_async_result( |
| basic_stackless_context<Handler, Signature>& c) |
| { |
| return &(*c.impl_)->result_value_; |
| } |
| |
| template <typename Handler, typename Signature> |
| inline void** get_coroutine_async_result( |
| basic_stackless_context<Handler, Signature>* c) |
| { |
| return &(*c->impl_)->result_value_; |
| } |
| |
| #if defined(ASIO_HAS_VARIADIC_TEMPLATES) |
| |
| template <typename Handler, typename Signature> |
| template <typename... T> |
| void basic_stackless_context<Handler, Signature>::complete(T&&... args) |
| { |
| if (!(*impl_)->completed_) |
| { |
| (*impl_)->completed_ = true; |
| (*impl_)->handler_(static_cast<T&&>(args)...); |
| } |
| } |
| |
| #else // defined(ASIO_HAS_VARIADIC_TEMPLATES) |
| |
| template <typename Handler, typename Signature> |
| void basic_stackless_context<Handler, Signature>::complete() |
| { |
| if (!(*impl_)->completed_) |
| { |
| (*impl_)->completed_ = true; |
| (*impl_)->handler_(); |
| } |
| } |
| |
| // A macro that should expand to: |
| // template <typename Handler, typename Signature> |
| // template <typename T1, ..., typename Tn> |
| // void basic_stackless_context<Handler, Signature>::complete( |
| // const T1& x1, ..., const Tn& xn) |
| // { |
| // if (!(*impl_)->completed_) |
| // { |
| // (*impl_)->completed_ = true; |
| // (*impl_)->handler_(x1, ..., xn); |
| // } |
| // } |
| // This macro should only persist within this file. |
| |
| # define ASIO_PRIVATE_COMPLETE_DEF(n) \ |
| template <typename Handler, typename Signature> \ |
| template <ASIO_VARIADIC_TPARAMS(n)> \ |
| void basic_stackless_context<Handler, Signature>::complete( \ |
| ASIO_VARIADIC_CONSTREF_PARAMS(n)) \ |
| { \ |
| if (!(*impl_)->completed_) \ |
| { \ |
| (*impl_)->completed_ = true; \ |
| (*impl_)->handler_(ASIO_VARIADIC_ARGS(n)); \ |
| } \ |
| } \ |
| /**/ |
| |
| ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_COMPLETE_DEF) |
| |
| # undef ASIO_PRIVATE_COMPLETE_DEF |
| |
| #endif // defined(ASIO_HAS_VARIADIC_TEMPLATES) |
| |
| template <typename Handler, typename Function> |
| ASIO_INITFN_RESULT_TYPE(Handler, void ()) |
| go(ASIO_MOVE_ARG(Handler) handler, |
| ASIO_MOVE_ARG(Function) function) |
| { |
| typedef typename remove_const< |
| typename remove_reference<Handler>::type>::type |
| passed_handler_type; |
| |
| typedef typename handler_type< |
| Handler, void ()>::type real_handler_type; |
| |
| typedef typename remove_const< |
| typename remove_reference<Function>::type>::type |
| function_type; |
| |
| detail::go_helper<passed_handler_type, void (), function_type> helper( |
| ASIO_MOVE_CAST(Handler)(handler), |
| ASIO_MOVE_CAST(Function)(function)); |
| |
| async_result<real_handler_type> result(helper.impl_->handler_); |
| |
| asio_handler_invoke_helpers::invoke( |
| helper, helper.impl_->handler_); |
| |
| return result.get(); |
| } |
| |
| template <typename Signature, typename Handler, typename Function> |
| ASIO_INITFN_RESULT_TYPE(Handler, Signature) |
| go(ASIO_MOVE_ARG(Handler) handler, |
| ASIO_MOVE_ARG(Function) function) |
| { |
| typedef typename remove_const< |
| typename remove_reference<Handler>::type>::type |
| passed_handler_type; |
| |
| typedef typename handler_type< |
| Handler, Signature>::type real_handler_type; |
| |
| typedef typename remove_const< |
| typename remove_reference<Function>::type>::type |
| function_type; |
| |
| detail::go_helper<passed_handler_type, Signature, function_type> helper( |
| ASIO_MOVE_CAST(Handler)(handler), |
| ASIO_MOVE_CAST(Function)(function)); |
| |
| async_result<real_handler_type> result(helper.impl_->handler_); |
| |
| asio_handler_invoke_helpers::invoke( |
| helper, helper.impl_->handler_); |
| |
| return result.get(); |
| } |
| |
| template <typename Handler, typename Function> |
| void go(basic_stackless_context<Handler> ctx, |
| ASIO_MOVE_ARG(Function) function) |
| { |
| Handler handler(ctx.handler_); |
| go(ASIO_MOVE_CAST(Handler)(handler), |
| ASIO_MOVE_CAST(Function)(function)); |
| } |
| |
| template <typename Function> |
| void go(asio::io_service::strand strand, |
| ASIO_MOVE_ARG(Function) function) |
| { |
| asio::go(strand.wrap(&detail::default_go_handler), |
| ASIO_MOVE_CAST(Function)(function)); |
| } |
| |
| template <typename Function> |
| void go(asio::io_service& io_service, |
| ASIO_MOVE_ARG(Function) function) |
| { |
| asio::go(asio::io_service::strand(io_service), |
| ASIO_MOVE_CAST(Function)(function)); |
| } |
| |
| #endif // !defined(GENERATING_DOCUMENTATION) |
| |
| } // namespace asio |
| |
| #include "asio/detail/pop_options.hpp" |
| |
| #endif // ASIO_IMPL_GO_HPP |