1 //
2 // io_object_impl.hpp
3 // ~~~~~~~~~~~~~~~~~~
4 //
5 // Copyright (c) 2003-2021 Christopher M. Kohlhoff (chris at kohlhoff dot com)
6 //
7 // Distributed under the Boost Software License, Version 1.0. (See accompanying
8 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
9 //
10 
11 #ifndef BOOST_ASIO_DETAIL_IO_OBJECT_IMPL_HPP
12 #define BOOST_ASIO_DETAIL_IO_OBJECT_IMPL_HPP
13 
14 #if defined(_MSC_VER) && (_MSC_VER >= 1200)
15 # pragma once
16 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
17 
18 #include <new>
19 #include <boost/asio/detail/config.hpp>
20 #include <boost/asio/detail/type_traits.hpp>
21 #include <boost/asio/execution/executor.hpp>
22 #include <boost/asio/execution/context.hpp>
23 #include <boost/asio/io_context.hpp>
24 #include <boost/asio/query.hpp>
25 
26 #include <boost/asio/detail/push_options.hpp>
27 
28 namespace boost {
29 namespace asio {
30 namespace detail {
31 
32 template <typename IoObjectService,
33     typename Executor = io_context::executor_type>
34 class io_object_impl
35 {
36 public:
37   // The type of the service that will be used to provide I/O operations.
38   typedef IoObjectService service_type;
39 
40   // The underlying implementation type of I/O object.
41   typedef typename service_type::implementation_type implementation_type;
42 
43   // The type of the executor associated with the object.
44   typedef Executor executor_type;
45 
46   // Construct an I/O object using an executor.
io_object_impl(int,const executor_type & ex)47   explicit io_object_impl(int, const executor_type& ex)
48     : service_(&boost::asio::use_service<IoObjectService>(
49           io_object_impl::get_context(ex))),
50       executor_(ex)
51   {
52     service_->construct(implementation_);
53   }
54 
55   // Construct an I/O object using an execution context.
56   template <typename ExecutionContext>
io_object_impl(int,int,ExecutionContext & context)57   explicit io_object_impl(int, int, ExecutionContext& context)
58     : service_(&boost::asio::use_service<IoObjectService>(context)),
59       executor_(context.get_executor())
60   {
61     service_->construct(implementation_);
62   }
63 
64 #if defined(BOOST_ASIO_HAS_MOVE)
65   // Move-construct an I/O object.
io_object_impl(io_object_impl && other)66   io_object_impl(io_object_impl&& other)
67     : service_(&other.get_service()),
68       executor_(other.get_executor())
69   {
70     service_->move_construct(implementation_, other.implementation_);
71   }
72 
73   // Perform a converting move-construction of an I/O object.
74   template <typename IoObjectService1, typename Executor1>
io_object_impl(io_object_impl<IoObjectService1,Executor1> && other)75   io_object_impl(io_object_impl<IoObjectService1, Executor1>&& other)
76     : service_(&boost::asio::use_service<IoObjectService>(
77             io_object_impl::get_context(other.get_executor()))),
78       executor_(other.get_executor())
79   {
80     service_->converting_move_construct(implementation_,
81         other.get_service(), other.get_implementation());
82   }
83 #endif // defined(BOOST_ASIO_HAS_MOVE)
84 
85   // Destructor.
~io_object_impl()86   ~io_object_impl()
87   {
88     service_->destroy(implementation_);
89   }
90 
91 #if defined(BOOST_ASIO_HAS_MOVE)
92   // Move-assign an I/O object.
operator =(io_object_impl && other)93   io_object_impl& operator=(io_object_impl&& other)
94   {
95     if (this != &other)
96     {
97       service_->move_assign(implementation_,
98           *other.service_, other.implementation_);
99       executor_.~executor_type();
100       new (&executor_) executor_type(other.executor_);
101       service_ = other.service_;
102     }
103     return *this;
104   }
105 #endif // defined(BOOST_ASIO_HAS_MOVE)
106 
107   // Get the executor associated with the object.
get_executor()108   const executor_type& get_executor() BOOST_ASIO_NOEXCEPT
109   {
110     return executor_;
111   }
112 
113   // Get the service associated with the I/O object.
get_service()114   service_type& get_service()
115   {
116     return *service_;
117   }
118 
119   // Get the service associated with the I/O object.
get_service() const120   const service_type& get_service() const
121   {
122     return *service_;
123   }
124 
125   // Get the underlying implementation of the I/O object.
get_implementation()126   implementation_type& get_implementation()
127   {
128     return implementation_;
129   }
130 
131   // Get the underlying implementation of the I/O object.
get_implementation() const132   const implementation_type& get_implementation() const
133   {
134     return implementation_;
135   }
136 
137 private:
138   // Helper function to get an executor's context.
139   template <typename T>
get_context(const T & t,typename enable_if<execution::is_executor<T>::value>::type * =0)140   static execution_context& get_context(const T& t,
141       typename enable_if<execution::is_executor<T>::value>::type* = 0)
142   {
143     return boost::asio::query(t, execution::context);
144   }
145 
146   // Helper function to get an executor's context.
147   template <typename T>
get_context(const T & t,typename enable_if<!execution::is_executor<T>::value>::type * =0)148   static execution_context& get_context(const T& t,
149       typename enable_if<!execution::is_executor<T>::value>::type* = 0)
150   {
151     return t.context();
152   }
153 
154   // Disallow copying and copy assignment.
155   io_object_impl(const io_object_impl&);
156   io_object_impl& operator=(const io_object_impl&);
157 
158   // The service associated with the I/O object.
159   service_type* service_;
160 
161   // The underlying implementation of the I/O object.
162   implementation_type implementation_;
163 
164   // The associated executor.
165   executor_type executor_;
166 };
167 
168 } // namespace detail
169 } // namespace asio
170 } // namespace boost
171 
172 #include <boost/asio/detail/pop_options.hpp>
173 
174 #endif // BOOST_ASIO_DETAIL_IO_OBJECT_IMPL_HPP
175