1 //
2 // require_concept.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_CONCEPT_HPP
12 #define BOOST_ASIO_REQUIRE_CONCEPT_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_concept_member.hpp>
22 #include <boost/asio/traits/require_concept_free.hpp>
23 #include <boost/asio/traits/static_require_concept.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-enforcing property to an
33 /// object.
34 /**
35  * The name <tt>require_concept</tt> denotes a customization point object. The
36  * expression <tt>boost::asio::require_concept(E, P)</tt> for some
37  * subexpressions <tt>E</tt> and <tt>P</tt> (with types <tt>T =
38  * decay_t<decltype(E)></tt> and <tt>Prop = decay_t<decltype(P)></tt>) is
39  * expression-equivalent to:
40  *
41  * @li If <tt>is_applicable_property_v<T, Prop> &&
42  *   Prop::is_requirable_concept</tt> is not a well-formed constant expression
43  *   with value <tt>true</tt>, <tt>boost::asio::require_concept(E, P)</tt> is
44  *   ill-formed.
45  *
46  * @li Otherwise, <tt>E</tt> if the expression <tt>Prop::template
47  *   static_query_v<T> == Prop::value()</tt> is a well-formed constant
48  *   expression with value <tt>true</tt>.
49  *
50  * @li Otherwise, <tt>(E).require_concept(P)</tt> if the expression
51  *   <tt>(E).require_concept(P)</tt> is well-formed.
52  *
53  * @li Otherwise, <tt>require_concept(E, P)</tt> if the expression
54  *   <tt>require_concept(E, P)</tt> is a valid expression with overload
55  *   resolution performed in a context that does not include the declaration
56  *   of the <tt>require_concept</tt> customization point object.
57  *
58  * @li Otherwise, <tt>boost::asio::require_concept(E, P)</tt> is ill-formed.
59  */
60 inline constexpr unspecified require_concept = unspecified;
61 
62 /// A type trait that determines whether a @c require_concept expression is
63 /// well-formed.
64 /**
65  * Class template @c can_require_concept is a trait that is derived from
66  * @c true_type if the expression
67  * <tt>boost::asio::require_concept(std::declval<T>(),
68  * std::declval<Property>())</tt> is well formed; otherwise @c false_type.
69  */
70 template <typename T, typename Property>
71 struct can_require_concept :
72   integral_constant<bool, automatically_determined>
73 {
74 };
75 
76 /// A type trait that determines whether a @c require_concept expression will
77 /// not throw.
78 /**
79  * Class template @c is_nothrow_require_concept is a trait that is derived from
80  * @c true_type if the expression
81  * <tt>boost::asio::require_concept(std::declval<T>(),
82  * std::declval<Property>())</tt> is @c noexcept; otherwise @c false_type.
83  */
84 template <typename T, typename Property>
85 struct is_nothrow_require_concept :
86   integral_constant<bool, automatically_determined>
87 {
88 };
89 
90 /// A type trait that determines the result type of a @c require_concept
91 /// expression.
92 /**
93  * Class template @c require_concept_result is a trait that determines the
94  * result type of the expression
95  * <tt>boost::asio::require_concept(std::declval<T>(),
96  * std::declval<Property>())</tt>.
97  */
98 template <typename T, typename Property>
99 struct require_concept_result
100 {
101   /// The result of the @c require_concept 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_concept_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_concept_free;
118 using boost::asio::traits::require_concept_member;
119 using boost::asio::traits::static_require_concept;
120 
121 void require_concept();
122 
123 enum overload_type
124 {
125   identity,
126   call_member,
127   call_free,
128   ill_formed
129 };
130 
131 template <typename Impl, typename T, typename Properties, typename = void,
132     typename = void, typename = void, typename = void, typename = void>
133 struct call_traits
134 {
135   BOOST_ASIO_STATIC_CONSTEXPR(overload_type, overload = ill_formed);
136   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
137   typedef void result_type;
138 };
139 
140 template <typename Impl, typename T, typename Property>
141 struct call_traits<Impl, T, void(Property),
142   typename enable_if<
143     is_applicable_property<
144       typename decay<T>::type,
145       typename decay<Property>::type
146     >::value
147   >::type,
148   typename enable_if<
149     decay<Property>::type::is_requirable_concept
150   >::type,
151   typename enable_if<
152     static_require_concept<T, Property>::is_valid
153   >::type>
154 {
155   BOOST_ASIO_STATIC_CONSTEXPR(overload_type, overload = identity);
156   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
157   typedef BOOST_ASIO_MOVE_ARG(T) result_type;
158 };
159 
160 template <typename Impl, typename T, typename Property>
161 struct call_traits<Impl, T, void(Property),
162   typename enable_if<
163     is_applicable_property<
164       typename decay<T>::type,
165       typename decay<Property>::type
166     >::value
167   >::type,
168   typename enable_if<
169     decay<Property>::type::is_requirable_concept
170   >::type,
171   typename enable_if<
172     !static_require_concept<T, Property>::is_valid
173   >::type,
174   typename enable_if<
175     require_concept_member<
176       typename Impl::template proxy<T>::type,
177       Property
178     >::is_valid
179   >::type> :
180   require_concept_member<
181     typename Impl::template proxy<T>::type,
182     Property
183   >
184 {
185   BOOST_ASIO_STATIC_CONSTEXPR(overload_type, overload = call_member);
186 };
187 
188 template <typename Impl, typename T, typename Property>
189 struct call_traits<Impl, T, void(Property),
190   typename enable_if<
191     is_applicable_property<
192       typename decay<T>::type,
193       typename decay<Property>::type
194     >::value
195   >::type,
196   typename enable_if<
197     decay<Property>::type::is_requirable_concept
198   >::type,
199   typename enable_if<
200     !static_require_concept<T, Property>::is_valid
201   >::type,
202   typename enable_if<
203     !require_concept_member<
204       typename Impl::template proxy<T>::type,
205       Property
206     >::is_valid
207   >::type,
208   typename enable_if<
209     require_concept_free<T, Property>::is_valid
210   >::type> :
211   require_concept_free<T, Property>
212 {
213   BOOST_ASIO_STATIC_CONSTEXPR(overload_type, overload = call_free);
214 };
215 
216 struct impl
217 {
218   template <typename T>
219   struct proxy
220   {
221 #if defined(BOOST_ASIO_HAS_DEDUCED_REQUIRE_CONCEPT_MEMBER_TRAIT)
222     struct type
223     {
224       template <typename P>
225       auto require_concept(BOOST_ASIO_MOVE_ARG(P) p)
226         noexcept(
227           noexcept(
228             declval<typename conditional<true, T, P>::type>().require_concept(
229               BOOST_ASIO_MOVE_CAST(P)(p))
230           )
231         )
232         -> decltype(
233           declval<typename conditional<true, T, P>::type>().require_concept(
234             BOOST_ASIO_MOVE_CAST(P)(p))
235         );
236     };
237 #else // defined(BOOST_ASIO_HAS_DEDUCED_REQUIRE_CONCEPT_MEMBER_TRAIT)
238     typedef T type;
239 #endif // defined(BOOST_ASIO_HAS_DEDUCED_REQUIRE_CONCEPT_MEMBER_TRAIT)
240   };
241 
242   template <typename T, typename Property>
243   BOOST_ASIO_NODISCARD BOOST_ASIO_CONSTEXPR typename enable_if<
244     call_traits<impl, T, void(Property)>::overload == identity,
245     typename call_traits<impl, T, void(Property)>::result_type
246   >::type
operator ()asio_require_concept_fn::impl247   operator()(
248       BOOST_ASIO_MOVE_ARG(T) t,
249       BOOST_ASIO_MOVE_ARG(Property)) const
250     BOOST_ASIO_NOEXCEPT_IF((
251       call_traits<impl, T, void(Property)>::is_noexcept))
252   {
253     return BOOST_ASIO_MOVE_CAST(T)(t);
254   }
255 
256   template <typename T, typename Property>
257   BOOST_ASIO_NODISCARD BOOST_ASIO_CONSTEXPR typename enable_if<
258     call_traits<impl, T, void(Property)>::overload == call_member,
259     typename call_traits<impl, T, void(Property)>::result_type
260   >::type
operator ()asio_require_concept_fn::impl261   operator()(
262       BOOST_ASIO_MOVE_ARG(T) t,
263       BOOST_ASIO_MOVE_ARG(Property) p) const
264     BOOST_ASIO_NOEXCEPT_IF((
265       call_traits<impl, T, void(Property)>::is_noexcept))
266   {
267     return BOOST_ASIO_MOVE_CAST(T)(t).require_concept(
268         BOOST_ASIO_MOVE_CAST(Property)(p));
269   }
270 
271   template <typename T, typename Property>
272   BOOST_ASIO_NODISCARD BOOST_ASIO_CONSTEXPR typename enable_if<
273     call_traits<impl, T, void(Property)>::overload == call_free,
274     typename call_traits<impl, T, void(Property)>::result_type
275   >::type
operator ()asio_require_concept_fn::impl276   operator()(
277       BOOST_ASIO_MOVE_ARG(T) t,
278       BOOST_ASIO_MOVE_ARG(Property) p) const
279     BOOST_ASIO_NOEXCEPT_IF((
280       call_traits<impl, T, void(Property)>::is_noexcept))
281   {
282     return require_concept(
283         BOOST_ASIO_MOVE_CAST(T)(t),
284         BOOST_ASIO_MOVE_CAST(Property)(p));
285   }
286 };
287 
288 template <typename T = impl>
289 struct static_instance
290 {
291   static const T instance;
292 };
293 
294 template <typename T>
295 const T static_instance<T>::instance = {};
296 
297 } // namespace asio_require_concept_fn
298 namespace boost {
299 namespace asio {
300 namespace {
301 
302 static BOOST_ASIO_CONSTEXPR const asio_require_concept_fn::impl&
303   require_concept = asio_require_concept_fn::static_instance<>::instance;
304 
305 } // namespace
306 
307 typedef asio_require_concept_fn::impl require_concept_t;
308 
309 template <typename T, typename Property>
310 struct can_require_concept :
311   integral_constant<bool,
312     asio_require_concept_fn::call_traits<
313       require_concept_t, T, void(Property)>::overload !=
314         asio_require_concept_fn::ill_formed>
315 {
316 };
317 
318 #if defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES)
319 
320 template <typename T, typename Property>
321 constexpr bool can_require_concept_v
322   = can_require_concept<T, Property>::value;
323 
324 #endif // defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES)
325 
326 template <typename T, typename Property>
327 struct is_nothrow_require_concept :
328   integral_constant<bool,
329     asio_require_concept_fn::call_traits<
330       require_concept_t, T, void(Property)>::is_noexcept>
331 {
332 };
333 
334 #if defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES)
335 
336 template <typename T, typename Property>
337 constexpr bool is_nothrow_require_concept_v
338   = is_nothrow_require_concept<T, Property>::value;
339 
340 #endif // defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES)
341 
342 template <typename T, typename Property>
343 struct require_concept_result
344 {
345   typedef typename asio_require_concept_fn::call_traits<
346       require_concept_t, T, void(Property)>::result_type type;
347 };
348 
349 } // namespace asio
350 } // namespace boost
351 
352 #endif // defined(GENERATING_DOCUMENTATION)
353 
354 #include <boost/asio/detail/pop_options.hpp>
355 
356 #endif // BOOST_ASIO_REQUIRE_CONCEPT_HPP
357