285 lines
		
	
	
		
			7.6 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			285 lines
		
	
	
		
			7.6 KiB
		
	
	
	
		
			C++
		
	
	
	
| //
 | |
| // experimental/detail/channel_operation.hpp
 | |
| // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 | |
| //
 | |
| // Copyright (c) 2003-2023 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_DETAIL_CHANNEL_OPERATION_HPP
 | |
| #define ASIO_EXPERIMENTAL_DETAIL_CHANNEL_OPERATION_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/associated_immediate_executor.hpp"
 | |
| #include "asio/detail/initiate_post.hpp"
 | |
| #include "asio/detail/initiate_dispatch.hpp"
 | |
| #include "asio/detail/op_queue.hpp"
 | |
| #include "asio/detail/type_traits.hpp"
 | |
| #include "asio/execution/executor.hpp"
 | |
| #include "asio/execution/outstanding_work.hpp"
 | |
| #include "asio/executor_work_guard.hpp"
 | |
| #include "asio/prefer.hpp"
 | |
| 
 | |
| #include "asio/detail/push_options.hpp"
 | |
| 
 | |
| namespace asio {
 | |
| namespace experimental {
 | |
| namespace detail {
 | |
| 
 | |
| // Base class for all channel operations. A function pointer is used instead of
 | |
| // virtual functions to avoid the associated overhead.
 | |
| class channel_operation ASIO_INHERIT_TRACKED_HANDLER
 | |
| {
 | |
| public:
 | |
|   template <typename Executor, typename = void>
 | |
|   class handler_work_base;
 | |
| 
 | |
|   template <typename Handler, typename IoExecutor, typename = void>
 | |
|   class handler_work;
 | |
| 
 | |
|   void destroy()
 | |
|   {
 | |
|     func_(this, destroy_op, 0);
 | |
|   }
 | |
| 
 | |
| protected:
 | |
|   enum action
 | |
|   {
 | |
|     destroy_op = 0,
 | |
|     immediate_op = 1,
 | |
|     complete_op = 2,
 | |
|     cancel_op = 3,
 | |
|     close_op = 4
 | |
|   };
 | |
| 
 | |
|   typedef void (*func_type)(channel_operation*, action, void*);
 | |
| 
 | |
|   channel_operation(func_type func)
 | |
|     : next_(0),
 | |
|       func_(func),
 | |
|       cancellation_key_(0)
 | |
|   {
 | |
|   }
 | |
| 
 | |
|   // Prevents deletion through this type.
 | |
|   ~channel_operation()
 | |
|   {
 | |
|   }
 | |
| 
 | |
|   friend class asio::detail::op_queue_access;
 | |
|   channel_operation* next_;
 | |
|   func_type func_;
 | |
| 
 | |
| public:
 | |
|   // The operation key used for targeted cancellation.
 | |
|   void* cancellation_key_;
 | |
| };
 | |
| 
 | |
| template <typename Executor, typename>
 | |
| class channel_operation::handler_work_base
 | |
| {
 | |
| public:
 | |
|   typedef typename decay<
 | |
|       typename prefer_result<Executor,
 | |
|         execution::outstanding_work_t::tracked_t
 | |
|       >::type
 | |
|     >::type executor_type;
 | |
| 
 | |
|   handler_work_base(int, const Executor& ex)
 | |
|     : executor_(asio::prefer(ex, execution::outstanding_work.tracked))
 | |
|   {
 | |
|   }
 | |
| 
 | |
|   const executor_type& get_executor() const ASIO_NOEXCEPT
 | |
|   {
 | |
|     return executor_;
 | |
|   }
 | |
| 
 | |
|   template <typename Function, typename Handler>
 | |
|   void post(Function& function, Handler& handler)
 | |
|   {
 | |
|     typename associated_allocator<Handler>::type allocator =
 | |
|       (get_associated_allocator)(handler);
 | |
| 
 | |
| #if defined(ASIO_NO_DEPRECATED)
 | |
|     asio::prefer(
 | |
|         asio::require(executor_, execution::blocking.never),
 | |
|         execution::allocator(allocator)
 | |
|       ).execute(ASIO_MOVE_CAST(Function)(function));
 | |
| #else // defined(ASIO_NO_DEPRECATED)
 | |
|     execution::execute(
 | |
|         asio::prefer(
 | |
|           asio::require(executor_, execution::blocking.never),
 | |
|           execution::allocator(allocator)),
 | |
|         ASIO_MOVE_CAST(Function)(function));
 | |
| #endif // defined(ASIO_NO_DEPRECATED)
 | |
|   }
 | |
| 
 | |
| private:
 | |
|   executor_type executor_;
 | |
| };
 | |
| 
 | |
| #if !defined(ASIO_NO_TS_EXECUTORS)
 | |
| 
 | |
| template <typename Executor>
 | |
| class channel_operation::handler_work_base<Executor,
 | |
|     typename enable_if<
 | |
|       !execution::is_executor<Executor>::value
 | |
|     >::type>
 | |
| {
 | |
| public:
 | |
|   typedef Executor executor_type;
 | |
| 
 | |
|   handler_work_base(int, const Executor& ex)
 | |
|     : work_(ex)
 | |
|   {
 | |
|   }
 | |
| 
 | |
|   executor_type get_executor() const ASIO_NOEXCEPT
 | |
|   {
 | |
|     return work_.get_executor();
 | |
|   }
 | |
| 
 | |
|   template <typename Function, typename Handler>
 | |
|   void post(Function& function, Handler& handler)
 | |
|   {
 | |
|     typename associated_allocator<Handler>::type allocator =
 | |
|       (get_associated_allocator)(handler);
 | |
| 
 | |
|     work_.get_executor().post(
 | |
|         ASIO_MOVE_CAST(Function)(function), allocator);
 | |
|   }
 | |
| 
 | |
| private:
 | |
|   executor_work_guard<Executor> work_;
 | |
| };
 | |
| 
 | |
| #endif // !defined(ASIO_NO_TS_EXECUTORS)
 | |
| 
 | |
| template <typename Handler, typename IoExecutor, typename>
 | |
| class channel_operation::handler_work :
 | |
|   channel_operation::handler_work_base<IoExecutor>,
 | |
|   channel_operation::handler_work_base<
 | |
|       typename associated_executor<Handler, IoExecutor>::type, IoExecutor>
 | |
| {
 | |
| public:
 | |
|   typedef channel_operation::handler_work_base<IoExecutor> base1_type;
 | |
| 
 | |
|   typedef channel_operation::handler_work_base<
 | |
|       typename associated_executor<Handler, IoExecutor>::type, IoExecutor>
 | |
|     base2_type;
 | |
| 
 | |
|   handler_work(Handler& handler, const IoExecutor& io_ex) ASIO_NOEXCEPT
 | |
|     : base1_type(0, io_ex),
 | |
|       base2_type(0, (get_associated_executor)(handler, io_ex))
 | |
|   {
 | |
|   }
 | |
| 
 | |
|   template <typename Function>
 | |
|   void complete(Function& function, Handler& handler)
 | |
|   {
 | |
|     base2_type::post(function, handler);
 | |
|   }
 | |
| 
 | |
|   template <typename Function>
 | |
|   void immediate(Function& function, Handler& handler, ...)
 | |
|   {
 | |
|     typedef typename associated_immediate_executor<Handler,
 | |
|       typename base1_type::executor_type>::type immediate_ex_type;
 | |
| 
 | |
|     immediate_ex_type immediate_ex = (get_associated_immediate_executor)(
 | |
|         handler, base1_type::get_executor());
 | |
| 
 | |
|     (asio::detail::initiate_dispatch_with_executor<immediate_ex_type>(
 | |
|           immediate_ex))(ASIO_MOVE_CAST(Function)(function));
 | |
|   }
 | |
| 
 | |
|   template <typename Function>
 | |
|   void immediate(Function& function, Handler&,
 | |
|       typename enable_if<
 | |
|         is_same<
 | |
|           typename associated_immediate_executor<
 | |
|             typename conditional<false, Function, Handler>::type,
 | |
|             typename base1_type::executor_type>::
 | |
|               asio_associated_immediate_executor_is_unspecialised,
 | |
|           void
 | |
|         >::value
 | |
|       >::type*)
 | |
|   {
 | |
|     (asio::detail::initiate_post_with_executor<
 | |
|         typename base1_type::executor_type>(
 | |
|           base1_type::get_executor()))(
 | |
|         ASIO_MOVE_CAST(Function)(function));
 | |
|   }
 | |
| };
 | |
| 
 | |
| template <typename Handler, typename IoExecutor>
 | |
| class channel_operation::handler_work<
 | |
|     Handler, IoExecutor,
 | |
|     typename enable_if<
 | |
|       is_same<
 | |
|         typename associated_executor<Handler,
 | |
|           IoExecutor>::asio_associated_executor_is_unspecialised,
 | |
|         void
 | |
|       >::value
 | |
|     >::type> : handler_work_base<IoExecutor>
 | |
| {
 | |
| public:
 | |
|   typedef channel_operation::handler_work_base<IoExecutor> base1_type;
 | |
| 
 | |
|   handler_work(Handler&, const IoExecutor& io_ex) ASIO_NOEXCEPT
 | |
|     : base1_type(0, io_ex)
 | |
|   {
 | |
|   }
 | |
| 
 | |
|   template <typename Function>
 | |
|   void complete(Function& function, Handler& handler)
 | |
|   {
 | |
|     base1_type::post(function, handler);
 | |
|   }
 | |
| 
 | |
|   template <typename Function>
 | |
|   void immediate(Function& function, Handler& handler, ...)
 | |
|   {
 | |
|     typedef typename associated_immediate_executor<Handler,
 | |
|       typename base1_type::executor_type>::type immediate_ex_type;
 | |
| 
 | |
|     immediate_ex_type immediate_ex = (get_associated_immediate_executor)(
 | |
|         handler, base1_type::get_executor());
 | |
| 
 | |
|     (asio::detail::initiate_dispatch_with_executor<immediate_ex_type>(
 | |
|           immediate_ex))(ASIO_MOVE_CAST(Function)(function));
 | |
|   }
 | |
| 
 | |
|   template <typename Function>
 | |
|   void immediate(Function& function, Handler& handler,
 | |
|       typename enable_if<
 | |
|         is_same<
 | |
|           typename associated_immediate_executor<
 | |
|             typename conditional<false, Function, Handler>::type,
 | |
|             typename base1_type::executor_type>::
 | |
|               asio_associated_immediate_executor_is_unspecialised,
 | |
|           void
 | |
|         >::value
 | |
|       >::type*)
 | |
|   {
 | |
|     base1_type::post(function, handler);
 | |
|   }
 | |
| };
 | |
| 
 | |
| } // namespace detail
 | |
| } // namespace experimental
 | |
| } // namespace asio
 | |
| 
 | |
| #include "asio/detail/pop_options.hpp"
 | |
| 
 | |
| #endif // ASIO_EXPERIMENTAL_DETAIL_CHANNEL_OPERATION_HPP
 |