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