]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | /////////////////////////////////////////////////////////////////////////////// |
2 | /// \file make_expr.hpp | |
3 | /// Definition of the \c make_expr() and \c unpack_expr() utilities for | |
4 | /// building Proto expression nodes from child nodes or from a Fusion | |
5 | /// sequence of child nodes, respectively. | |
6 | // | |
7 | // Copyright 2008 Eric Niebler. Distributed under the Boost | |
8 | // Software License, Version 1.0. (See accompanying file | |
9 | // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) | |
10 | ||
11 | #ifndef BOOST_PROTO_MAKE_EXPR_HPP_EAN_04_01_2005 | |
12 | #define BOOST_PROTO_MAKE_EXPR_HPP_EAN_04_01_2005 | |
13 | ||
14 | #include <boost/preprocessor/cat.hpp> | |
15 | #include <boost/preprocessor/arithmetic/inc.hpp> | |
16 | #include <boost/preprocessor/arithmetic/dec.hpp> | |
17 | #include <boost/preprocessor/arithmetic/sub.hpp> | |
18 | #include <boost/preprocessor/punctuation/comma_if.hpp> | |
19 | #include <boost/preprocessor/iteration/iterate.hpp> | |
20 | #include <boost/preprocessor/facilities/intercept.hpp> | |
21 | #include <boost/preprocessor/repetition/enum.hpp> | |
22 | #include <boost/preprocessor/repetition/enum_params.hpp> | |
23 | #include <boost/preprocessor/repetition/enum_binary_params.hpp> | |
24 | #include <boost/preprocessor/repetition/enum_shifted_params.hpp> | |
25 | #include <boost/preprocessor/repetition/enum_trailing_params.hpp> | |
26 | #include <boost/preprocessor/repetition/enum_trailing_binary_params.hpp> | |
27 | #include <boost/preprocessor/repetition/repeat.hpp> | |
28 | #include <boost/ref.hpp> | |
29 | #include <boost/mpl/if.hpp> | |
30 | #include <boost/mpl/assert.hpp> | |
31 | #include <boost/mpl/eval_if.hpp> | |
32 | #include <boost/utility/enable_if.hpp> | |
33 | #include <boost/type_traits/add_const.hpp> | |
34 | #include <boost/type_traits/add_reference.hpp> | |
35 | #include <boost/type_traits/remove_cv.hpp> | |
36 | #include <boost/proto/proto_fwd.hpp> | |
37 | #include <boost/proto/traits.hpp> | |
38 | #include <boost/proto/domain.hpp> | |
39 | #include <boost/proto/generate.hpp> | |
40 | #include <boost/fusion/include/at_c.hpp> | |
41 | #include <boost/fusion/include/begin.hpp> | |
42 | #include <boost/fusion/include/next.hpp> | |
43 | #include <boost/fusion/include/value_of.hpp> | |
44 | #include <boost/fusion/include/size.hpp> | |
45 | #include <boost/proto/detail/poly_function.hpp> | |
46 | #include <boost/proto/detail/deprecated.hpp> | |
47 | ||
48 | #if defined(_MSC_VER) | |
49 | # pragma warning(push) | |
50 | # pragma warning(disable : 4180) // qualifier applied to function type has no meaning; ignored | |
51 | # pragma warning(disable : 4714) // function 'xxx' marked as __forceinline not inlined | |
52 | #endif | |
53 | ||
54 | namespace boost { namespace proto | |
55 | { | |
56 | /// INTERNAL ONLY | |
57 | /// | |
58 | #define BOOST_PROTO_AS_CHILD_TYPE(Z, N, DATA) \ | |
59 | typename boost::proto::detail::protoify< \ | |
60 | BOOST_PP_CAT(BOOST_PP_TUPLE_ELEM(3, 0, DATA), N) \ | |
61 | , BOOST_PP_TUPLE_ELEM(3, 2, DATA) \ | |
62 | >::result_type \ | |
63 | /**/ | |
64 | ||
65 | /// INTERNAL ONLY | |
66 | /// | |
67 | #define BOOST_PROTO_AS_CHILD(Z, N, DATA) \ | |
68 | boost::proto::detail::protoify< \ | |
69 | BOOST_PP_CAT(BOOST_PP_TUPLE_ELEM(3, 0, DATA), N) \ | |
70 | , BOOST_PP_TUPLE_ELEM(3, 2, DATA) \ | |
71 | >()(BOOST_PP_CAT(BOOST_PP_TUPLE_ELEM(3, 1, DATA), N)) \ | |
72 | /**/ | |
73 | ||
74 | namespace detail | |
75 | { | |
76 | template<typename T, typename Domain> | |
77 | struct protoify | |
78 | : Domain::template as_expr<T> | |
79 | {}; | |
80 | ||
81 | template<typename T, typename Domain> | |
82 | struct protoify<T &, Domain> | |
83 | : Domain::template as_child<T> | |
84 | {}; | |
85 | ||
86 | template<typename T, typename Domain> | |
87 | struct protoify<boost::reference_wrapper<T>, Domain> | |
88 | : Domain::template as_child<T> | |
89 | {}; | |
90 | ||
91 | template<typename T, typename Domain> | |
92 | struct protoify<boost::reference_wrapper<T> const, Domain> | |
93 | : Domain::template as_child<T> | |
94 | {}; | |
95 | ||
96 | // Definition of detail::unpack_expr_ | |
97 | #include <boost/proto/detail/unpack_expr_.hpp> | |
98 | ||
99 | // Definition of detail::make_expr_ | |
100 | #include <boost/proto/detail/make_expr_.hpp> | |
101 | } | |
102 | ||
103 | namespace result_of | |
104 | { | |
105 | /// \brief Metafunction that computes the return type of the | |
106 | /// \c make_expr() function, with a domain deduced from the | |
107 | /// domains of the children. | |
108 | /// | |
109 | /// Use the <tt>result_of::make_expr\<\></tt> metafunction to | |
110 | /// compute the return type of the \c make_expr() function. | |
111 | /// | |
112 | /// In this specialization, the domain is deduced from the | |
113 | /// domains of the child types. (If | |
114 | /// <tt>is_domain\<A0\>::value</tt> is \c true, then another | |
115 | /// specialization is selected.) | |
116 | template< | |
117 | typename Tag | |
118 | , BOOST_PP_ENUM_PARAMS(BOOST_PROTO_MAX_ARITY, typename A) | |
119 | , typename Void1 // = void | |
120 | , typename Void2 // = void | |
121 | > | |
122 | struct make_expr | |
123 | { | |
124 | /// Same as <tt>result_of::make_expr\<Tag, D, A0, ... AN\>::type</tt> | |
125 | /// where \c D is the deduced domain, which is calculated as follows: | |
126 | /// | |
127 | /// For each \c x in <tt>[0,N)</tt> (proceeding in order beginning with | |
128 | /// <tt>x=0</tt>), if <tt>domain_of\<Ax\>::type</tt> is not | |
129 | /// \c default_domain, then \c D is <tt>domain_of\<Ax\>::type</tt>. | |
130 | /// Otherwise, \c D is \c default_domain. | |
131 | typedef | |
132 | typename detail::make_expr_< | |
133 | Tag | |
134 | , deduce_domain | |
135 | BOOST_PP_ENUM_TRAILING_PARAMS(BOOST_PROTO_MAX_ARITY, A) | |
136 | >::result_type | |
137 | type; | |
138 | }; | |
139 | ||
140 | /// \brief Metafunction that computes the return type of the | |
141 | /// \c make_expr() function, within the specified domain. | |
142 | /// | |
143 | /// Use the <tt>result_of::make_expr\<\></tt> metafunction to compute | |
144 | /// the return type of the \c make_expr() function. | |
145 | template< | |
146 | typename Tag | |
147 | , typename Domain | |
148 | BOOST_PP_ENUM_TRAILING_PARAMS(BOOST_PROTO_MAX_ARITY, typename A) | |
149 | > | |
150 | struct make_expr< | |
151 | Tag | |
152 | , Domain | |
153 | BOOST_PP_ENUM_TRAILING_PARAMS(BOOST_PROTO_MAX_ARITY, A) | |
154 | , typename Domain::proto_is_domain_ | |
155 | > | |
156 | { | |
157 | /// If \c Tag is <tt>tag::terminal</tt>, then \c type is a | |
158 | /// typedef for <tt>boost::result_of\<Domain(expr\<tag::terminal, | |
159 | /// term\<A0\> \>)\>::type</tt>. | |
160 | /// | |
161 | /// Otherwise, \c type is a typedef for <tt>boost::result_of\<Domain(expr\<Tag, | |
162 | /// listN\< as_child\<A0\>::type, ... as_child\<AN\>::type\>) | |
163 | /// \>::type</tt>, where \c N is the number of non-void template | |
164 | /// arguments, and <tt>as_child\<A\>::type</tt> is evaluated as | |
165 | /// follows: | |
166 | /// | |
167 | /// \li If <tt>is_expr\<A\>::value</tt> is \c true, then the | |
168 | /// child type is \c A. | |
169 | /// \li If \c A is <tt>B &</tt> or <tt>cv boost::reference_wrapper\<B\></tt>, | |
170 | /// and <tt>is_expr\<B\>::value</tt> is \c true, then the | |
171 | /// child type is <tt>B &</tt>. | |
172 | /// \li If <tt>is_expr\<A\>::value</tt> is \c false, then the | |
173 | /// child type is <tt>boost::result_of\<Domain(expr\<tag::terminal, term\<A\> \> | |
174 | /// )\>::type</tt>. | |
175 | /// \li If \c A is <tt>B &</tt> or <tt>cv boost::reference_wrapper\<B\></tt>, | |
176 | /// and <tt>is_expr\<B\>::value</tt> is \c false, then the | |
177 | /// child type is <tt>boost::result_of\<Domain(expr\<tag::terminal, term\<B &\> \> | |
178 | /// )\>::type</tt>. | |
179 | typedef | |
180 | typename detail::make_expr_< | |
181 | Tag | |
182 | , Domain | |
183 | BOOST_PP_ENUM_TRAILING_PARAMS(BOOST_PROTO_MAX_ARITY, A) | |
184 | >::result_type | |
185 | type; | |
186 | }; | |
187 | ||
188 | /// \brief Metafunction that computes the return type of the | |
189 | /// \c unpack_expr() function, with a domain deduced from the | |
190 | /// domains of the children. | |
191 | /// | |
192 | /// Use the <tt>result_of::unpack_expr\<\></tt> metafunction to | |
193 | /// compute the return type of the \c unpack_expr() function. | |
194 | /// | |
195 | /// \c Sequence is a Fusion Forward Sequence. | |
196 | /// | |
197 | /// In this specialization, the domain is deduced from the | |
198 | /// domains of the child types. (If | |
199 | /// <tt>is_domain\<Sequence>::value</tt> is \c true, then another | |
200 | /// specialization is selected.) | |
201 | template< | |
202 | typename Tag | |
203 | , typename Sequence | |
204 | , typename Void1 // = void | |
205 | , typename Void2 // = void | |
206 | > | |
207 | struct unpack_expr | |
208 | { | |
209 | /// Let \c S be the type of a Fusion Random Access Sequence | |
210 | /// equivalent to \c Sequence. Then \c type is the | |
211 | /// same as <tt>result_of::make_expr\<Tag, | |
212 | /// fusion::result_of::value_at_c\<S, 0\>::type, ... | |
213 | /// fusion::result_of::value_at_c\<S, N-1\>::type\>::type</tt>, | |
214 | /// where \c N is the size of \c S. | |
215 | typedef | |
216 | typename detail::unpack_expr_< | |
217 | Tag | |
218 | , deduce_domain | |
219 | , Sequence | |
220 | , fusion::result_of::size<Sequence>::type::value | |
221 | >::type | |
222 | type; | |
223 | }; | |
224 | ||
225 | /// \brief Metafunction that computes the return type of the | |
226 | /// \c unpack_expr() function, within the specified domain. | |
227 | /// | |
228 | /// Use the <tt>result_of::make_expr\<\></tt> metafunction to compute | |
229 | /// the return type of the \c make_expr() function. | |
230 | template<typename Tag, typename Domain, typename Sequence> | |
231 | struct unpack_expr<Tag, Domain, Sequence, typename Domain::proto_is_domain_> | |
232 | { | |
233 | /// Let \c S be the type of a Fusion Random Access Sequence | |
234 | /// equivalent to \c Sequence. Then \c type is the | |
235 | /// same as <tt>result_of::make_expr\<Tag, Domain, | |
236 | /// fusion::result_of::value_at_c\<S, 0\>::type, ... | |
237 | /// fusion::result_of::value_at_c\<S, N-1\>::type\>::type</tt>, | |
238 | /// where \c N is the size of \c S. | |
239 | typedef | |
240 | typename detail::unpack_expr_< | |
241 | Tag | |
242 | , Domain | |
243 | , Sequence | |
244 | , fusion::result_of::size<Sequence>::type::value | |
245 | >::type | |
246 | type; | |
247 | }; | |
248 | } | |
249 | ||
250 | namespace functional | |
251 | { | |
252 | /// \brief A callable function object equivalent to the | |
253 | /// \c proto::make_expr() function. | |
254 | /// | |
255 | /// In all cases, <tt>functional::make_expr\<Tag, Domain\>()(a0, ... aN)</tt> | |
256 | /// is equivalent to <tt>proto::make_expr\<Tag, Domain\>(a0, ... aN)</tt>. | |
257 | /// | |
258 | /// <tt>functional::make_expr\<Tag\>()(a0, ... aN)</tt> | |
259 | /// is equivalent to <tt>proto::make_expr\<Tag\>(a0, ... aN)</tt>. | |
260 | template<typename Tag, typename Domain /* = deduce_domain*/> | |
261 | struct make_expr | |
262 | { | |
263 | BOOST_PROTO_CALLABLE() | |
264 | BOOST_PROTO_POLY_FUNCTION() | |
265 | ||
266 | template<typename Sig> | |
267 | struct result; | |
268 | ||
269 | template<typename This, typename A0> | |
270 | struct result<This(A0)> | |
271 | { | |
272 | typedef | |
273 | typename result_of::make_expr< | |
274 | Tag | |
275 | , Domain | |
276 | , A0 | |
277 | >::type | |
278 | type; | |
279 | }; | |
280 | ||
281 | /// Construct an expression node with tag type \c Tag | |
282 | /// and in the domain \c Domain. | |
283 | /// | |
284 | /// \return <tt>proto::make_expr\<Tag, Domain\>(a0,...aN)</tt> | |
285 | template<typename A0> | |
286 | BOOST_FORCEINLINE | |
287 | typename result_of::make_expr< | |
288 | Tag | |
289 | , Domain | |
290 | , A0 const | |
291 | >::type const | |
292 | operator ()(A0 const &a0) const | |
293 | { | |
294 | return proto::detail::make_expr_< | |
295 | Tag | |
296 | , Domain | |
297 | , A0 const | |
298 | >()(a0); | |
299 | } | |
300 | ||
301 | // Additional overloads generated by the preprocessor ... | |
302 | #include <boost/proto/detail/make_expr_funop.hpp> | |
303 | ||
304 | /// INTERNAL ONLY | |
305 | /// | |
306 | template< | |
307 | BOOST_PP_ENUM_BINARY_PARAMS( | |
308 | BOOST_PROTO_MAX_ARITY | |
309 | , typename A | |
310 | , = void BOOST_PP_INTERCEPT | |
311 | ) | |
312 | > | |
313 | struct impl | |
314 | : detail::make_expr_< | |
315 | Tag | |
316 | , Domain | |
317 | BOOST_PP_ENUM_TRAILING_PARAMS(BOOST_PROTO_MAX_ARITY, A) | |
318 | > | |
319 | {}; | |
320 | }; | |
321 | ||
322 | /// \brief A callable function object equivalent to the | |
323 | /// \c proto::unpack_expr() function. | |
324 | /// | |
325 | /// In all cases, <tt>functional::unpack_expr\<Tag, Domain\>()(seq)</tt> | |
326 | /// is equivalent to <tt>proto::unpack_expr\<Tag, Domain\>(seq)</tt>. | |
327 | /// | |
328 | /// <tt>functional::unpack_expr\<Tag\>()(seq)</tt> | |
329 | /// is equivalent to <tt>proto::unpack_expr\<Tag\>(seq)</tt>. | |
330 | template<typename Tag, typename Domain /* = deduce_domain*/> | |
331 | struct unpack_expr | |
332 | { | |
333 | BOOST_PROTO_CALLABLE() | |
334 | ||
335 | template<typename Sig> | |
336 | struct result; | |
337 | ||
338 | template<typename This, typename Sequence> | |
339 | struct result<This(Sequence)> | |
340 | { | |
341 | typedef | |
342 | typename result_of::unpack_expr< | |
343 | Tag | |
344 | , Domain | |
345 | , typename remove_reference<Sequence>::type | |
346 | >::type | |
347 | type; | |
348 | }; | |
349 | ||
350 | /// Construct an expression node with tag type \c Tag | |
351 | /// and in the domain \c Domain. | |
352 | /// | |
353 | /// \param sequence A Fusion Forward Sequence | |
354 | /// \return <tt>proto::unpack_expr\<Tag, Domain\>(sequence)</tt> | |
355 | template<typename Sequence> | |
356 | BOOST_FORCEINLINE | |
357 | typename result_of::unpack_expr<Tag, Domain, Sequence const>::type const | |
358 | operator ()(Sequence const &sequence) const | |
359 | { | |
360 | return proto::detail::unpack_expr_< | |
361 | Tag | |
362 | , Domain | |
363 | , Sequence const | |
364 | , fusion::result_of::size<Sequence>::type::value | |
365 | >::call(sequence); | |
366 | } | |
367 | }; | |
368 | ||
369 | } // namespace functional | |
370 | ||
371 | /// \brief Construct an expression of the requested tag type | |
372 | /// with a domain and with the specified arguments as children. | |
373 | /// | |
374 | /// This function template may be invoked either with or without | |
375 | /// specifying a \c Domain argument. If no domain is specified, | |
376 | /// the domain is deduced by examining in order the domains of | |
377 | /// the given arguments and taking the first that is not | |
378 | /// \c default_domain, if any such domain exists, or | |
379 | /// \c default_domain otherwise. | |
380 | /// | |
381 | /// Let \c wrap_(x) be defined such that: | |
382 | /// \li If \c x is a <tt>boost::reference_wrapper\<\></tt>, | |
383 | /// \c wrap_(x) is equivalent to <tt>as_child\<Domain\>(x.get())</tt>. | |
384 | /// \li Otherwise, \c wrap_(x) is equivalent to | |
385 | /// <tt>as_expr\<Domain\>(x)</tt>. | |
386 | /// | |
387 | /// Let <tt>make_\<Tag\>(b0,...bN)</tt> be defined as | |
388 | /// <tt>expr\<Tag, listN\<C0,...CN\> \>::make(c0,...cN)</tt> | |
389 | /// where \c Bx is the type of \c bx. | |
390 | /// | |
391 | /// \return <tt>Domain()(make_\<Tag\>(wrap_(a0),...wrap_(aN)))</tt>. | |
392 | template<typename Tag, typename A0> | |
393 | BOOST_FORCEINLINE | |
394 | typename lazy_disable_if< | |
395 | is_domain<A0> | |
396 | , result_of::make_expr< | |
397 | Tag | |
398 | , A0 const | |
399 | > | |
400 | >::type const | |
401 | make_expr(A0 const &a0) | |
402 | { | |
403 | return proto::detail::make_expr_< | |
404 | Tag | |
405 | , deduce_domain | |
406 | , A0 const | |
407 | >()(a0); | |
408 | } | |
409 | ||
410 | /// \overload | |
411 | /// | |
412 | template<typename Tag, typename Domain, typename C0> | |
413 | BOOST_FORCEINLINE | |
414 | typename result_of::make_expr< | |
415 | Tag | |
416 | , Domain | |
417 | , C0 const | |
418 | >::type const | |
419 | make_expr(C0 const &c0) | |
420 | { | |
421 | return proto::detail::make_expr_< | |
422 | Tag | |
423 | , Domain | |
424 | , C0 const | |
425 | >()(c0); | |
426 | } | |
427 | ||
428 | // Additional overloads generated by the preprocessor... | |
429 | #include <boost/proto/detail/make_expr.hpp> | |
430 | ||
431 | /// \brief Construct an expression of the requested tag type | |
432 | /// with a domain and with childres from the specified Fusion | |
433 | /// Forward Sequence. | |
434 | /// | |
435 | /// This function template may be invoked either with or without | |
436 | /// specifying a \c Domain argument. If no domain is specified, | |
437 | /// the domain is deduced by examining in order the domains of the | |
438 | /// elements of \c sequence and taking the first that is not | |
439 | /// \c default_domain, if any such domain exists, or | |
440 | /// \c default_domain otherwise. | |
441 | /// | |
442 | /// Let \c s be a Fusion Random Access Sequence equivalent to \c sequence. | |
443 | /// Let <tt>wrap_\<N\>(s)</tt>, where \c s has type \c S, be defined | |
444 | /// such that: | |
445 | /// \li If <tt>fusion::result_of::value_at_c\<S,N\>::type</tt> is a reference, | |
446 | /// <tt>wrap_\<N\>(s)</tt> is equivalent to | |
447 | /// <tt>as_child\<Domain\>(fusion::at_c\<N\>(s))</tt>. | |
448 | /// \li Otherwise, <tt>wrap_\<N\>(s)</tt> is equivalent to | |
449 | /// <tt>as_expr\<Domain\>(fusion::at_c\<N\>(s))</tt>. | |
450 | /// | |
451 | /// Let <tt>make_\<Tag\>(b0,...bN)</tt> be defined as | |
452 | /// <tt>expr\<Tag, listN\<B0,...BN\> \>::make(b0,...bN)</tt> | |
453 | /// where \c Bx is the type of \c bx. | |
454 | /// | |
455 | /// \param sequence a Fusion Forward Sequence. | |
456 | /// \return <tt>Domain()(make_\<Tag\>(wrap_\<0\>(s),...wrap_\<N-1\>(s)))</tt>, | |
457 | /// where N is the size of \c Sequence. | |
458 | template<typename Tag, typename Sequence> | |
459 | BOOST_FORCEINLINE | |
460 | typename lazy_disable_if< | |
461 | is_domain<Sequence> | |
462 | , result_of::unpack_expr<Tag, Sequence const> | |
463 | >::type const | |
464 | unpack_expr(Sequence const &sequence) | |
465 | { | |
466 | return proto::detail::unpack_expr_< | |
467 | Tag | |
468 | , deduce_domain | |
469 | , Sequence const | |
470 | , fusion::result_of::size<Sequence>::type::value | |
471 | >::call(sequence); | |
472 | } | |
473 | ||
474 | /// \overload | |
475 | /// | |
476 | template<typename Tag, typename Domain, typename Sequence2> | |
477 | BOOST_FORCEINLINE | |
478 | typename result_of::unpack_expr<Tag, Domain, Sequence2 const>::type const | |
479 | unpack_expr(Sequence2 const &sequence2) | |
480 | { | |
481 | return proto::detail::unpack_expr_< | |
482 | Tag | |
483 | , Domain | |
484 | , Sequence2 const | |
485 | , fusion::result_of::size<Sequence2>::type::value | |
486 | >::call(sequence2); | |
487 | } | |
488 | ||
489 | /// INTERNAL ONLY | |
490 | /// | |
491 | template<typename Tag, typename Domain> | |
492 | struct is_callable<functional::make_expr<Tag, Domain> > | |
493 | : mpl::true_ | |
494 | {}; | |
495 | ||
496 | /// INTERNAL ONLY | |
497 | /// | |
498 | template<typename Tag, typename Domain> | |
499 | struct is_callable<functional::unpack_expr<Tag, Domain> > | |
500 | : mpl::true_ | |
501 | {}; | |
502 | ||
503 | }} | |
504 | ||
505 | #if defined(_MSC_VER) | |
506 | # pragma warning(pop) | |
507 | #endif | |
508 | ||
509 | #endif // BOOST_PROTO_MAKE_EXPR_HPP_EAN_04_01_2005 |