1 | // |
2 | // require_concept.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_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 boost_asio_require_concept_fn { |
111 | |
112 | using boost::asio::conditional_t; |
113 | using boost::asio::decay_t; |
114 | using boost::asio::declval; |
115 | using boost::asio::enable_if_t; |
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 | static constexpr overload_type overload = ill_formed; |
136 | 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 | enable_if_t< |
143 | is_applicable_property< |
144 | decay_t<T>, |
145 | decay_t<Property> |
146 | >::value |
147 | >, |
148 | enable_if_t< |
149 | decay_t<Property>::is_requirable_concept |
150 | >, |
151 | enable_if_t< |
152 | static_require_concept<T, Property>::is_valid |
153 | >> |
154 | { |
155 | static constexpr overload_type overload = identity; |
156 | static constexpr bool is_noexcept = true; |
157 | typedef T&& result_type; |
158 | }; |
159 | |
160 | template <typename Impl, typename T, typename Property> |
161 | struct call_traits<Impl, T, void(Property), |
162 | enable_if_t< |
163 | is_applicable_property< |
164 | decay_t<T>, |
165 | decay_t<Property> |
166 | >::value |
167 | >, |
168 | enable_if_t< |
169 | decay_t<Property>::is_requirable_concept |
170 | >, |
171 | enable_if_t< |
172 | !static_require_concept<T, Property>::is_valid |
173 | >, |
174 | enable_if_t< |
175 | require_concept_member< |
176 | typename Impl::template proxy<T>::type, |
177 | Property |
178 | >::is_valid |
179 | >> : |
180 | require_concept_member< |
181 | typename Impl::template proxy<T>::type, |
182 | Property |
183 | > |
184 | { |
185 | 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 | enable_if_t< |
191 | is_applicable_property< |
192 | decay_t<T>, |
193 | decay_t<Property> |
194 | >::value |
195 | >, |
196 | enable_if_t< |
197 | decay_t<Property>::is_requirable_concept |
198 | >, |
199 | enable_if_t< |
200 | !static_require_concept<T, Property>::is_valid |
201 | >, |
202 | enable_if_t< |
203 | !require_concept_member< |
204 | typename Impl::template proxy<T>::type, |
205 | Property |
206 | >::is_valid |
207 | >, |
208 | enable_if_t< |
209 | require_concept_free<T, Property>::is_valid |
210 | >> : |
211 | require_concept_free<T, Property> |
212 | { |
213 | 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(P&& p) |
226 | noexcept( |
227 | noexcept( |
228 | declval<conditional_t<true, T, P>>().require_concept( |
229 | static_cast<P&&>(p)) |
230 | ) |
231 | ) |
232 | -> decltype( |
233 | declval<conditional_t<true, T, P>>().require_concept( |
234 | static_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 constexpr enable_if_t< |
244 | call_traits<impl, T, void(Property)>::overload == identity, |
245 | typename call_traits<impl, T, void(Property)>::result_type |
246 | > |
247 | operator()(T&& t, Property&&) const |
248 | noexcept(call_traits<impl, T, void(Property)>::is_noexcept) |
249 | { |
250 | return static_cast<T&&>(t); |
251 | } |
252 | |
253 | template <typename T, typename Property> |
254 | BOOST_ASIO_NODISCARD constexpr enable_if_t< |
255 | call_traits<impl, T, void(Property)>::overload == call_member, |
256 | typename call_traits<impl, T, void(Property)>::result_type |
257 | > |
258 | operator()(T&& t, Property&& p) const |
259 | noexcept(call_traits<impl, T, void(Property)>::is_noexcept) |
260 | { |
261 | return static_cast<T&&>(t).require_concept(static_cast<Property&&>(p)); |
262 | } |
263 | |
264 | template <typename T, typename Property> |
265 | BOOST_ASIO_NODISCARD constexpr enable_if_t< |
266 | call_traits<impl, T, void(Property)>::overload == call_free, |
267 | typename call_traits<impl, T, void(Property)>::result_type |
268 | > |
269 | operator()(T&& t, Property&& p) const |
270 | noexcept(call_traits<impl, T, void(Property)>::is_noexcept) |
271 | { |
272 | return require_concept(static_cast<T&&>(t), static_cast<Property&&>(p)); |
273 | } |
274 | }; |
275 | |
276 | template <typename T = impl> |
277 | struct static_instance |
278 | { |
279 | static const T instance; |
280 | }; |
281 | |
282 | template <typename T> |
283 | const T static_instance<T>::instance = {}; |
284 | |
285 | } // namespace boost_asio_require_concept_fn |
286 | namespace boost { |
287 | namespace asio { |
288 | namespace { |
289 | |
290 | static constexpr const boost_asio_require_concept_fn::impl& |
291 | require_concept = boost_asio_require_concept_fn::static_instance<>::instance; |
292 | |
293 | } // namespace |
294 | |
295 | typedef boost_asio_require_concept_fn::impl require_concept_t; |
296 | |
297 | template <typename T, typename Property> |
298 | struct can_require_concept : |
299 | integral_constant<bool, |
300 | boost_asio_require_concept_fn::call_traits< |
301 | require_concept_t, T, void(Property)>::overload != |
302 | boost_asio_require_concept_fn::ill_formed> |
303 | { |
304 | }; |
305 | |
306 | #if defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) |
307 | |
308 | template <typename T, typename Property> |
309 | constexpr bool can_require_concept_v = can_require_concept<T, Property>::value; |
310 | |
311 | #endif // defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) |
312 | |
313 | template <typename T, typename Property> |
314 | struct is_nothrow_require_concept : |
315 | integral_constant<bool, |
316 | boost_asio_require_concept_fn::call_traits< |
317 | require_concept_t, T, void(Property)>::is_noexcept> |
318 | { |
319 | }; |
320 | |
321 | #if defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) |
322 | |
323 | template <typename T, typename Property> |
324 | constexpr bool is_nothrow_require_concept_v |
325 | = is_nothrow_require_concept<T, Property>::value; |
326 | |
327 | #endif // defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) |
328 | |
329 | template <typename T, typename Property> |
330 | struct require_concept_result |
331 | { |
332 | typedef typename boost_asio_require_concept_fn::call_traits< |
333 | require_concept_t, T, void(Property)>::result_type type; |
334 | }; |
335 | |
336 | template <typename T, typename Property> |
337 | using require_concept_result_t = |
338 | typename require_concept_result<T, Property>::type; |
339 | |
340 | } // namespace asio |
341 | } // namespace boost |
342 | |
343 | #endif // defined(GENERATING_DOCUMENTATION) |
344 | |
345 | #include <boost/asio/detail/pop_options.hpp> |
346 | |
347 | #endif // BOOST_ASIO_REQUIRE_CONCEPT_HPP |
348 | |