1 | // |
2 | // prefer.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_PREFER_HPP |
12 | #define BOOST_ASIO_PREFER_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/traits/prefer_free.hpp> |
22 | #include <boost/asio/traits/prefer_member.hpp> |
23 | #include <boost/asio/traits/require_free.hpp> |
24 | #include <boost/asio/traits/require_member.hpp> |
25 | #include <boost/asio/traits/static_require.hpp> |
26 | |
27 | #include <boost/asio/detail/push_options.hpp> |
28 | |
29 | #if defined(GENERATING_DOCUMENTATION) |
30 | |
31 | namespace boost { |
32 | namespace asio { |
33 | |
34 | /// A customisation point that attempts to apply a property to an object. |
35 | /** |
36 | * The name <tt>prefer</tt> denotes a customisation point object. The |
37 | * expression <tt>boost::asio::prefer(E, P0, Pn...)</tt> for some subexpressions |
38 | * <tt>E</tt> and <tt>P0</tt>, and where <tt>Pn...</tt> represents <tt>N</tt> |
39 | * subexpressions (where <tt>N</tt> is 0 or more, and with types <tt>T = |
40 | * decay_t<decltype(E)></tt> and <tt>Prop0 = decay_t<decltype(P0)></tt>) is |
41 | * expression-equivalent to: |
42 | * |
43 | * @li If <tt>is_applicable_property_v<T, Prop0> && Prop0::is_preferable</tt> is |
44 | * not a well-formed constant expression with value <tt>true</tt>, |
45 | * <tt>boost::asio::prefer(E, P0, Pn...)</tt> is ill-formed. |
46 | * |
47 | * @li Otherwise, <tt>E</tt> if <tt>N == 0</tt> and the expression |
48 | * <tt>Prop0::template static_query_v<T> == Prop0::value()</tt> is a |
49 | * well-formed constant expression with value <tt>true</tt>. |
50 | * |
51 | * @li Otherwise, <tt>(E).require(P0)</tt> if <tt>N == 0</tt> and the expression |
52 | * <tt>(E).require(P0)</tt> is a valid expression. |
53 | * |
54 | * @li Otherwise, <tt>require(E, P0)</tt> if <tt>N == 0</tt> and the expression |
55 | * <tt>require(E, P0)</tt> is a valid expression with overload resolution |
56 | * performed in a context that does not include the declaration of the |
57 | * <tt>require</tt> customization point object. |
58 | * |
59 | * @li Otherwise, <tt>(E).prefer(P0)</tt> if <tt>N == 0</tt> and the expression |
60 | * <tt>(E).prefer(P0)</tt> is a valid expression. |
61 | * |
62 | * @li Otherwise, <tt>prefer(E, P0)</tt> if <tt>N == 0</tt> and the expression |
63 | * <tt>prefer(E, P0)</tt> is a valid expression with overload resolution |
64 | * performed in a context that does not include the declaration of the |
65 | * <tt>prefer</tt> customization point object. |
66 | * |
67 | * @li Otherwise, <tt>E</tt> if <tt>N == 0</tt>. |
68 | * |
69 | * @li Otherwise, |
70 | * <tt>boost::asio::prefer(boost::asio::prefer(E, P0), Pn...)</tt> |
71 | * if <tt>N > 0</tt> and the expression |
72 | * <tt>boost::asio::prefer(boost::asio::prefer(E, P0), Pn...)</tt> |
73 | * is a valid expression. |
74 | * |
75 | * @li Otherwise, <tt>boost::asio::prefer(E, P0, Pn...)</tt> is ill-formed. |
76 | */ |
77 | inline constexpr unspecified prefer = unspecified; |
78 | |
79 | /// A type trait that determines whether a @c prefer expression is well-formed. |
80 | /** |
81 | * Class template @c can_prefer is a trait that is derived from |
82 | * @c true_type if the expression <tt>boost::asio::prefer(std::declval<T>(), |
83 | * std::declval<Properties>()...)</tt> is well formed; otherwise @c false_type. |
84 | */ |
85 | template <typename T, typename... Properties> |
86 | struct can_prefer : |
87 | integral_constant<bool, automatically_determined> |
88 | { |
89 | }; |
90 | |
91 | /// A type trait that determines whether a @c prefer expression will not throw. |
92 | /** |
93 | * Class template @c is_nothrow_prefer is a trait that is derived from |
94 | * @c true_type if the expression <tt>boost::asio::prefer(std::declval<T>(), |
95 | * std::declval<Properties>()...)</tt> is @c noexcept; otherwise @c false_type. |
96 | */ |
97 | template <typename T, typename... Properties> |
98 | struct is_nothrow_prefer : |
99 | integral_constant<bool, automatically_determined> |
100 | { |
101 | }; |
102 | |
103 | /// A type trait that determines the result type of a @c prefer expression. |
104 | /** |
105 | * Class template @c prefer_result is a trait that determines the result |
106 | * type of the expression <tt>boost::asio::prefer(std::declval<T>(), |
107 | * std::declval<Properties>()...)</tt>. |
108 | */ |
109 | template <typename T, typename... Properties> |
110 | struct prefer_result |
111 | { |
112 | /// The result of the @c prefer expression. |
113 | typedef automatically_determined type; |
114 | }; |
115 | |
116 | } // namespace asio |
117 | } // namespace boost |
118 | |
119 | #else // defined(GENERATING_DOCUMENTATION) |
120 | |
121 | namespace boost_asio_prefer_fn { |
122 | |
123 | using boost::asio::conditional_t; |
124 | using boost::asio::decay_t; |
125 | using boost::asio::declval; |
126 | using boost::asio::enable_if_t; |
127 | using boost::asio::is_applicable_property; |
128 | using boost::asio::traits::prefer_free; |
129 | using boost::asio::traits::prefer_member; |
130 | using boost::asio::traits::require_free; |
131 | using boost::asio::traits::require_member; |
132 | using boost::asio::traits::static_require; |
133 | |
134 | void prefer(); |
135 | void require(); |
136 | |
137 | enum overload_type |
138 | { |
139 | identity, |
140 | call_require_member, |
141 | call_require_free, |
142 | call_prefer_member, |
143 | call_prefer_free, |
144 | two_props, |
145 | n_props, |
146 | ill_formed |
147 | }; |
148 | |
149 | template <typename Impl, typename T, typename Properties, |
150 | typename = void, typename = void, typename = void, typename = void, |
151 | typename = void, typename = void, typename = void> |
152 | struct call_traits |
153 | { |
154 | static constexpr overload_type overload = ill_formed; |
155 | static constexpr bool is_noexcept = false; |
156 | typedef void result_type; |
157 | }; |
158 | |
159 | template <typename Impl, typename T, typename Property> |
160 | struct call_traits<Impl, T, void(Property), |
161 | enable_if_t< |
162 | is_applicable_property< |
163 | decay_t<T>, |
164 | decay_t<Property> |
165 | >::value |
166 | >, |
167 | enable_if_t< |
168 | decay_t<Property>::is_preferable |
169 | >, |
170 | enable_if_t< |
171 | static_require<T, Property>::is_valid |
172 | >> |
173 | { |
174 | static constexpr overload_type overload = identity; |
175 | static constexpr bool is_noexcept = true; |
176 | |
177 | typedef T&& result_type; |
178 | }; |
179 | |
180 | template <typename Impl, typename T, typename Property> |
181 | struct call_traits<Impl, T, void(Property), |
182 | enable_if_t< |
183 | is_applicable_property< |
184 | decay_t<T>, |
185 | decay_t<Property> |
186 | >::value |
187 | >, |
188 | enable_if_t< |
189 | decay_t<Property>::is_preferable |
190 | >, |
191 | enable_if_t< |
192 | !static_require<T, Property>::is_valid |
193 | >, |
194 | enable_if_t< |
195 | require_member<typename Impl::template proxy<T>::type, Property>::is_valid |
196 | >> : |
197 | require_member<typename Impl::template proxy<T>::type, Property> |
198 | { |
199 | static constexpr overload_type overload = call_require_member; |
200 | }; |
201 | |
202 | template <typename Impl, typename T, typename Property> |
203 | struct call_traits<Impl, T, void(Property), |
204 | enable_if_t< |
205 | is_applicable_property< |
206 | decay_t<T>, |
207 | decay_t<Property> |
208 | >::value |
209 | >, |
210 | enable_if_t< |
211 | decay_t<Property>::is_preferable |
212 | >, |
213 | enable_if_t< |
214 | !static_require<T, Property>::is_valid |
215 | >, |
216 | enable_if_t< |
217 | !require_member<typename Impl::template proxy<T>::type, Property>::is_valid |
218 | >, |
219 | enable_if_t< |
220 | require_free<T, Property>::is_valid |
221 | >> : |
222 | require_free<T, Property> |
223 | { |
224 | static constexpr overload_type overload = call_require_free; |
225 | }; |
226 | |
227 | template <typename Impl, typename T, typename Property> |
228 | struct call_traits<Impl, T, void(Property), |
229 | enable_if_t< |
230 | is_applicable_property< |
231 | decay_t<T>, |
232 | decay_t<Property> |
233 | >::value |
234 | >, |
235 | enable_if_t< |
236 | decay_t<Property>::is_preferable |
237 | >, |
238 | enable_if_t< |
239 | !static_require<T, Property>::is_valid |
240 | >, |
241 | enable_if_t< |
242 | !require_member<typename Impl::template proxy<T>::type, Property>::is_valid |
243 | >, |
244 | enable_if_t< |
245 | !require_free<T, Property>::is_valid |
246 | >, |
247 | enable_if_t< |
248 | prefer_member<typename Impl::template proxy<T>::type, Property>::is_valid |
249 | >> : |
250 | prefer_member<typename Impl::template proxy<T>::type, Property> |
251 | { |
252 | static constexpr overload_type overload = call_prefer_member; |
253 | }; |
254 | |
255 | template <typename Impl, typename T, typename Property> |
256 | struct call_traits<Impl, T, void(Property), |
257 | enable_if_t< |
258 | is_applicable_property< |
259 | decay_t<T>, |
260 | decay_t<Property> |
261 | >::value |
262 | >, |
263 | enable_if_t< |
264 | decay_t<Property>::is_preferable |
265 | >, |
266 | enable_if_t< |
267 | !static_require<T, Property>::is_valid |
268 | >, |
269 | enable_if_t< |
270 | !require_member<typename Impl::template proxy<T>::type, Property>::is_valid |
271 | >, |
272 | enable_if_t< |
273 | !require_free<T, Property>::is_valid |
274 | >, |
275 | enable_if_t< |
276 | !prefer_member<typename Impl::template proxy<T>::type, Property>::is_valid |
277 | >, |
278 | enable_if_t< |
279 | prefer_free<T, Property>::is_valid |
280 | >> : |
281 | prefer_free<T, Property> |
282 | { |
283 | static constexpr overload_type overload = call_prefer_free; |
284 | }; |
285 | |
286 | template <typename Impl, typename T, typename Property> |
287 | struct call_traits<Impl, T, void(Property), |
288 | enable_if_t< |
289 | is_applicable_property< |
290 | decay_t<T>, |
291 | decay_t<Property> |
292 | >::value |
293 | >, |
294 | enable_if_t< |
295 | decay_t<Property>::is_preferable |
296 | >, |
297 | enable_if_t< |
298 | !static_require<T, Property>::is_valid |
299 | >, |
300 | enable_if_t< |
301 | !require_member<typename Impl::template proxy<T>::type, Property>::is_valid |
302 | >, |
303 | enable_if_t< |
304 | !require_free<T, Property>::is_valid |
305 | >, |
306 | enable_if_t< |
307 | !prefer_member<typename Impl::template proxy<T>::type, Property>::is_valid |
308 | >, |
309 | enable_if_t< |
310 | !prefer_free<T, Property>::is_valid |
311 | >> |
312 | { |
313 | static constexpr overload_type overload = identity; |
314 | static constexpr bool is_noexcept = true; |
315 | |
316 | typedef T&& result_type; |
317 | }; |
318 | |
319 | template <typename Impl, typename T, typename P0, typename P1> |
320 | struct call_traits<Impl, T, void(P0, P1), |
321 | enable_if_t< |
322 | call_traits<Impl, T, void(P0)>::overload != ill_formed |
323 | >, |
324 | enable_if_t< |
325 | call_traits< |
326 | Impl, |
327 | typename call_traits<Impl, T, void(P0)>::result_type, |
328 | void(P1) |
329 | >::overload != ill_formed |
330 | >> |
331 | { |
332 | static constexpr overload_type overload = two_props; |
333 | |
334 | static constexpr bool is_noexcept = |
335 | ( |
336 | call_traits<Impl, T, void(P0)>::is_noexcept |
337 | && |
338 | call_traits< |
339 | Impl, |
340 | typename call_traits<Impl, T, void(P0)>::result_type, |
341 | void(P1) |
342 | >::is_noexcept |
343 | ); |
344 | |
345 | typedef decay_t< |
346 | typename call_traits< |
347 | Impl, |
348 | typename call_traits<Impl, T, void(P0)>::result_type, |
349 | void(P1) |
350 | >::result_type |
351 | > result_type; |
352 | }; |
353 | |
354 | template <typename Impl, typename T, typename P0, |
355 | typename P1, typename... PN> |
356 | struct call_traits<Impl, T, void(P0, P1, PN...), |
357 | enable_if_t< |
358 | call_traits<Impl, T, void(P0)>::overload != ill_formed |
359 | >, |
360 | enable_if_t< |
361 | call_traits< |
362 | Impl, |
363 | typename call_traits<Impl, T, void(P0)>::result_type, |
364 | void(P1, PN...) |
365 | >::overload != ill_formed |
366 | >> |
367 | { |
368 | static constexpr overload_type overload = n_props; |
369 | |
370 | static constexpr bool is_noexcept = |
371 | ( |
372 | call_traits<Impl, T, void(P0)>::is_noexcept |
373 | && |
374 | call_traits< |
375 | Impl, |
376 | typename call_traits<Impl, T, void(P0)>::result_type, |
377 | void(P1, PN...) |
378 | >::is_noexcept |
379 | ); |
380 | |
381 | typedef decay_t< |
382 | typename call_traits< |
383 | Impl, |
384 | typename call_traits<Impl, T, void(P0)>::result_type, |
385 | void(P1, PN...) |
386 | >::result_type |
387 | > result_type; |
388 | }; |
389 | |
390 | struct impl |
391 | { |
392 | template <typename T> |
393 | struct proxy |
394 | { |
395 | #if defined(BOOST_ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT) \ |
396 | && defined(BOOST_ASIO_HAS_DEDUCED_PREFER_MEMBER_TRAIT) |
397 | struct type |
398 | { |
399 | template <typename P> |
400 | auto require(P&& p) |
401 | noexcept( |
402 | noexcept( |
403 | declval<conditional_t<true, T, P>>().require(static_cast<P&&>(p)) |
404 | ) |
405 | ) |
406 | -> decltype( |
407 | declval<conditional_t<true, T, P>>().require(static_cast<P&&>(p)) |
408 | ); |
409 | |
410 | template <typename P> |
411 | auto prefer(P&& p) |
412 | noexcept( |
413 | noexcept( |
414 | declval<conditional_t<true, T, P>>().prefer(static_cast<P&&>(p)) |
415 | ) |
416 | ) |
417 | -> decltype( |
418 | declval<conditional_t<true, T, P>>().prefer(static_cast<P&&>(p)) |
419 | ); |
420 | }; |
421 | #else // defined(BOOST_ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT) |
422 | // && defined(BOOST_ASIO_HAS_DEDUCED_PREFER_MEMBER_TRAIT) |
423 | typedef T type; |
424 | #endif // defined(BOOST_ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT) |
425 | // && defined(BOOST_ASIO_HAS_DEDUCED_PREFER_MEMBER_TRAIT) |
426 | }; |
427 | |
428 | template <typename T, typename Property> |
429 | BOOST_ASIO_NODISCARD constexpr enable_if_t< |
430 | call_traits<impl, T, void(Property)>::overload == identity, |
431 | typename call_traits<impl, T, void(Property)>::result_type |
432 | > |
433 | operator()(T&& t, Property&&) const |
434 | noexcept(call_traits<impl, T, void(Property)>::is_noexcept) |
435 | { |
436 | return static_cast<T&&>(t); |
437 | } |
438 | |
439 | template <typename T, typename Property> |
440 | BOOST_ASIO_NODISCARD constexpr enable_if_t< |
441 | call_traits<impl, T, void(Property)>::overload == call_require_member, |
442 | typename call_traits<impl, T, void(Property)>::result_type |
443 | > |
444 | operator()(T&& t, Property&& p) const |
445 | noexcept(call_traits<impl, T, void(Property)>::is_noexcept) |
446 | { |
447 | return static_cast<T&&>(t).require(static_cast<Property&&>(p)); |
448 | } |
449 | |
450 | template <typename T, typename Property> |
451 | BOOST_ASIO_NODISCARD constexpr enable_if_t< |
452 | call_traits<impl, T, void(Property)>::overload == call_require_free, |
453 | typename call_traits<impl, T, void(Property)>::result_type |
454 | > |
455 | operator()(T&& t, Property&& p) const |
456 | noexcept(call_traits<impl, T, void(Property)>::is_noexcept) |
457 | { |
458 | return require(static_cast<T&&>(t), static_cast<Property&&>(p)); |
459 | } |
460 | |
461 | template <typename T, typename Property> |
462 | BOOST_ASIO_NODISCARD constexpr enable_if_t< |
463 | call_traits<impl, T, void(Property)>::overload == call_prefer_member, |
464 | typename call_traits<impl, T, void(Property)>::result_type |
465 | > |
466 | operator()(T&& t, Property&& p) const |
467 | noexcept(call_traits<impl, T, void(Property)>::is_noexcept) |
468 | { |
469 | return static_cast<T&&>(t).prefer(static_cast<Property&&>(p)); |
470 | } |
471 | |
472 | template <typename T, typename Property> |
473 | BOOST_ASIO_NODISCARD constexpr enable_if_t< |
474 | call_traits<impl, T, void(Property)>::overload == call_prefer_free, |
475 | typename call_traits<impl, T, void(Property)>::result_type |
476 | > |
477 | operator()(T&& t, Property&& p) const |
478 | noexcept(call_traits<impl, T, void(Property)>::is_noexcept) |
479 | { |
480 | return prefer(static_cast<T&&>(t), static_cast<Property&&>(p)); |
481 | } |
482 | |
483 | template <typename T, typename P0, typename P1> |
484 | BOOST_ASIO_NODISCARD constexpr enable_if_t< |
485 | call_traits<impl, T, void(P0, P1)>::overload == two_props, |
486 | typename call_traits<impl, T, void(P0, P1)>::result_type |
487 | > |
488 | operator()(T&& t, P0&& p0, P1&& p1) const |
489 | noexcept(call_traits<impl, T, void(P0, P1)>::is_noexcept) |
490 | { |
491 | return (*this)( |
492 | (*this)(static_cast<T&&>(t), static_cast<P0&&>(p0)), |
493 | static_cast<P1&&>(p1)); |
494 | } |
495 | |
496 | template <typename T, typename P0, typename P1, |
497 | typename... PN> |
498 | BOOST_ASIO_NODISCARD constexpr enable_if_t< |
499 | call_traits<impl, T, void(P0, P1, PN...)>::overload == n_props, |
500 | typename call_traits<impl, T, void(P0, P1, PN...)>::result_type |
501 | > |
502 | operator()(T&& t, P0&& p0, P1&& p1, PN&&... pn) const |
503 | noexcept(call_traits<impl, T, void(P0, P1, PN...)>::is_noexcept) |
504 | { |
505 | return (*this)( |
506 | (*this)(static_cast<T&&>(t), static_cast<P0&&>(p0)), |
507 | static_cast<P1&&>(p1), static_cast<PN&&>(pn)...); |
508 | } |
509 | }; |
510 | |
511 | template <typename T = impl> |
512 | struct static_instance |
513 | { |
514 | static const T instance; |
515 | }; |
516 | |
517 | template <typename T> |
518 | const T static_instance<T>::instance = {}; |
519 | |
520 | } // namespace boost_asio_prefer_fn |
521 | namespace boost { |
522 | namespace asio { |
523 | namespace { |
524 | |
525 | static constexpr const boost_asio_prefer_fn::impl& |
526 | prefer = boost_asio_prefer_fn::static_instance<>::instance; |
527 | |
528 | } // namespace |
529 | |
530 | typedef boost_asio_prefer_fn::impl prefer_t; |
531 | |
532 | template <typename T, typename... Properties> |
533 | struct can_prefer : |
534 | integral_constant<bool, |
535 | boost_asio_prefer_fn::call_traits< |
536 | prefer_t, T, void(Properties...)>::overload |
537 | != boost_asio_prefer_fn::ill_formed> |
538 | { |
539 | }; |
540 | |
541 | #if defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) |
542 | |
543 | template <typename T, typename... Properties> |
544 | constexpr bool can_prefer_v |
545 | = can_prefer<T, Properties...>::value; |
546 | |
547 | #endif // defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) |
548 | |
549 | template <typename T, typename... Properties> |
550 | struct is_nothrow_prefer : |
551 | integral_constant<bool, |
552 | boost_asio_prefer_fn::call_traits< |
553 | prefer_t, T, void(Properties...)>::is_noexcept> |
554 | { |
555 | }; |
556 | |
557 | #if defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) |
558 | |
559 | template <typename T, typename... Properties> |
560 | constexpr bool is_nothrow_prefer_v = is_nothrow_prefer<T, Properties...>::value; |
561 | |
562 | #endif // defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) |
563 | |
564 | template <typename T, typename... Properties> |
565 | struct prefer_result |
566 | { |
567 | typedef typename boost_asio_prefer_fn::call_traits< |
568 | prefer_t, T, void(Properties...)>::result_type type; |
569 | }; |
570 | |
571 | template <typename T, typename... Properties> |
572 | using prefer_result_t = typename prefer_result<T, Properties...>::type; |
573 | |
574 | } // namespace asio |
575 | } // namespace boost |
576 | |
577 | #endif // defined(GENERATING_DOCUMENTATION) |
578 | |
579 | #include <boost/asio/detail/pop_options.hpp> |
580 | |
581 | #endif // BOOST_ASIO_PREFER_HPP |
582 | |