1 | // |
2 | // execution/prefer_only.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_EXECUTION_PREFER_ONLY_HPP |
12 | #define BOOST_ASIO_EXECUTION_PREFER_ONLY_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/detail/type_traits.hpp> |
20 | #include <boost/asio/is_applicable_property.hpp> |
21 | #include <boost/asio/prefer.hpp> |
22 | #include <boost/asio/query.hpp> |
23 | #include <boost/asio/traits/static_query.hpp> |
24 | |
25 | #include <boost/asio/detail/push_options.hpp> |
26 | |
27 | namespace boost { |
28 | namespace asio { |
29 | |
30 | #if defined(GENERATING_DOCUMENTATION) |
31 | |
32 | namespace execution { |
33 | |
34 | /// A property adapter that is used with the polymorphic executor wrapper |
35 | /// to mark properties as preferable, but not requirable. |
36 | template <typename Property> |
37 | struct prefer_only |
38 | { |
39 | /// The prefer_only adapter applies to the same types as the nested property. |
40 | template <typename T> |
41 | static constexpr bool is_applicable_property_v = |
42 | is_applicable_property<T, Property>::value; |
43 | |
44 | /// The context_t property cannot be required. |
45 | static constexpr bool is_requirable = false; |
46 | |
47 | /// The context_t property can be preferred, it the underlying property can |
48 | /// be preferred. |
49 | /** |
50 | * @c true if @c Property::is_preferable is @c true, otherwise @c false. |
51 | */ |
52 | static constexpr bool is_preferable = automatically_determined; |
53 | |
54 | /// The type returned by queries against an @c any_executor. |
55 | typedef typename Property::polymorphic_query_result_type |
56 | polymorphic_query_result_type; |
57 | }; |
58 | |
59 | } // namespace execution |
60 | |
61 | #else // defined(GENERATING_DOCUMENTATION) |
62 | |
63 | namespace execution { |
64 | namespace detail { |
65 | |
66 | template <typename InnerProperty, typename = void> |
67 | struct prefer_only_is_preferable |
68 | { |
69 | static constexpr bool is_preferable = false; |
70 | }; |
71 | |
72 | template <typename InnerProperty> |
73 | struct prefer_only_is_preferable<InnerProperty, |
74 | enable_if_t< |
75 | InnerProperty::is_preferable |
76 | > |
77 | > |
78 | { |
79 | static constexpr bool is_preferable = true; |
80 | }; |
81 | |
82 | template <typename InnerProperty, typename = void> |
83 | struct prefer_only_polymorphic_query_result_type |
84 | { |
85 | }; |
86 | |
87 | template <typename InnerProperty> |
88 | struct prefer_only_polymorphic_query_result_type<InnerProperty, |
89 | void_t< |
90 | typename InnerProperty::polymorphic_query_result_type |
91 | > |
92 | > |
93 | { |
94 | typedef typename InnerProperty::polymorphic_query_result_type |
95 | polymorphic_query_result_type; |
96 | }; |
97 | |
98 | template <typename InnerProperty, typename = void> |
99 | struct prefer_only_property |
100 | { |
101 | InnerProperty property; |
102 | |
103 | prefer_only_property(const InnerProperty& p) |
104 | : property(p) |
105 | { |
106 | } |
107 | }; |
108 | |
109 | #if defined(BOOST_ASIO_HAS_WORKING_EXPRESSION_SFINAE) |
110 | |
111 | template <typename InnerProperty> |
112 | struct prefer_only_property<InnerProperty, |
113 | void_t< |
114 | decltype(boost::asio::declval<const InnerProperty>().value()) |
115 | > |
116 | > |
117 | { |
118 | InnerProperty property; |
119 | |
120 | prefer_only_property(const InnerProperty& p) |
121 | : property(p) |
122 | { |
123 | } |
124 | |
125 | constexpr auto value() const |
126 | noexcept(noexcept(boost::asio::declval<const InnerProperty>().value())) |
127 | -> decltype(boost::asio::declval<const InnerProperty>().value()) |
128 | { |
129 | return property.value(); |
130 | } |
131 | }; |
132 | |
133 | #else // defined(BOOST_ASIO_HAS_WORKING_EXPRESSION_SFINAE) |
134 | |
135 | struct prefer_only_memfns_base |
136 | { |
137 | void value(); |
138 | }; |
139 | |
140 | template <typename T> |
141 | struct prefer_only_memfns_derived |
142 | : T, prefer_only_memfns_base |
143 | { |
144 | }; |
145 | |
146 | template <typename T, T> |
147 | struct prefer_only_memfns_check |
148 | { |
149 | }; |
150 | |
151 | template <typename> |
152 | char (&prefer_only_value_memfn_helper(...))[2]; |
153 | |
154 | template <typename T> |
155 | char prefer_only_value_memfn_helper( |
156 | prefer_only_memfns_check< |
157 | void (prefer_only_memfns_base::*)(), |
158 | &prefer_only_memfns_derived<T>::value>*); |
159 | |
160 | template <typename InnerProperty> |
161 | struct prefer_only_property<InnerProperty, |
162 | enable_if_t< |
163 | sizeof(prefer_only_value_memfn_helper<InnerProperty>(0)) != 1 |
164 | && !is_same<typename InnerProperty::polymorphic_query_result_type, |
165 | void>::value |
166 | > |
167 | > |
168 | { |
169 | InnerProperty property; |
170 | |
171 | prefer_only_property(const InnerProperty& p) |
172 | : property(p) |
173 | { |
174 | } |
175 | |
176 | constexpr typename InnerProperty::polymorphic_query_result_type |
177 | value() const |
178 | { |
179 | return property.value(); |
180 | } |
181 | }; |
182 | |
183 | #endif // defined(BOOST_ASIO_HAS_WORKING_EXPRESSION_SFINAE) |
184 | |
185 | } // namespace detail |
186 | |
187 | template <typename InnerProperty> |
188 | struct prefer_only : |
189 | detail::prefer_only_is_preferable<InnerProperty>, |
190 | detail::prefer_only_polymorphic_query_result_type<InnerProperty>, |
191 | detail::prefer_only_property<InnerProperty> |
192 | { |
193 | static constexpr bool is_requirable = false; |
194 | |
195 | constexpr prefer_only(const InnerProperty& p) |
196 | : detail::prefer_only_property<InnerProperty>(p) |
197 | { |
198 | } |
199 | |
200 | #if defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ |
201 | && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) |
202 | template <typename T> |
203 | static constexpr |
204 | typename traits::static_query<T, InnerProperty>::result_type |
205 | static_query() |
206 | noexcept(traits::static_query<T, InnerProperty>::is_noexcept) |
207 | { |
208 | return traits::static_query<T, InnerProperty>::value(); |
209 | } |
210 | |
211 | template <typename E, typename T = decltype(prefer_only::static_query<E>())> |
212 | static constexpr const T static_query_v |
213 | = prefer_only::static_query<E>(); |
214 | #endif // defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) |
215 | // && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) |
216 | |
217 | template <typename Executor, typename Property> |
218 | friend constexpr |
219 | prefer_result_t<const Executor&, const InnerProperty&> |
220 | prefer(const Executor& ex, const prefer_only<Property>& p, |
221 | enable_if_t< |
222 | is_same<Property, InnerProperty>::value |
223 | >* = 0, |
224 | enable_if_t< |
225 | can_prefer<const Executor&, const InnerProperty&>::value |
226 | >* = 0) |
227 | #if !defined(BOOST_ASIO_MSVC) \ |
228 | && !defined(__clang__) // Clang crashes if noexcept is used here. |
229 | noexcept(is_nothrow_prefer<const Executor&, const InnerProperty&>::value) |
230 | #endif // !defined(BOOST_ASIO_MSVC) |
231 | // && !defined(__clang__) |
232 | { |
233 | return boost::asio::prefer(ex, p.property); |
234 | } |
235 | |
236 | template <typename Executor, typename Property> |
237 | friend constexpr |
238 | query_result_t<const Executor&, const InnerProperty&> |
239 | query(const Executor& ex, const prefer_only<Property>& p, |
240 | enable_if_t< |
241 | is_same<Property, InnerProperty>::value |
242 | >* = 0, |
243 | enable_if_t< |
244 | can_query<const Executor&, const InnerProperty&>::value |
245 | >* = 0) |
246 | #if !defined(BOOST_ASIO_MSVC) \ |
247 | && !defined(__clang__) // Clang crashes if noexcept is used here. |
248 | noexcept(is_nothrow_query<const Executor&, const InnerProperty&>::value) |
249 | #endif // !defined(BOOST_ASIO_MSVC) |
250 | // && !defined(__clang__) |
251 | { |
252 | return boost::asio::query(ex, p.property); |
253 | } |
254 | }; |
255 | |
256 | #if defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ |
257 | && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) |
258 | template <typename InnerProperty> template <typename E, typename T> |
259 | const T prefer_only<InnerProperty>::static_query_v; |
260 | #endif // defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) |
261 | // && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) |
262 | |
263 | } // namespace execution |
264 | |
265 | template <typename T, typename InnerProperty> |
266 | struct is_applicable_property<T, execution::prefer_only<InnerProperty>> |
267 | : is_applicable_property<T, InnerProperty> |
268 | { |
269 | }; |
270 | |
271 | namespace traits { |
272 | |
273 | #if !defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ |
274 | || !defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) |
275 | |
276 | template <typename T, typename InnerProperty> |
277 | struct static_query<T, execution::prefer_only<InnerProperty>> : |
278 | static_query<T, const InnerProperty&> |
279 | { |
280 | }; |
281 | |
282 | #endif // !defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) |
283 | // || !defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) |
284 | |
285 | #if !defined(BOOST_ASIO_HAS_DEDUCED_PREFER_FREE_TRAIT) |
286 | |
287 | template <typename T, typename InnerProperty> |
288 | struct prefer_free_default<T, execution::prefer_only<InnerProperty>, |
289 | enable_if_t< |
290 | can_prefer<const T&, const InnerProperty&>::value |
291 | > |
292 | > |
293 | { |
294 | static constexpr bool is_valid = true; |
295 | static constexpr bool is_noexcept = |
296 | is_nothrow_prefer<const T&, const InnerProperty&>::value; |
297 | |
298 | typedef prefer_result_t<const T&, const InnerProperty&> result_type; |
299 | }; |
300 | |
301 | #endif // !defined(BOOST_ASIO_HAS_DEDUCED_PREFER_FREE_TRAIT) |
302 | |
303 | #if !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_FREE_TRAIT) |
304 | |
305 | template <typename T, typename InnerProperty> |
306 | struct query_free<T, execution::prefer_only<InnerProperty>, |
307 | enable_if_t< |
308 | can_query<const T&, const InnerProperty&>::value |
309 | > |
310 | > |
311 | { |
312 | static constexpr bool is_valid = true; |
313 | static constexpr bool is_noexcept = |
314 | is_nothrow_query<const T&, const InnerProperty&>::value; |
315 | |
316 | typedef query_result_t<const T&, const InnerProperty&> result_type; |
317 | }; |
318 | |
319 | #endif // !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_FREE_TRAIT) |
320 | |
321 | } // namespace traits |
322 | |
323 | #endif // defined(GENERATING_DOCUMENTATION) |
324 | |
325 | } // namespace asio |
326 | } // namespace boost |
327 | |
328 | #include <boost/asio/detail/pop_options.hpp> |
329 | |
330 | #endif // BOOST_ASIO_EXECUTION_PREFER_ONLY_HPP |
331 | |