/////////////////////////////////////////////////////////////////////////////// // proto::make_expr.hpp // // Copyright 2008 Eric Niebler. Distributed under the Boost // Software License, Version 1.0. (See accompanying file // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) #include #include #include #include #include #include namespace fusion = boost::fusion; namespace proto = boost::proto; template struct ewrap; struct mydomain : proto::domain > {}; template struct ewrap : proto::extends, mydomain> { explicit ewrap(E const &e = E()) : proto::extends, mydomain>(e) {} }; void test_make_expr() { int i = 42; proto::terminal::type t1 = proto::make_expr(1); proto::terminal::type t2 = proto::make_expr(i); proto::unary_plus::type>::type p1 = proto::make_expr(1); proto::unary_plus::type>::type p2 = proto::make_expr(i); BOOST_CHECK_EQUAL(proto::value(proto::child(p2)), 42); typedef ewrap< proto::basic_expr< proto::tag::unary_plus , proto::list1< ewrap > > > > > p3_type; p3_type p3 = proto::make_expr(i); BOOST_CHECK_EQUAL(proto::value(proto::child(p3)), 42); typedef ewrap< proto::basic_expr< proto::tag::plus , proto::list2< p3_type , ewrap > > > > > p4_type; p4_type p4 = proto::make_expr(p3, 0); BOOST_CHECK_EQUAL(proto::value(proto::child(proto::left(p4))), 42); } void test_make_expr_ref() { int i = 42; int const ci = 84; proto::terminal::type t1 = proto::make_expr(boost::cref(ci)); proto::terminal::type t2 = proto::make_expr(boost::ref(i)); BOOST_CHECK_EQUAL(&i, &proto::value(t2)); proto::unary_plus::type>::type p1 = proto::make_expr(boost::cref(ci)); proto::unary_plus::type>::type p2 = proto::make_expr(boost::ref(i)); BOOST_CHECK_EQUAL(proto::value(proto::child(p2)), 42); typedef ewrap< proto::basic_expr< proto::tag::unary_plus , proto::list1< ewrap > > > > > p3_type; p3_type p3 = proto::make_expr(boost::ref(i)); BOOST_CHECK_EQUAL(proto::value(proto::child(p3)), 42); typedef ewrap< proto::basic_expr< proto::tag::plus , proto::list2< p3_type & , ewrap > > > > > p4_type; p4_type p4 = proto::make_expr(boost::ref(p3), 0); BOOST_CHECK_EQUAL(proto::value(proto::child(proto::left(p4))), 42); } void test_make_expr_functional() { int i = 42; proto::terminal::type t1 = proto::functional::make_expr()(1); proto::terminal::type t2 = proto::functional::make_expr()(i); proto::unary_plus::type>::type p1 = proto::functional::make_expr()(1); proto::unary_plus::type>::type p2 = proto::functional::make_expr()(i); BOOST_CHECK_EQUAL(proto::value(proto::child(p2)), 42); typedef ewrap< proto::basic_expr< proto::tag::unary_plus , proto::list1< ewrap > > > > > p3_type; p3_type p3 = proto::functional::make_expr()(i); BOOST_CHECK_EQUAL(proto::value(proto::child(p3)), 42); typedef ewrap< proto::basic_expr< proto::tag::plus , proto::list2< p3_type , ewrap > > > > > p4_type; p4_type p4 = proto::functional::make_expr()(p3, 0); } void test_make_expr_functional_ref() { int i = 42; int const ci = 84; proto::terminal::type t1 = proto::functional::make_expr()(boost::cref(ci)); proto::terminal::type t2 = proto::functional::make_expr()(boost::ref(i)); BOOST_CHECK_EQUAL(&i, &proto::value(t2)); proto::unary_plus::type>::type p1 = proto::functional::make_expr()(boost::cref(ci)); proto::unary_plus::type>::type p2 = proto::functional::make_expr()(boost::ref(i)); BOOST_CHECK_EQUAL(proto::value(proto::child(p2)), 42); typedef ewrap< proto::basic_expr< proto::tag::unary_plus , proto::list1< ewrap > > > > > p3_type; p3_type p3 = proto::functional::make_expr()(boost::ref(i)); BOOST_CHECK_EQUAL(proto::value(proto::child(p3)), 42); typedef ewrap< proto::basic_expr< proto::tag::plus , proto::list2< p3_type & , ewrap > > > > > p4_type; p4_type p4 = proto::functional::make_expr()(boost::ref(p3), 0); BOOST_CHECK_EQUAL(proto::value(proto::child(proto::left(p4))), 42); } void test_unpack_expr() { int i = 42; proto::terminal::type t1 = proto::unpack_expr(fusion::make_tuple(1)); proto::terminal::type t2 = proto::unpack_expr(fusion::make_tuple(boost::ref(i))); proto::unary_plus::type>::type p1 = proto::unpack_expr(fusion::make_tuple(1)); proto::unary_plus::type>::type p2 = proto::unpack_expr(fusion::make_tuple(boost::ref(i))); BOOST_CHECK_EQUAL(proto::value(proto::child(p2)), 42); typedef ewrap< proto::basic_expr< proto::tag::unary_plus , proto::list1< ewrap > > > > > p3_type; p3_type p3 = proto::unpack_expr(fusion::make_tuple(boost::ref(i))); BOOST_CHECK_EQUAL(proto::value(proto::child(p3)), 42); typedef ewrap< proto::basic_expr< proto::tag::plus , proto::list2< p3_type & , ewrap > > > > > p4_type; p4_type p4 = proto::unpack_expr(fusion::make_tuple(boost::ref(p3), 0)); BOOST_CHECK_EQUAL(proto::value(proto::child(proto::left(p4))), 42); } void test_unpack_expr_functional() { int i = 42; proto::terminal::type t1 = proto::functional::unpack_expr()(fusion::make_tuple(1)); proto::terminal::type t2 = proto::functional::unpack_expr()(fusion::make_tuple(boost::ref(i))); proto::unary_plus::type>::type p1 = proto::functional::unpack_expr()(fusion::make_tuple(1)); proto::unary_plus::type>::type p2 = proto::functional::unpack_expr()(fusion::make_tuple(boost::ref(i))); BOOST_CHECK_EQUAL(proto::value(proto::child(p2)), 42); typedef ewrap< proto::basic_expr< proto::tag::unary_plus , proto::list1< ewrap > > > > > p3_type; p3_type p3 = proto::functional::unpack_expr()(fusion::make_tuple(boost::ref(i))); BOOST_CHECK_EQUAL(proto::value(proto::child(p3)), 42); typedef ewrap< proto::basic_expr< proto::tag::plus , proto::list2< p3_type & , ewrap > > > > > p4_type; p4_type p4 = proto::functional::unpack_expr()(fusion::make_tuple(boost::ref(p3), 0)); BOOST_CHECK_EQUAL(proto::value(proto::child(proto::left(p4))), 42); } #if BOOST_WORKAROUND(BOOST_MSVC, == 1310) #define _byref(x) call #define _byval(x) call #define Minus(x) proto::call #endif // Turn all terminals held by reference into ones held by value struct ByVal : proto::or_< proto::when, proto::_make_terminal(proto::_byval(proto::_value))> , proto::when > > > {}; // Turn all terminals held by value into ones held by reference (not safe in general) struct ByRef : proto::or_< proto::when, proto::_make_terminal(proto::_byref(proto::_value))> , proto::when > > > {}; // turn all proto::plus nodes to minus nodes: struct Minus : proto::or_< proto::when > , proto::when, proto::_make_minus(Minus(proto::_left), Minus(proto::_right)) > > {}; struct Square : proto::or_< // Not creating new proto::terminal nodes here, // so hold the existing terminals by reference: proto::when, proto::_make_multiplies(proto::_, proto::_)> , proto::when > > {}; #if BOOST_WORKAROUND(BOOST_MSVC, == 1310) #undef _byref #undef _byval #undef Minus #endif void test_make_expr_transform() { proto::plus< proto::terminal::type , proto::terminal::type >::type t1 = ByVal()(proto::as_expr(1) + 1); proto::plus< proto::terminal::type , proto::terminal::type >::type t2 = ByRef()(proto::as_expr(1) + 1); proto::minus< proto::terminal::type const & , proto::terminal::type const & >::type t3 = Minus()(proto::as_expr(1) + 1); proto::plus< proto::multiplies::type const &, proto::terminal::type const &>::type , proto::multiplies::type const &, proto::terminal::type const &>::type >::type t4 = Square()(proto::as_expr(1) + 1); } struct length_impl {}; struct dot_impl {}; proto::terminal::type const length = {{}}; proto::terminal::type const dot = {{}}; // work around msvc bugs... #if BOOST_WORKAROUND(BOOST_MSVC, BOOST_TESTED_AT(1500)) #define _byref(a) call #define _byval(a) call #define _child1(a) call #define _make_terminal(a) call #define _make_function(a,b,c) call #define dot_impl() proto::make #endif // convert length(a) < length(b) to dot(a,a) < dot(b,b) struct Convert : proto::when< proto::less< proto::function, proto::_> , proto::function, proto::_> > , proto::_make_less( proto::_make_function( proto::_make_terminal(dot_impl()) , proto::_child1(proto::_child0) , proto::_child1(proto::_child0) ) , proto::_make_function( proto::_make_terminal(dot_impl()) , proto::_child1(proto::_child1) , proto::_child1(proto::_child1) ) ) > {}; template void test_make_expr_transform2_test(Expr const &expr) { void const *addr1 = boost::addressof(proto::child_c<1>(proto::child_c<0>(expr))); void const *addr2 = boost::addressof(proto::child_c<1>(proto::child_c<0>(Convert()(expr)))); BOOST_CHECK_EQUAL(addr1, addr2); BOOST_CHECK_EQUAL(1, proto::value(proto::child_c<1>(proto::child_c<0>(expr)))); BOOST_CHECK_EQUAL(1, proto::value(proto::child_c<1>(proto::child_c<0>(Convert()(expr))))); } void test_make_expr_transform2() { test_make_expr_transform2_test(length(1) < length(2)); } #if BOOST_WORKAROUND(BOOST_MSVC, BOOST_TESTED_AT(1500)) #undef _byref #undef _byval #undef _child1 #undef _make_terminal #undef _make_function #undef dot_impl #endif using namespace boost::unit_test; /////////////////////////////////////////////////////////////////////////////// // init_unit_test_suite // test_suite* init_unit_test_suite( int argc, char* argv[] ) { test_suite *test = BOOST_TEST_SUITE("test proto::make_expr, proto::unpack_expr and friends"); test->add(BOOST_TEST_CASE(&test_make_expr)); test->add(BOOST_TEST_CASE(&test_make_expr_ref)); test->add(BOOST_TEST_CASE(&test_make_expr_functional)); test->add(BOOST_TEST_CASE(&test_make_expr_functional_ref)); test->add(BOOST_TEST_CASE(&test_unpack_expr)); test->add(BOOST_TEST_CASE(&test_unpack_expr_functional)); test->add(BOOST_TEST_CASE(&test_make_expr_transform)); test->add(BOOST_TEST_CASE(&test_make_expr_transform2)); return test; }