]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | /////////////////////////////////////////////////////////////////////////////// |
2 | /// \file default.hpp | |
3 | /// Definintion of default_context, a default evaluation context for | |
4 | /// proto::eval() that uses Boost.Typeof to deduce return types | |
5 | /// of the built-in operators. | |
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_CONTEXT_DEFAULT_HPP_EAN_01_08_2007 | |
12 | #define BOOST_PROTO_CONTEXT_DEFAULT_HPP_EAN_01_08_2007 | |
13 | ||
14 | #include <boost/config.hpp> | |
15 | #include <boost/preprocessor/arithmetic/add.hpp> | |
16 | #include <boost/preprocessor/arithmetic/sub.hpp> | |
17 | #include <boost/preprocessor/iteration/iterate.hpp> | |
18 | #include <boost/preprocessor/repetition/enum.hpp> | |
19 | #include <boost/preprocessor/repetition/enum_shifted.hpp> | |
20 | #include <boost/utility/result_of.hpp> | |
21 | #include <boost/type_traits/is_const.hpp> | |
22 | #include <boost/type_traits/is_function.hpp> | |
23 | #include <boost/type_traits/remove_reference.hpp> | |
24 | #include <boost/type_traits/is_member_pointer.hpp> | |
25 | #include <boost/type_traits/is_member_object_pointer.hpp> | |
26 | #include <boost/type_traits/is_member_function_pointer.hpp> | |
27 | #include <boost/proto/proto_fwd.hpp> | |
28 | #include <boost/proto/tags.hpp> | |
29 | #include <boost/proto/eval.hpp> | |
30 | #include <boost/proto/traits.hpp> // for proto::child_c() | |
31 | #include <boost/proto/detail/decltype.hpp> | |
32 | ||
33 | namespace boost { namespace proto | |
34 | { | |
35 | /// INTERNAL ONLY | |
36 | /// | |
37 | #define UNREF(x) typename boost::remove_reference<x>::type | |
38 | ||
39 | namespace context | |
40 | { | |
41 | template< | |
42 | typename Expr | |
43 | , typename Context | |
44 | , typename Tag // = typename Expr::proto_tag | |
45 | , long Arity // = Expr::proto_arity_c | |
46 | > | |
47 | struct default_eval | |
48 | {}; | |
49 | ||
50 | template<typename Expr, typename Context> | |
51 | struct default_eval<Expr, Context, tag::terminal, 0> | |
52 | { | |
53 | typedef | |
54 | typename proto::result_of::value<Expr &>::type | |
55 | result_type; | |
56 | ||
57 | result_type operator ()(Expr &expr, Context &) const | |
58 | { | |
59 | return proto::value(expr); | |
60 | } | |
61 | }; | |
62 | ||
63 | /// INTERNAL ONLY | |
64 | /// | |
65 | #define BOOST_PROTO_UNARY_DEFAULT_EVAL(OP, TAG, MAKE) \ | |
66 | template<typename Expr, typename Context> \ | |
67 | struct default_eval<Expr, Context, TAG, 1> \ | |
68 | { \ | |
69 | private: \ | |
70 | typedef typename proto::result_of::child_c<Expr, 0>::type e0; \ | |
71 | typedef typename proto::result_of::eval<UNREF(e0), Context>::type r0; \ | |
72 | public: \ | |
73 | BOOST_PROTO_DECLTYPE_(OP proto::detail::MAKE<r0>(), result_type) \ | |
74 | result_type operator ()(Expr &expr, Context &ctx) const \ | |
75 | { \ | |
76 | return OP proto::eval(proto::child_c<0>(expr), ctx); \ | |
77 | } \ | |
78 | }; \ | |
79 | /**/ | |
80 | ||
81 | /// INTERNAL ONLY | |
82 | /// | |
83 | #define BOOST_PROTO_BINARY_DEFAULT_EVAL(OP, TAG, LMAKE, RMAKE) \ | |
84 | template<typename Expr, typename Context> \ | |
85 | struct default_eval<Expr, Context, TAG, 2> \ | |
86 | { \ | |
87 | private: \ | |
88 | typedef typename proto::result_of::child_c<Expr, 0>::type e0; \ | |
89 | typedef typename proto::result_of::child_c<Expr, 1>::type e1; \ | |
90 | typedef typename proto::result_of::eval<UNREF(e0), Context>::type r0; \ | |
91 | typedef typename proto::result_of::eval<UNREF(e1), Context>::type r1; \ | |
92 | public: \ | |
93 | BOOST_PROTO_DECLTYPE_( \ | |
94 | proto::detail::LMAKE<r0>() OP proto::detail::RMAKE<r1>() \ | |
95 | , result_type \ | |
96 | ) \ | |
97 | result_type operator ()(Expr &expr, Context &ctx) const \ | |
98 | { \ | |
99 | return proto::eval( \ | |
100 | proto::child_c<0>(expr), ctx) OP proto::eval(proto::child_c<1>(expr) \ | |
101 | , ctx \ | |
102 | ); \ | |
103 | } \ | |
104 | }; \ | |
105 | /**/ | |
106 | ||
107 | BOOST_PROTO_UNARY_DEFAULT_EVAL(+, proto::tag::unary_plus, make) | |
108 | BOOST_PROTO_UNARY_DEFAULT_EVAL(-, proto::tag::negate, make) | |
109 | BOOST_PROTO_UNARY_DEFAULT_EVAL(*, proto::tag::dereference, make) | |
110 | BOOST_PROTO_UNARY_DEFAULT_EVAL(~, proto::tag::complement, make) | |
111 | BOOST_PROTO_UNARY_DEFAULT_EVAL(&, proto::tag::address_of, make) | |
112 | BOOST_PROTO_UNARY_DEFAULT_EVAL(!, proto::tag::logical_not, make) | |
113 | BOOST_PROTO_UNARY_DEFAULT_EVAL(++, proto::tag::pre_inc, make_mutable) | |
114 | BOOST_PROTO_UNARY_DEFAULT_EVAL(--, proto::tag::pre_dec, make_mutable) | |
115 | ||
116 | BOOST_PROTO_BINARY_DEFAULT_EVAL(<<, proto::tag::shift_left, make_mutable, make) | |
117 | BOOST_PROTO_BINARY_DEFAULT_EVAL(>>, proto::tag::shift_right, make_mutable, make) | |
118 | BOOST_PROTO_BINARY_DEFAULT_EVAL(*, proto::tag::multiplies, make, make) | |
119 | BOOST_PROTO_BINARY_DEFAULT_EVAL(/, proto::tag::divides, make, make) | |
120 | BOOST_PROTO_BINARY_DEFAULT_EVAL(%, proto::tag::modulus, make, make) | |
121 | BOOST_PROTO_BINARY_DEFAULT_EVAL(+, proto::tag::plus, make, make) | |
122 | BOOST_PROTO_BINARY_DEFAULT_EVAL(-, proto::tag::minus, make, make) | |
123 | BOOST_PROTO_BINARY_DEFAULT_EVAL(<, proto::tag::less, make, make) | |
124 | BOOST_PROTO_BINARY_DEFAULT_EVAL(>, proto::tag::greater, make, make) | |
125 | BOOST_PROTO_BINARY_DEFAULT_EVAL(<=, proto::tag::less_equal, make, make) | |
126 | BOOST_PROTO_BINARY_DEFAULT_EVAL(>=, proto::tag::greater_equal, make, make) | |
127 | BOOST_PROTO_BINARY_DEFAULT_EVAL(==, proto::tag::equal_to, make, make) | |
128 | BOOST_PROTO_BINARY_DEFAULT_EVAL(!=, proto::tag::not_equal_to, make, make) | |
129 | BOOST_PROTO_BINARY_DEFAULT_EVAL(||, proto::tag::logical_or, make, make) | |
130 | BOOST_PROTO_BINARY_DEFAULT_EVAL(&&, proto::tag::logical_and, make, make) | |
131 | BOOST_PROTO_BINARY_DEFAULT_EVAL(&, proto::tag::bitwise_and, make, make) | |
132 | BOOST_PROTO_BINARY_DEFAULT_EVAL(|, proto::tag::bitwise_or, make, make) | |
133 | BOOST_PROTO_BINARY_DEFAULT_EVAL(^, proto::tag::bitwise_xor, make, make) | |
134 | ||
135 | BOOST_PROTO_BINARY_DEFAULT_EVAL(=, proto::tag::assign, make_mutable, make) | |
136 | BOOST_PROTO_BINARY_DEFAULT_EVAL(<<=, proto::tag::shift_left_assign, make_mutable, make) | |
137 | BOOST_PROTO_BINARY_DEFAULT_EVAL(>>=, proto::tag::shift_right_assign, make_mutable, make) | |
138 | BOOST_PROTO_BINARY_DEFAULT_EVAL(*=, proto::tag::multiplies_assign, make_mutable, make) | |
139 | BOOST_PROTO_BINARY_DEFAULT_EVAL(/=, proto::tag::divides_assign, make_mutable, make) | |
140 | BOOST_PROTO_BINARY_DEFAULT_EVAL(%=, proto::tag::modulus_assign, make_mutable, make) | |
141 | BOOST_PROTO_BINARY_DEFAULT_EVAL(+=, proto::tag::plus_assign, make_mutable, make) | |
142 | BOOST_PROTO_BINARY_DEFAULT_EVAL(-=, proto::tag::minus_assign, make_mutable, make) | |
143 | BOOST_PROTO_BINARY_DEFAULT_EVAL(&=, proto::tag::bitwise_and_assign, make_mutable, make) | |
144 | BOOST_PROTO_BINARY_DEFAULT_EVAL(|=, proto::tag::bitwise_or_assign, make_mutable, make) | |
145 | BOOST_PROTO_BINARY_DEFAULT_EVAL(^=, proto::tag::bitwise_xor_assign, make_mutable, make) | |
146 | ||
147 | #undef BOOST_PROTO_UNARY_DEFAULT_EVAL | |
148 | #undef BOOST_PROTO_BINARY_DEFAULT_EVAL | |
149 | ||
150 | /// INTERNAL ONLY | |
151 | template<typename Expr, typename Context> | |
152 | struct is_member_function_eval | |
153 | : is_member_function_pointer< | |
154 | typename detail::uncvref< | |
155 | typename proto::result_of::eval< | |
156 | typename remove_reference< | |
157 | typename proto::result_of::child_c<Expr, 1>::type | |
158 | >::type | |
159 | , Context | |
160 | >::type | |
161 | >::type | |
162 | > | |
163 | {}; | |
164 | ||
165 | /// INTERNAL ONLY | |
166 | template<typename Expr, typename Context, bool IsMemFunCall> | |
167 | struct memfun_eval | |
168 | { | |
169 | private: | |
170 | typedef typename result_of::child_c<Expr, 0>::type e0; | |
171 | typedef typename result_of::child_c<Expr, 1>::type e1; | |
172 | typedef typename proto::result_of::eval<UNREF(e0), Context>::type r0; | |
173 | typedef typename proto::result_of::eval<UNREF(e1), Context>::type r1; | |
174 | public: | |
175 | typedef typename detail::mem_ptr_fun<r0, r1>::result_type result_type; | |
176 | result_type operator ()(Expr &expr, Context &ctx) const | |
177 | { | |
178 | return detail::mem_ptr_fun<r0, r1>()( | |
179 | proto::eval(proto::child_c<0>(expr), ctx) | |
180 | , proto::eval(proto::child_c<1>(expr), ctx) | |
181 | ); | |
182 | } | |
183 | }; | |
184 | ||
185 | /// INTERNAL ONLY | |
186 | template<typename Expr, typename Context> | |
187 | struct memfun_eval<Expr, Context, true> | |
188 | { | |
189 | private: | |
190 | typedef typename result_of::child_c<Expr, 0>::type e0; | |
191 | typedef typename result_of::child_c<Expr, 1>::type e1; | |
192 | typedef typename proto::result_of::eval<UNREF(e0), Context>::type r0; | |
193 | typedef typename proto::result_of::eval<UNREF(e1), Context>::type r1; | |
194 | public: | |
195 | typedef detail::memfun<r0, r1> result_type; | |
196 | result_type const operator ()(Expr &expr, Context &ctx) const | |
197 | { | |
198 | return detail::memfun<r0, r1>( | |
199 | proto::eval(proto::child_c<0>(expr), ctx) | |
200 | , proto::eval(proto::child_c<1>(expr), ctx) | |
201 | ); | |
202 | } | |
203 | }; | |
204 | ||
205 | template<typename Expr, typename Context> | |
206 | struct default_eval<Expr, Context, tag::mem_ptr, 2> | |
207 | : memfun_eval<Expr, Context, is_member_function_eval<Expr, Context>::value> | |
208 | {}; | |
209 | ||
210 | // Handle post-increment specially. | |
211 | template<typename Expr, typename Context> | |
212 | struct default_eval<Expr, Context, proto::tag::post_inc, 1> | |
213 | { | |
214 | private: | |
215 | typedef typename proto::result_of::child_c<Expr, 0>::type e0; | |
216 | typedef typename proto::result_of::eval<UNREF(e0), Context>::type r0; | |
217 | public: | |
218 | BOOST_PROTO_DECLTYPE_(proto::detail::make_mutable<r0>() ++, result_type) | |
219 | result_type operator ()(Expr &expr, Context &ctx) const | |
220 | { | |
221 | return proto::eval(proto::child_c<0>(expr), ctx) ++; | |
222 | } | |
223 | }; | |
224 | ||
225 | // Handle post-decrement specially. | |
226 | template<typename Expr, typename Context> | |
227 | struct default_eval<Expr, Context, proto::tag::post_dec, 1> | |
228 | { | |
229 | private: | |
230 | typedef typename proto::result_of::child_c<Expr, 0>::type e0; | |
231 | typedef typename proto::result_of::eval<UNREF(e0), Context>::type r0; | |
232 | public: | |
233 | BOOST_PROTO_DECLTYPE_(proto::detail::make_mutable<r0>() --, result_type) | |
234 | result_type operator ()(Expr &expr, Context &ctx) const | |
235 | { | |
236 | return proto::eval(proto::child_c<0>(expr), ctx) --; | |
237 | } | |
238 | }; | |
239 | ||
240 | // Handle subscript specially. | |
241 | template<typename Expr, typename Context> | |
242 | struct default_eval<Expr, Context, proto::tag::subscript, 2> | |
243 | { | |
244 | private: | |
245 | typedef typename proto::result_of::child_c<Expr, 0>::type e0; | |
246 | typedef typename proto::result_of::child_c<Expr, 1>::type e1; | |
247 | typedef typename proto::result_of::eval<UNREF(e0), Context>::type r0; | |
248 | typedef typename proto::result_of::eval<UNREF(e1), Context>::type r1; | |
249 | public: | |
250 | BOOST_PROTO_DECLTYPE_(proto::detail::make_subscriptable<r0>()[proto::detail::make<r1>()], result_type) | |
251 | result_type operator ()(Expr &expr, Context &ctx) const | |
252 | { | |
253 | return proto::eval(proto::child_c<0>(expr), ctx)[proto::eval(proto::child_c<1>(expr), ctx)]; | |
254 | } | |
255 | }; | |
256 | ||
257 | // Handle if_else_ specially. | |
258 | template<typename Expr, typename Context> | |
259 | struct default_eval<Expr, Context, proto::tag::if_else_, 3> | |
260 | { | |
261 | private: | |
262 | typedef typename proto::result_of::child_c<Expr, 0>::type e0; | |
263 | typedef typename proto::result_of::child_c<Expr, 1>::type e1; | |
264 | typedef typename proto::result_of::child_c<Expr, 2>::type e2; | |
265 | typedef typename proto::result_of::eval<UNREF(e0), Context>::type r0; | |
266 | typedef typename proto::result_of::eval<UNREF(e1), Context>::type r1; | |
267 | typedef typename proto::result_of::eval<UNREF(e2), Context>::type r2; | |
268 | public: | |
269 | BOOST_PROTO_DECLTYPE_( | |
270 | proto::detail::make<r0>() | |
271 | ? proto::detail::make<r1>() | |
272 | : proto::detail::make<r2>() | |
273 | , result_type | |
274 | ) | |
275 | result_type operator ()(Expr &expr, Context &ctx) const | |
276 | { | |
277 | return proto::eval(proto::child_c<0>(expr), ctx) | |
278 | ? proto::eval(proto::child_c<1>(expr), ctx) | |
279 | : proto::eval(proto::child_c<2>(expr), ctx); | |
280 | } | |
281 | }; | |
282 | ||
283 | // Handle comma specially. | |
284 | template<typename Expr, typename Context> | |
285 | struct default_eval<Expr, Context, proto::tag::comma, 2> | |
286 | { | |
287 | private: | |
288 | typedef typename proto::result_of::child_c<Expr, 0>::type e0; | |
289 | typedef typename proto::result_of::child_c<Expr, 1>::type e1; | |
290 | typedef typename proto::result_of::eval<UNREF(e0), Context>::type r0; | |
291 | typedef typename proto::result_of::eval<UNREF(e1), Context>::type r1; | |
292 | public: | |
293 | typedef typename proto::detail::comma_result<r0, r1>::type result_type; | |
294 | result_type operator ()(Expr &expr, Context &ctx) const | |
295 | { | |
296 | return proto::eval(proto::child_c<0>(expr), ctx), proto::eval(proto::child_c<1>(expr), ctx); | |
297 | } | |
298 | }; | |
299 | ||
300 | // Handle function specially | |
301 | #define BOOST_PROTO_DEFAULT_EVAL_TYPE(Z, N, DATA) \ | |
302 | typename proto::result_of::eval< \ | |
303 | typename remove_reference< \ | |
304 | typename proto::result_of::child_c<DATA, N>::type \ | |
305 | >::type \ | |
306 | , Context \ | |
307 | >::type \ | |
308 | /**/ | |
309 | ||
310 | #define BOOST_PROTO_DEFAULT_EVAL(Z, N, DATA) \ | |
311 | proto::eval(proto::child_c<N>(DATA), context) \ | |
312 | /**/ | |
313 | ||
314 | template<typename Expr, typename Context> | |
315 | struct default_eval<Expr, Context, proto::tag::function, 1> | |
316 | { | |
317 | typedef | |
318 | typename proto::detail::result_of_fixup< | |
319 | BOOST_PROTO_DEFAULT_EVAL_TYPE(~, 0, Expr) | |
320 | >::type | |
321 | function_type; | |
322 | ||
323 | typedef | |
324 | typename BOOST_PROTO_RESULT_OF<function_type()>::type | |
325 | result_type; | |
326 | ||
327 | result_type operator ()(Expr &expr, Context &context) const | |
328 | { | |
329 | return BOOST_PROTO_DEFAULT_EVAL(~, 0, expr)(); | |
330 | } | |
331 | }; | |
332 | ||
333 | template<typename Expr, typename Context> | |
334 | struct default_eval<Expr, Context, proto::tag::function, 2> | |
335 | { | |
336 | typedef | |
337 | typename proto::detail::result_of_fixup< | |
338 | BOOST_PROTO_DEFAULT_EVAL_TYPE(~, 0, Expr) | |
339 | >::type | |
340 | function_type; | |
341 | ||
342 | typedef | |
343 | typename detail::result_of_< | |
344 | function_type(BOOST_PROTO_DEFAULT_EVAL_TYPE(~, 1, Expr)) | |
345 | >::type | |
346 | result_type; | |
347 | ||
348 | result_type operator ()(Expr &expr, Context &context) const | |
349 | { | |
350 | return this->invoke( | |
351 | expr | |
352 | , context | |
353 | , is_member_function_pointer<function_type>() | |
354 | , is_member_object_pointer<function_type>() | |
355 | ); | |
356 | } | |
357 | ||
358 | private: | |
359 | result_type invoke(Expr &expr, Context &context, mpl::false_, mpl::false_) const | |
360 | { | |
361 | return BOOST_PROTO_DEFAULT_EVAL(~, 0, expr)(BOOST_PROTO_DEFAULT_EVAL(~, 1, expr)); | |
362 | } | |
363 | ||
364 | result_type invoke(Expr &expr, Context &context, mpl::true_, mpl::false_) const | |
365 | { | |
366 | BOOST_PROTO_USE_GET_POINTER(); | |
367 | typedef typename detail::class_member_traits<function_type>::class_type class_type; | |
368 | return ( | |
369 | BOOST_PROTO_GET_POINTER(class_type, (BOOST_PROTO_DEFAULT_EVAL(~, 1, expr))) ->* | |
370 | BOOST_PROTO_DEFAULT_EVAL(~, 0, expr) | |
371 | )(); | |
372 | } | |
373 | ||
374 | result_type invoke(Expr &expr, Context &context, mpl::false_, mpl::true_) const | |
375 | { | |
376 | BOOST_PROTO_USE_GET_POINTER(); | |
377 | typedef typename detail::class_member_traits<function_type>::class_type class_type; | |
378 | return ( | |
379 | BOOST_PROTO_GET_POINTER(class_type, (BOOST_PROTO_DEFAULT_EVAL(~, 1, expr))) ->* | |
380 | BOOST_PROTO_DEFAULT_EVAL(~, 0, expr) | |
381 | ); | |
382 | } | |
383 | }; | |
384 | ||
385 | // Additional specialization are generated by the preprocessor | |
386 | #include <boost/proto/context/detail/default_eval.hpp> | |
387 | ||
388 | #undef BOOST_PROTO_DEFAULT_EVAL_TYPE | |
389 | #undef BOOST_PROTO_DEFAULT_EVAL | |
390 | ||
391 | /// default_context | |
392 | /// | |
393 | struct default_context | |
394 | { | |
395 | /// default_context::eval | |
396 | /// | |
397 | template<typename Expr, typename ThisContext = default_context const> | |
398 | struct eval | |
399 | : default_eval<Expr, ThisContext> | |
400 | {}; | |
401 | }; | |
402 | ||
403 | } // namespace context | |
404 | ||
405 | }} // namespace boost::proto | |
406 | ||
407 | #undef UNREF | |
408 | ||
409 | #endif |