1 | // |
2 | // associated_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_EXECUTOR_HPP |
12 | #define BOOST_ASIO_ASSOCIATED_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/executor.hpp> |
23 | #include <boost/asio/is_executor.hpp> |
24 | #include <boost/asio/system_executor.hpp> |
25 | |
26 | #include <boost/asio/detail/push_options.hpp> |
27 | |
28 | namespace boost { |
29 | namespace asio { |
30 | |
31 | template <typename T, typename Executor> |
32 | struct associated_executor; |
33 | |
34 | namespace detail { |
35 | |
36 | template <typename T, typename = void> |
37 | struct has_executor_type : false_type |
38 | { |
39 | }; |
40 | |
41 | template <typename T> |
42 | struct has_executor_type<T, void_t<typename T::executor_type>> |
43 | : true_type |
44 | { |
45 | }; |
46 | |
47 | template <typename T, typename E, typename = void, typename = void> |
48 | struct associated_executor_impl |
49 | { |
50 | typedef void asio_associated_executor_is_unspecialised; |
51 | |
52 | typedef E type; |
53 | |
54 | static type get(const T&) noexcept |
55 | { |
56 | return type(); |
57 | } |
58 | |
59 | static const type& get(const T&, const E& e) noexcept |
60 | { |
61 | return e; |
62 | } |
63 | }; |
64 | |
65 | template <typename T, typename E> |
66 | struct associated_executor_impl<T, E, void_t<typename T::executor_type>> |
67 | { |
68 | typedef typename T::executor_type type; |
69 | |
70 | static auto get(const T& t) noexcept |
71 | -> decltype(t.get_executor()) |
72 | { |
73 | return t.get_executor(); |
74 | } |
75 | |
76 | static auto get(const T& t, const E&) noexcept |
77 | -> decltype(t.get_executor()) |
78 | { |
79 | return t.get_executor(); |
80 | } |
81 | }; |
82 | |
83 | template <typename T, typename E> |
84 | struct associated_executor_impl<T, E, |
85 | enable_if_t< |
86 | !has_executor_type<T>::value |
87 | >, |
88 | void_t< |
89 | typename associator<associated_executor, T, E>::type |
90 | >> : associator<associated_executor, T, E> |
91 | { |
92 | }; |
93 | |
94 | } // namespace detail |
95 | |
96 | /// Traits type used to obtain the executor associated with an object. |
97 | /** |
98 | * A program may specialise this traits type if the @c T template parameter in |
99 | * the specialisation is a user-defined type. The template parameter @c |
100 | * Executor shall be a type meeting the Executor requirements. |
101 | * |
102 | * Specialisations shall meet the following requirements, where @c t is a const |
103 | * reference to an object of type @c T, and @c e is an object of type @c |
104 | * Executor. |
105 | * |
106 | * @li Provide a nested typedef @c type that identifies a type meeting the |
107 | * Executor requirements. |
108 | * |
109 | * @li Provide a noexcept static member function named @c get, callable as @c |
110 | * get(t) and with return type @c type or a (possibly const) reference to @c |
111 | * type. |
112 | * |
113 | * @li Provide a noexcept static member function named @c get, callable as @c |
114 | * get(t,e) and with return type @c type or a (possibly const) reference to @c |
115 | * type. |
116 | */ |
117 | template <typename T, typename Executor = system_executor> |
118 | struct associated_executor |
119 | #if !defined(GENERATING_DOCUMENTATION) |
120 | : detail::associated_executor_impl<T, Executor> |
121 | #endif // !defined(GENERATING_DOCUMENTATION) |
122 | { |
123 | #if defined(GENERATING_DOCUMENTATION) |
124 | /// If @c T has a nested type @c executor_type, <tt>T::executor_type</tt>. |
125 | /// Otherwise @c Executor. |
126 | typedef see_below type; |
127 | |
128 | /// If @c T has a nested type @c executor_type, returns |
129 | /// <tt>t.get_executor()</tt>. Otherwise returns @c type(). |
130 | static decltype(auto) get(const T& t) noexcept; |
131 | |
132 | /// If @c T has a nested type @c executor_type, returns |
133 | /// <tt>t.get_executor()</tt>. Otherwise returns @c ex. |
134 | static decltype(auto) get(const T& t, const Executor& ex) noexcept; |
135 | #endif // defined(GENERATING_DOCUMENTATION) |
136 | }; |
137 | |
138 | /// Helper function to obtain an object's associated executor. |
139 | /** |
140 | * @returns <tt>associated_executor<T>::get(t)</tt> |
141 | */ |
142 | template <typename T> |
143 | BOOST_ASIO_NODISCARD inline typename associated_executor<T>::type |
144 | get_associated_executor(const T& t) noexcept |
145 | { |
146 | return associated_executor<T>::get(t); |
147 | } |
148 | |
149 | /// Helper function to obtain an object's associated executor. |
150 | /** |
151 | * @returns <tt>associated_executor<T, Executor>::get(t, ex)</tt> |
152 | */ |
153 | template <typename T, typename Executor> |
154 | BOOST_ASIO_NODISCARD inline auto get_associated_executor( |
155 | const T& t, const Executor& ex, |
156 | constraint_t< |
157 | is_executor<Executor>::value || execution::is_executor<Executor>::value |
158 | > = 0) noexcept |
159 | -> decltype(associated_executor<T, Executor>::get(t, ex)) |
160 | { |
161 | return associated_executor<T, Executor>::get(t, ex); |
162 | } |
163 | |
164 | /// Helper function to obtain an object's associated executor. |
165 | /** |
166 | * @returns <tt>associated_executor<T, typename |
167 | * ExecutionContext::executor_type>::get(t, ctx.get_executor())</tt> |
168 | */ |
169 | template <typename T, typename ExecutionContext> |
170 | BOOST_ASIO_NODISCARD inline typename associated_executor<T, |
171 | typename ExecutionContext::executor_type>::type |
172 | get_associated_executor(const T& t, ExecutionContext& ctx, |
173 | constraint_t<is_convertible<ExecutionContext&, |
174 | execution_context&>::value> = 0) noexcept |
175 | { |
176 | return associated_executor<T, |
177 | typename ExecutionContext::executor_type>::get(t, ctx.get_executor()); |
178 | } |
179 | |
180 | template <typename T, typename Executor = system_executor> |
181 | using associated_executor_t = typename associated_executor<T, Executor>::type; |
182 | |
183 | namespace detail { |
184 | |
185 | template <typename T, typename E, typename = void> |
186 | struct associated_executor_forwarding_base |
187 | { |
188 | }; |
189 | |
190 | template <typename T, typename E> |
191 | struct associated_executor_forwarding_base<T, E, |
192 | enable_if_t< |
193 | is_same< |
194 | typename associated_executor<T, |
195 | E>::asio_associated_executor_is_unspecialised, |
196 | void |
197 | >::value |
198 | >> |
199 | { |
200 | typedef void asio_associated_executor_is_unspecialised; |
201 | }; |
202 | |
203 | } // namespace detail |
204 | |
205 | /// Specialisation of associated_executor for @c std::reference_wrapper. |
206 | template <typename T, typename Executor> |
207 | struct associated_executor<reference_wrapper<T>, Executor> |
208 | #if !defined(GENERATING_DOCUMENTATION) |
209 | : detail::associated_executor_forwarding_base<T, Executor> |
210 | #endif // !defined(GENERATING_DOCUMENTATION) |
211 | { |
212 | /// Forwards @c type to the associator specialisation for the unwrapped type |
213 | /// @c T. |
214 | typedef typename associated_executor<T, Executor>::type type; |
215 | |
216 | /// Forwards the request to get the executor to the associator specialisation |
217 | /// for the unwrapped type @c T. |
218 | static type get(reference_wrapper<T> t) noexcept |
219 | { |
220 | return associated_executor<T, Executor>::get(t.get()); |
221 | } |
222 | |
223 | /// Forwards the request to get the executor to the associator specialisation |
224 | /// for the unwrapped type @c T. |
225 | static auto get(reference_wrapper<T> t, const Executor& ex) noexcept |
226 | -> decltype(associated_executor<T, Executor>::get(t.get(), ex)) |
227 | { |
228 | return associated_executor<T, Executor>::get(t.get(), ex); |
229 | } |
230 | }; |
231 | |
232 | } // namespace asio |
233 | } // namespace boost |
234 | |
235 | #include <boost/asio/detail/pop_options.hpp> |
236 | |
237 | #endif // BOOST_ASIO_ASSOCIATED_EXECUTOR_HPP |
238 | |