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 
operator ()boost::proto::context::default_eval57             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;
operator ()boost::proto::context::memfun_eval176             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;
operator ()boost::proto::context::memfun_eval196             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)
operator ()boost::proto::context::default_eval219             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)
operator ()boost::proto::context::default_eval234             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:
BOOST_PROTO_DECLTYPE_boost::proto::context::default_eval250             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             )
operator ()boost::proto::context::default_eval275             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;
operator ()boost::proto::context::default_eval294             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 
operator ()boost::proto::context::default_eval327             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 
operator ()boost::proto::context::default_eval348             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:
invokeboost::proto::context::default_eval359             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 
invokeboost::proto::context::default_eval364             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 
invokeboost::proto::context::default_eval374             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
410