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