1 | // |
2 | // associated_immediate_executor.hpp |
3 | // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
4 | // |
5 | // Copyright (c) 2003-2024 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_ASSOCIATED_IMMEDIATE_EXECUTOR_HPP |
12 | #define BOOST_ASIO_ASSOCIATED_IMMEDIATE_EXECUTOR_HPP |
13 | |
14 | #if defined(_MSC_VER) && (_MSC_VER >= 1200) |
15 | # pragma once |
16 | #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) |
17 | |
18 | #include <boost/asio/detail/config.hpp> |
19 | #include <boost/asio/associator.hpp> |
20 | #include <boost/asio/detail/functional.hpp> |
21 | #include <boost/asio/detail/type_traits.hpp> |
22 | #include <boost/asio/execution/blocking.hpp> |
23 | #include <boost/asio/execution/executor.hpp> |
24 | #include <boost/asio/execution_context.hpp> |
25 | #include <boost/asio/is_executor.hpp> |
26 | #include <boost/asio/require.hpp> |
27 | |
28 | #include <boost/asio/detail/push_options.hpp> |
29 | |
30 | namespace boost { |
31 | namespace asio { |
32 | |
33 | template <typename T, typename Executor> |
34 | struct associated_immediate_executor; |
35 | |
36 | namespace detail { |
37 | |
38 | template <typename T, typename = void> |
39 | struct has_immediate_executor_type : false_type |
40 | { |
41 | }; |
42 | |
43 | template <typename T> |
44 | struct has_immediate_executor_type<T, |
45 | void_t<typename T::immediate_executor_type>> |
46 | : true_type |
47 | { |
48 | }; |
49 | |
50 | template <typename E, typename = void, typename = void> |
51 | struct default_immediate_executor |
52 | { |
53 | typedef require_result_t<E, execution::blocking_t::never_t> type; |
54 | |
55 | static type get(const E& e) noexcept |
56 | { |
57 | return boost::asio::require(e, execution::blocking.never); |
58 | } |
59 | }; |
60 | |
61 | template <typename E> |
62 | struct default_immediate_executor<E, |
63 | enable_if_t< |
64 | !execution::is_executor<E>::value |
65 | >, |
66 | enable_if_t< |
67 | is_executor<E>::value |
68 | >> |
69 | { |
70 | class type : public E |
71 | { |
72 | public: |
73 | template <typename Executor1> |
74 | explicit type(const Executor1& e, |
75 | constraint_t< |
76 | conditional_t< |
77 | !is_same<Executor1, type>::value, |
78 | is_convertible<Executor1, E>, |
79 | false_type |
80 | >::value |
81 | > = 0) noexcept |
82 | : E(e) |
83 | { |
84 | } |
85 | |
86 | type(const type& other) noexcept |
87 | : E(static_cast<const E&>(other)) |
88 | { |
89 | } |
90 | |
91 | type(type&& other) noexcept |
92 | : E(static_cast<E&&>(other)) |
93 | { |
94 | } |
95 | |
96 | template <typename Function, typename Allocator> |
97 | void dispatch(Function&& f, const Allocator& a) const |
98 | { |
99 | this->post(static_cast<Function&&>(f), a); |
100 | } |
101 | |
102 | friend bool operator==(const type& a, const type& b) noexcept |
103 | { |
104 | return static_cast<const E&>(a) == static_cast<const E&>(b); |
105 | } |
106 | |
107 | friend bool operator!=(const type& a, const type& b) noexcept |
108 | { |
109 | return static_cast<const E&>(a) != static_cast<const E&>(b); |
110 | } |
111 | }; |
112 | |
113 | static type get(const E& e) noexcept |
114 | { |
115 | return type(e); |
116 | } |
117 | }; |
118 | |
119 | template <typename T, typename E, typename = void, typename = void> |
120 | struct associated_immediate_executor_impl |
121 | { |
122 | typedef void asio_associated_immediate_executor_is_unspecialised; |
123 | |
124 | typedef typename default_immediate_executor<E>::type type; |
125 | |
126 | static auto get(const T&, const E& e) noexcept |
127 | -> decltype(default_immediate_executor<E>::get(e)) |
128 | { |
129 | return default_immediate_executor<E>::get(e); |
130 | } |
131 | }; |
132 | |
133 | template <typename T, typename E> |
134 | struct associated_immediate_executor_impl<T, E, |
135 | void_t<typename T::immediate_executor_type>> |
136 | { |
137 | typedef typename T::immediate_executor_type type; |
138 | |
139 | static auto get(const T& t, const E&) noexcept |
140 | -> decltype(t.get_immediate_executor()) |
141 | { |
142 | return t.get_immediate_executor(); |
143 | } |
144 | }; |
145 | |
146 | template <typename T, typename E> |
147 | struct associated_immediate_executor_impl<T, E, |
148 | enable_if_t< |
149 | !has_immediate_executor_type<T>::value |
150 | >, |
151 | void_t< |
152 | typename associator<associated_immediate_executor, T, E>::type |
153 | >> : associator<associated_immediate_executor, T, E> |
154 | { |
155 | }; |
156 | |
157 | } // namespace detail |
158 | |
159 | /// Traits type used to obtain the immediate executor associated with an object. |
160 | /** |
161 | * A program may specialise this traits type if the @c T template parameter in |
162 | * the specialisation is a user-defined type. The template parameter @c |
163 | * Executor shall be a type meeting the Executor requirements. |
164 | * |
165 | * Specialisations shall meet the following requirements, where @c t is a const |
166 | * reference to an object of type @c T, and @c e is an object of type @c |
167 | * Executor. |
168 | * |
169 | * @li Provide a nested typedef @c type that identifies a type meeting the |
170 | * Executor requirements. |
171 | * |
172 | * @li Provide a noexcept static member function named @c get, callable as @c |
173 | * get(t) and with return type @c type or a (possibly const) reference to @c |
174 | * type. |
175 | * |
176 | * @li Provide a noexcept static member function named @c get, callable as @c |
177 | * get(t,e) and with return type @c type or a (possibly const) reference to @c |
178 | * type. |
179 | */ |
180 | template <typename T, typename Executor> |
181 | struct associated_immediate_executor |
182 | #if !defined(GENERATING_DOCUMENTATION) |
183 | : detail::associated_immediate_executor_impl<T, Executor> |
184 | #endif // !defined(GENERATING_DOCUMENTATION) |
185 | { |
186 | #if defined(GENERATING_DOCUMENTATION) |
187 | /// If @c T has a nested type @c immediate_executor_type, |
188 | // <tt>T::immediate_executor_type</tt>. Otherwise @c Executor. |
189 | typedef see_below type; |
190 | |
191 | /// If @c T has a nested type @c immediate_executor_type, returns |
192 | /// <tt>t.get_immediate_executor()</tt>. Otherwise returns |
193 | /// <tt>boost::asio::require(ex, boost::asio::execution::blocking.never)</tt>. |
194 | static decltype(auto) get(const T& t, const Executor& ex) noexcept; |
195 | #endif // defined(GENERATING_DOCUMENTATION) |
196 | }; |
197 | |
198 | /// Helper function to obtain an object's associated executor. |
199 | /** |
200 | * @returns <tt>associated_immediate_executor<T, Executor>::get(t, ex)</tt> |
201 | */ |
202 | template <typename T, typename Executor> |
203 | BOOST_ASIO_NODISCARD inline auto get_associated_immediate_executor( |
204 | const T& t, const Executor& ex, |
205 | constraint_t< |
206 | is_executor<Executor>::value || execution::is_executor<Executor>::value |
207 | > = 0) noexcept |
208 | -> decltype(associated_immediate_executor<T, Executor>::get(t, ex)) |
209 | { |
210 | return associated_immediate_executor<T, Executor>::get(t, ex); |
211 | } |
212 | |
213 | /// Helper function to obtain an object's associated executor. |
214 | /** |
215 | * @returns <tt>associated_immediate_executor<T, typename |
216 | * ExecutionContext::executor_type>::get(t, ctx.get_executor())</tt> |
217 | */ |
218 | template <typename T, typename ExecutionContext> |
219 | BOOST_ASIO_NODISCARD inline typename associated_immediate_executor<T, |
220 | typename ExecutionContext::executor_type>::type |
221 | get_associated_immediate_executor(const T& t, ExecutionContext& ctx, |
222 | constraint_t< |
223 | is_convertible<ExecutionContext&, execution_context&>::value |
224 | > = 0) noexcept |
225 | { |
226 | return associated_immediate_executor<T, |
227 | typename ExecutionContext::executor_type>::get(t, ctx.get_executor()); |
228 | } |
229 | |
230 | template <typename T, typename Executor> |
231 | using associated_immediate_executor_t = |
232 | typename associated_immediate_executor<T, Executor>::type; |
233 | |
234 | namespace detail { |
235 | |
236 | template <typename T, typename E, typename = void> |
237 | struct associated_immediate_executor_forwarding_base |
238 | { |
239 | }; |
240 | |
241 | template <typename T, typename E> |
242 | struct associated_immediate_executor_forwarding_base<T, E, |
243 | enable_if_t< |
244 | is_same< |
245 | typename associated_immediate_executor<T, |
246 | E>::asio_associated_immediate_executor_is_unspecialised, |
247 | void |
248 | >::value |
249 | >> |
250 | { |
251 | typedef void asio_associated_immediate_executor_is_unspecialised; |
252 | }; |
253 | |
254 | } // namespace detail |
255 | |
256 | /// Specialisation of associated_immediate_executor for |
257 | /// @c std::reference_wrapper. |
258 | template <typename T, typename Executor> |
259 | struct associated_immediate_executor<reference_wrapper<T>, Executor> |
260 | #if !defined(GENERATING_DOCUMENTATION) |
261 | : detail::associated_immediate_executor_forwarding_base<T, Executor> |
262 | #endif // !defined(GENERATING_DOCUMENTATION) |
263 | { |
264 | /// Forwards @c type to the associator specialisation for the unwrapped type |
265 | /// @c T. |
266 | typedef typename associated_immediate_executor<T, Executor>::type type; |
267 | |
268 | /// Forwards the request to get the executor to the associator specialisation |
269 | /// for the unwrapped type @c T. |
270 | static auto get(reference_wrapper<T> t, const Executor& ex) noexcept |
271 | -> decltype(associated_immediate_executor<T, Executor>::get(t.get(), ex)) |
272 | { |
273 | return associated_immediate_executor<T, Executor>::get(t.get(), ex); |
274 | } |
275 | }; |
276 | |
277 | } // namespace asio |
278 | } // namespace boost |
279 | |
280 | #include <boost/asio/detail/pop_options.hpp> |
281 | |
282 | #endif // BOOST_ASIO_ASSOCIATED_IMMEDIATE_EXECUTOR_HPP |
283 | |