1 //
2 // execution/prefer_only.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_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   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_preferable = false);
70 };
71 
72 template <typename InnerProperty>
73 struct prefer_only_is_preferable<InnerProperty,
74     typename enable_if<
75       InnerProperty::is_preferable
76     >::type>
77 {
78   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_preferable = true);
79 };
80 
81 template <typename InnerProperty, typename = void>
82 struct prefer_only_polymorphic_query_result_type
83 {
84 };
85 
86 template <typename InnerProperty>
87 struct prefer_only_polymorphic_query_result_type<InnerProperty,
88     typename void_type<
89       typename InnerProperty::polymorphic_query_result_type
90     >::type>
91 {
92   typedef typename InnerProperty::polymorphic_query_result_type
93     polymorphic_query_result_type;
94 };
95 
96 template <typename InnerProperty, typename = void>
97 struct prefer_only_property
98 {
99   InnerProperty property;
100 
101   prefer_only_property(const InnerProperty& p)
102     : property(p)
103   {
104   }
105 };
106 
107 #if defined(BOOST_ASIO_HAS_DECLTYPE) \
108   && defined(BOOST_ASIO_HAS_WORKING_EXPRESSION_SFINAE)
109 
110 template <typename InnerProperty>
111 struct prefer_only_property<InnerProperty,
112     typename void_type<
113       decltype(boost::asio::declval<const InnerProperty>().value())
114     >::type>
115 {
116   InnerProperty property;
117 
118   prefer_only_property(const InnerProperty& p)
119     : property(p)
120   {
121   }
122 
123   BOOST_ASIO_CONSTEXPR auto value() const
124     BOOST_ASIO_NOEXCEPT_IF((
125       noexcept(boost::asio::declval<const InnerProperty>().value())))
126     -> decltype(boost::asio::declval<const InnerProperty>().value())
127   {
128     return property.value();
129   }
130 };
131 
132 #else // defined(BOOST_ASIO_HAS_DECLTYPE)
133       //   && 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     typename enable_if<
163       sizeof(prefer_only_value_memfn_helper<InnerProperty>(0)) != 1
164         && !is_same<typename InnerProperty::polymorphic_query_result_type,
165           void>::value
166     >::type>
167 {
168   InnerProperty property;
169 
170   prefer_only_property(const InnerProperty& p)
171     : property(p)
172   {
173   }
174 
175   BOOST_ASIO_CONSTEXPR typename InnerProperty::polymorphic_query_result_type
176   value() const
177   {
178     return property.value();
179   }
180 };
181 
182 #endif // defined(BOOST_ASIO_HAS_DECLTYPE)
183        //   && 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   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_requirable = false);
194 
195   BOOST_ASIO_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 BOOST_ASIO_CONSTEXPR
204   typename traits::static_query<T, InnerProperty>::result_type
205   static_query()
206     BOOST_ASIO_NOEXCEPT_IF((
207       traits::static_query<T, InnerProperty>::is_noexcept))
208   {
209     return traits::static_query<T, InnerProperty>::value();
210   }
211 
212   template <typename E, typename T = decltype(prefer_only::static_query<E>())>
213   static BOOST_ASIO_CONSTEXPR const T static_query_v
214     = prefer_only::static_query<E>();
215 #endif // defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)
216        //   && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
217 
218   template <typename Executor, typename Property>
219   friend BOOST_ASIO_CONSTEXPR
220   typename prefer_result<const Executor&, const InnerProperty&>::type
221   prefer(const Executor& ex, const prefer_only<Property>& p,
222       typename enable_if<
223         is_same<Property, InnerProperty>::value
224       >::type* = 0,
225       typename enable_if<
226         can_prefer<const Executor&, const InnerProperty&>::value
227       >::type* = 0)
228 #if !defined(BOOST_ASIO_MSVC) \
229   && !defined(__clang__) // Clang crashes if noexcept is used here.
230     BOOST_ASIO_NOEXCEPT_IF((
231       is_nothrow_prefer<const Executor&, const InnerProperty&>::value))
232 #endif // !defined(BOOST_ASIO_MSVC)
233        //   && !defined(__clang__)
234   {
235     return boost::asio::prefer(ex, p.property);
236   }
237 
238   template <typename Executor, typename Property>
239   friend BOOST_ASIO_CONSTEXPR
240   typename query_result<const Executor&, const InnerProperty&>::type
241   query(const Executor& ex, const prefer_only<Property>& p,
242       typename enable_if<
243         is_same<Property, InnerProperty>::value
244       >::type* = 0,
245       typename enable_if<
246         can_query<const Executor&, const InnerProperty&>::value
247       >::type* = 0)
248 #if !defined(BOOST_ASIO_MSVC) \
249   && !defined(__clang__) // Clang crashes if noexcept is used here.
250     BOOST_ASIO_NOEXCEPT_IF((
251       is_nothrow_query<const Executor&, const InnerProperty&>::value))
252 #endif // !defined(BOOST_ASIO_MSVC)
253        //   && !defined(__clang__)
254   {
255     return boost::asio::query(ex, p.property);
256   }
257 };
258 
259 #if defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \
260   && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
261 template <typename InnerProperty> template <typename E, typename T>
262 const T prefer_only<InnerProperty>::static_query_v;
263 #endif // defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)
264        //   && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
265 
266 } // namespace execution
267 
268 template <typename T, typename InnerProperty>
269 struct is_applicable_property<T, execution::prefer_only<InnerProperty> >
270   : is_applicable_property<T, InnerProperty>
271 {
272 };
273 
274 namespace traits {
275 
276 #if !defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \
277   || !defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
278 
279 template <typename T, typename InnerProperty>
280 struct static_query<T, execution::prefer_only<InnerProperty> > :
281   static_query<T, const InnerProperty&>
282 {
283 };
284 
285 #endif // !defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)
286        //   || !defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
287 
288 #if !defined(BOOST_ASIO_HAS_DEDUCED_PREFER_FREE_TRAIT)
289 
290 template <typename T, typename InnerProperty>
291 struct prefer_free_default<T, execution::prefer_only<InnerProperty>,
292     typename enable_if<
293       can_prefer<const T&, const InnerProperty&>::value
294     >::type>
295 {
296   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
297   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept =
298     (is_nothrow_prefer<const T&, const InnerProperty&>::value));
299 
300   typedef typename prefer_result<const T&,
301       const InnerProperty&>::type result_type;
302 };
303 
304 #endif // !defined(BOOST_ASIO_HAS_DEDUCED_PREFER_FREE_TRAIT)
305 
306 #if !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_FREE_TRAIT)
307 
308 template <typename T, typename InnerProperty>
309 struct query_free<T, execution::prefer_only<InnerProperty>,
310     typename enable_if<
311       can_query<const T&, const InnerProperty&>::value
312     >::type>
313 {
314   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
315   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept =
316     (is_nothrow_query<const T&, const InnerProperty&>::value));
317 
318   typedef typename query_result<const T&,
319       const InnerProperty&>::type result_type;
320 };
321 
322 #endif // !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_FREE_TRAIT)
323 
324 } // namespace traits
325 
326 #endif // defined(GENERATING_DOCUMENTATION)
327 
328 } // namespace asio
329 } // namespace boost
330 
331 #include <boost/asio/detail/pop_options.hpp>
332 
333 #endif // BOOST_ASIO_EXECUTION_PREFER_ONLY_HPP
334