1 //
2 // query.hpp
3 // ~~~~~~~~~
4 //
5 // Copyright (c) 2003-2020 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::decay;
106 using boost::asio::declval;
107 using boost::asio::enable_if;
108 using boost::asio::is_applicable_property;
109 using boost::asio::traits::query_free;
110 using boost::asio::traits::query_member;
111 using boost::asio::traits::static_query;
112 
113 void query();
114 
115 enum overload_type
116 {
117   static_value,
118   call_member,
119   call_free,
120   ill_formed
121 };
122 
123 template <typename T, typename Properties, typename = void>
124 struct call_traits
125 {
126   BOOST_ASIO_STATIC_CONSTEXPR(overload_type, overload = ill_formed);
127   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
128   typedef void result_type;
129 };
130 
131 template <typename T, typename Property>
132 struct call_traits<T, void(Property),
133   typename enable_if<
134     (
135       is_applicable_property<
136         typename decay<T>::type,
137         typename decay<Property>::type
138       >::value
139       &&
140       static_query<T, Property>::is_valid
141     )
142   >::type> :
143   static_query<T, Property>
144 {
145   BOOST_ASIO_STATIC_CONSTEXPR(overload_type, overload = static_value);
146 };
147 
148 template <typename T, typename Property>
149 struct call_traits<T, void(Property),
150   typename enable_if<
151     (
152       is_applicable_property<
153         typename decay<T>::type,
154         typename decay<Property>::type
155       >::value
156       &&
157       !static_query<T, Property>::is_valid
158       &&
159       query_member<T, Property>::is_valid
160     )
161   >::type> :
162   query_member<T, Property>
163 {
164   BOOST_ASIO_STATIC_CONSTEXPR(overload_type, overload = call_member);
165 };
166 
167 template <typename T, typename Property>
168 struct call_traits<T, void(Property),
169   typename enable_if<
170     (
171       is_applicable_property<
172         typename decay<T>::type,
173         typename decay<Property>::type
174       >::value
175       &&
176       !static_query<T, Property>::is_valid
177       &&
178       !query_member<T, Property>::is_valid
179       &&
180       query_free<T, Property>::is_valid
181     )
182   >::type> :
183   query_free<T, Property>
184 {
185   BOOST_ASIO_STATIC_CONSTEXPR(overload_type, overload = call_free);
186 };
187 
188 struct impl
189 {
190   template <typename T, typename Property>
191   BOOST_ASIO_NODISCARD BOOST_ASIO_CONSTEXPR typename enable_if<
192     call_traits<T, void(Property)>::overload == static_value,
193     typename call_traits<T, void(Property)>::result_type
194   >::type
operator ()asio_query_fn::impl195   operator()(
196       BOOST_ASIO_MOVE_ARG(T),
197       BOOST_ASIO_MOVE_ARG(Property)) const
198     BOOST_ASIO_NOEXCEPT_IF((
199       call_traits<T, void(Property)>::is_noexcept))
200   {
201     return static_query<
202       typename decay<T>::type,
203       typename decay<Property>::type
204     >::value();
205   }
206 
207   template <typename T, typename Property>
208   BOOST_ASIO_NODISCARD BOOST_ASIO_CONSTEXPR typename enable_if<
209     call_traits<T, void(Property)>::overload == call_member,
210     typename call_traits<T, void(Property)>::result_type
211   >::type
operator ()asio_query_fn::impl212   operator()(
213       BOOST_ASIO_MOVE_ARG(T) t,
214       BOOST_ASIO_MOVE_ARG(Property) p) const
215     BOOST_ASIO_NOEXCEPT_IF((
216       call_traits<T, void(Property)>::is_noexcept))
217   {
218     return BOOST_ASIO_MOVE_CAST(T)(t).query(BOOST_ASIO_MOVE_CAST(Property)(p));
219   }
220 
221   template <typename T, typename Property>
222   BOOST_ASIO_NODISCARD BOOST_ASIO_CONSTEXPR typename enable_if<
223     call_traits<T, void(Property)>::overload == call_free,
224     typename call_traits<T, void(Property)>::result_type
225   >::type
operator ()asio_query_fn::impl226   operator()(
227       BOOST_ASIO_MOVE_ARG(T) t,
228       BOOST_ASIO_MOVE_ARG(Property) p) const
229     BOOST_ASIO_NOEXCEPT_IF((
230       call_traits<T, void(Property)>::is_noexcept))
231   {
232     return query(BOOST_ASIO_MOVE_CAST(T)(t), BOOST_ASIO_MOVE_CAST(Property)(p));
233   }
234 };
235 
236 template <typename T = impl>
237 struct static_instance
238 {
239   static const T instance;
240 };
241 
242 template <typename T>
243 const T static_instance<T>::instance = {};
244 
245 } // namespace asio_query_fn
246 namespace boost {
247 namespace asio {
248 namespace {
249 
250 static BOOST_ASIO_CONSTEXPR const asio_query_fn::impl&
251   query = asio_query_fn::static_instance<>::instance;
252 
253 } // namespace
254 
255 template <typename T, typename Property>
256 struct can_query :
257   integral_constant<bool,
258     asio_query_fn::call_traits<T, void(Property)>::overload !=
259       asio_query_fn::ill_formed>
260 {
261 };
262 
263 #if defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES)
264 
265 template <typename T, typename Property>
266 constexpr bool can_query_v
267   = can_query<T, Property>::value;
268 
269 #endif // defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES)
270 
271 template <typename T, typename Property>
272 struct is_nothrow_query :
273   integral_constant<bool,
274     asio_query_fn::call_traits<T, void(Property)>::is_noexcept>
275 {
276 };
277 
278 #if defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES)
279 
280 template <typename T, typename Property>
281 constexpr bool is_nothrow_query_v
282   = is_nothrow_query<T, Property>::value;
283 
284 #endif // defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES)
285 
286 template <typename T, typename Property>
287 struct query_result
288 {
289   typedef typename asio_query_fn::call_traits<
290       T, void(Property)>::result_type type;
291 };
292 
293 } // namespace asio
294 } // namespace boost
295 
296 #endif // defined(GENERATING_DOCUMENTATION)
297 
298 #include <boost/asio/detail/pop_options.hpp>
299 
300 #endif // BOOST_ASIO_QUERY_HPP
301