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