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