/////////////////////////////////////////////////////////////////////////////// // 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 #if BOOST_VERSION >= 103500 #include #else #include #endif #include using namespace boost; using namespace proto; template struct ewrap; struct mydomain : domain > {}; template struct ewrap : extends, mydomain> { explicit ewrap(E const &e = E()) : extends, mydomain>(e) {} }; void test_make_expr() { int i = 42; terminal::type t1 = make_expr(1); terminal::type t2 = make_expr(i); unary_plus::type>::type p1 = make_expr(1); unary_plus::type>::type p2 = make_expr(i); BOOST_CHECK_EQUAL(proto::value(proto::child(p2)), 42); ewrap::type> >::type> p3 = make_expr(i); BOOST_CHECK_EQUAL(proto::value(proto::child(p3)), 42); ewrap::type> >::type> , ewrap::type> >::type> p4 = make_expr(p3, 0); BOOST_CHECK_EQUAL(proto::value(proto::child(proto::left(p4))), 42); } void test_make_expr_ref() { int i = 42; terminal::type t1 = make_expr(boost::cref(1)); // DANGEROUS terminal::type t2 = make_expr(boost::ref(i)); BOOST_CHECK_EQUAL(&i, &proto::value(t2)); unary_plus::type>::type p1 = make_expr(boost::cref(1)); // DANGEROUS unary_plus::type>::type p2 = make_expr(boost::ref(i)); BOOST_CHECK_EQUAL(proto::value(proto::child(p2)), 42); ewrap::type> >::type> p3 = make_expr(boost::ref(i)); BOOST_CHECK_EQUAL(proto::value(proto::child(p3)), 42); ewrap::type> >::type> & , ewrap::type> >::type> p4 = 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; terminal::type t1 = functional::make_expr()(1); terminal::type t2 = functional::make_expr()(i); unary_plus::type>::type p1 = functional::make_expr()(1); unary_plus::type>::type p2 = functional::make_expr()(i); BOOST_CHECK_EQUAL(proto::value(proto::child(p2)), 42); ewrap::type> >::type> p3 = functional::make_expr()(i); BOOST_CHECK_EQUAL(proto::value(proto::child(p3)), 42); ewrap::type> >::type> , ewrap::type> >::type> p4 = functional::make_expr()(p3, 0); BOOST_CHECK_EQUAL(proto::value(proto::child(proto::left(p4))), 42); } void test_make_expr_functional_ref() { int i = 42; terminal::type t1 = functional::make_expr()(boost::cref(1)); // DANGEROUS terminal::type t2 = functional::make_expr()(boost::ref(i)); BOOST_CHECK_EQUAL(&i, &proto::value(t2)); unary_plus::type>::type p1 = functional::make_expr()(boost::cref(1)); // DANGEROUS unary_plus::type>::type p2 = functional::make_expr()(boost::ref(i)); BOOST_CHECK_EQUAL(proto::value(proto::child(p2)), 42); ewrap::type> >::type> p3 = functional::make_expr()(boost::ref(i)); BOOST_CHECK_EQUAL(proto::value(proto::child(p3)), 42); ewrap::type> >::type> & , ewrap::type> >::type> p4 = 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; terminal::type t1 = unpack_expr(fusion::make_tuple(1)); terminal::type t2 = unpack_expr(fusion::make_tuple(boost::ref(i))); unary_plus::type>::type p1 = unpack_expr(fusion::make_tuple(1)); unary_plus::type>::type p2 = unpack_expr(fusion::make_tuple(boost::ref(i))); BOOST_CHECK_EQUAL(proto::value(proto::child(p2)), 42); ewrap::type> >::type> p3 = unpack_expr(fusion::make_tuple(boost::ref(i))); BOOST_CHECK_EQUAL(proto::value(proto::child(p3)), 42); ewrap::type> >::type> & , ewrap::type> >::type> p4 = 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; terminal::type t1 = functional::unpack_expr()(fusion::make_tuple(1)); terminal::type t2 = functional::unpack_expr()(fusion::make_tuple(boost::ref(i))); unary_plus::type>::type p1 = functional::unpack_expr()(fusion::make_tuple(1)); unary_plus::type>::type p2 = functional::unpack_expr()(fusion::make_tuple(boost::ref(i))); BOOST_CHECK_EQUAL(proto::value(proto::child(p2)), 42); ewrap::type> >::type> p3 = functional::unpack_expr()(fusion::make_tuple(boost::ref(i))); BOOST_CHECK_EQUAL(proto::value(proto::child(p3)), 42); ewrap::type> >::type> & , ewrap::type> >::type> p4 = 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<_byref(x)> #define _byval(x) call<_byval(x)> #define Minus(x) call #endif // Turn all terminals held by reference into ones held by value struct ByVal : or_< when, _make_terminal(_byval(_value))> , when > > > {}; // Turn all terminals held by value into ones held by reference (not safe in general) struct ByRef : or_< when, _make_terminal(_byref(_value))> , when > > > {}; // turn all plus nodes to minus nodes: struct Minus : or_< when > , when, _make_minus(Minus(_left), Minus(_right)) > > {}; struct Square : or_< // Not creating new terminal nodes here, // so hold the existing terminals by reference: when, _make_multiplies(_, _)> , when > > {}; #if BOOST_WORKAROUND(BOOST_MSVC, == 1310) #undef _byref #undef _byval #undef Minus #endif void test_make_expr_transform() { plus< terminal::type , terminal::type >::type t1 = ByVal()(as_expr(1) + 1); plus< terminal::type , terminal::type >::type t2 = ByRef()(as_expr(1) + 1); minus< terminal::type const & , terminal::type const & >::type t3 = Minus()(as_expr(1) + 1); plus< multiplies::type const &, terminal::type const &>::type , multiplies::type const &, terminal::type const &>::type >::type t4 = Square()(as_expr(1) + 1); } struct length_impl {}; struct dot_impl {}; terminal::type const length = {{}}; terminal::type const dot = {{}}; // work around msvc bugs... #if BOOST_WORKAROUND(BOOST_MSVC, BOOST_TESTED_AT(1500)) #define _byref(a) call<_byref(a)> #define _byval(a) call<_byval(a)> #define _child1(a) call<_child1(a)> #define _make_terminal(a) call<_make_terminal(a)> #define _make_function(a,b,c) call<_make_function(a,b,c)> #define dot_impl() make #endif // convert length(a) < length(b) to dot(a,a) < dot(b,b) struct Convert : when< less< function, _> , function, _> > , _make_less( _make_function( _make_terminal(dot_impl()) , _child1(_child0) , _child1(_child0) ) , _make_function( _make_terminal(dot_impl()) , _child1(_child1) , _child1(_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 unit_test; /////////////////////////////////////////////////////////////////////////////// // init_unit_test_suite // test_suite* init_unit_test_suite( int argc, char* argv[] ) { test_suite *test = BOOST_TEST_SUITE("test make_expr, 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; }