/////////////////////////////////////////////////////////////////////////////// // 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 <sstream> #include <boost/proto/core.hpp> #include <boost/proto/transform.hpp> #include <boost/utility/addressof.hpp> #include <boost/fusion/tuple.hpp> #include <boost/test/unit_test.hpp> namespace fusion = boost::fusion; namespace proto = boost::proto; template<typename E> struct ewrap; struct mydomain : proto::domain<proto::generator<ewrap> > {}; template<typename E> struct ewrap : proto::extends<E, ewrap<E>, mydomain> { explicit ewrap(E const &e = E()) : proto::extends<E, ewrap<E>, mydomain>(e) {} }; void test_make_expr() { int i = 42; proto::terminal<int>::type t1 = proto::make_expr<proto::tag::terminal>(1); proto::terminal<int>::type t2 = proto::make_expr<proto::tag::terminal>(i); proto::unary_plus<proto::terminal<int>::type>::type p1 = proto::make_expr<proto::tag::unary_plus>(1); proto::unary_plus<proto::terminal<int>::type>::type p2 = proto::make_expr<proto::tag::unary_plus>(i); BOOST_CHECK_EQUAL(proto::value(proto::child(p2)), 42); typedef ewrap< proto::basic_expr< proto::tag::unary_plus , proto::list1< ewrap<proto::basic_expr<proto::tag::terminal, proto::term<int> > > > > > p3_type; p3_type p3 = proto::make_expr<proto::tag::unary_plus, mydomain>(i); BOOST_CHECK_EQUAL(proto::value(proto::child(p3)), 42); typedef ewrap< proto::basic_expr< proto::tag::plus , proto::list2< p3_type , ewrap<proto::basic_expr<proto::tag::terminal, proto::term<int> > > > > > p4_type; p4_type p4 = proto::make_expr<proto::tag::plus>(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<int const &>::type t1 = proto::make_expr<proto::tag::terminal>(boost::cref(ci)); proto::terminal<int &>::type t2 = proto::make_expr<proto::tag::terminal>(boost::ref(i)); BOOST_CHECK_EQUAL(&i, &proto::value(t2)); proto::unary_plus<proto::terminal<int const &>::type>::type p1 = proto::make_expr<proto::tag::unary_plus>(boost::cref(ci)); proto::unary_plus<proto::terminal<int &>::type>::type p2 = proto::make_expr<proto::tag::unary_plus>(boost::ref(i)); BOOST_CHECK_EQUAL(proto::value(proto::child(p2)), 42); typedef ewrap< proto::basic_expr< proto::tag::unary_plus , proto::list1< ewrap<proto::basic_expr<proto::tag::terminal, proto::term<int &> > > > > > p3_type; p3_type p3 = proto::make_expr<proto::tag::unary_plus, mydomain>(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<proto::basic_expr<proto::tag::terminal, proto::term<int> > > > > > p4_type; p4_type p4 = proto::make_expr<proto::tag::plus>(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<int>::type t1 = proto::functional::make_expr<proto::tag::terminal>()(1); proto::terminal<int>::type t2 = proto::functional::make_expr<proto::tag::terminal>()(i); proto::unary_plus<proto::terminal<int>::type>::type p1 = proto::functional::make_expr<proto::tag::unary_plus>()(1); proto::unary_plus<proto::terminal<int>::type>::type p2 = proto::functional::make_expr<proto::tag::unary_plus>()(i); BOOST_CHECK_EQUAL(proto::value(proto::child(p2)), 42); typedef ewrap< proto::basic_expr< proto::tag::unary_plus , proto::list1< ewrap<proto::basic_expr<proto::tag::terminal, proto::term<int> > > > > > p3_type; p3_type p3 = proto::functional::make_expr<proto::tag::unary_plus, mydomain>()(i); BOOST_CHECK_EQUAL(proto::value(proto::child(p3)), 42); typedef ewrap< proto::basic_expr< proto::tag::plus , proto::list2< p3_type , ewrap<proto::basic_expr<proto::tag::terminal, proto::term<int> > > > > > p4_type; p4_type p4 = proto::functional::make_expr<proto::tag::plus>()(p3, 0); } void test_make_expr_functional_ref() { int i = 42; int const ci = 84; proto::terminal<int const &>::type t1 = proto::functional::make_expr<proto::tag::terminal>()(boost::cref(ci)); proto::terminal<int &>::type t2 = proto::functional::make_expr<proto::tag::terminal>()(boost::ref(i)); BOOST_CHECK_EQUAL(&i, &proto::value(t2)); proto::unary_plus<proto::terminal<int const &>::type>::type p1 = proto::functional::make_expr<proto::tag::unary_plus>()(boost::cref(ci)); proto::unary_plus<proto::terminal<int &>::type>::type p2 = proto::functional::make_expr<proto::tag::unary_plus>()(boost::ref(i)); BOOST_CHECK_EQUAL(proto::value(proto::child(p2)), 42); typedef ewrap< proto::basic_expr< proto::tag::unary_plus , proto::list1< ewrap<proto::basic_expr<proto::tag::terminal, proto::term<int &> > > > > > p3_type; p3_type p3 = proto::functional::make_expr<proto::tag::unary_plus, mydomain>()(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<proto::basic_expr<proto::tag::terminal, proto::term<int> > > > > > p4_type; p4_type p4 = proto::functional::make_expr<proto::tag::plus>()(boost::ref(p3), 0); BOOST_CHECK_EQUAL(proto::value(proto::child(proto::left(p4))), 42); } void test_unpack_expr() { int i = 42; proto::terminal<int>::type t1 = proto::unpack_expr<proto::tag::terminal>(fusion::make_tuple(1)); proto::terminal<int &>::type t2 = proto::unpack_expr<proto::tag::terminal>(fusion::make_tuple(boost::ref(i))); proto::unary_plus<proto::terminal<int>::type>::type p1 = proto::unpack_expr<proto::tag::unary_plus>(fusion::make_tuple(1)); proto::unary_plus<proto::terminal<int &>::type>::type p2 = proto::unpack_expr<proto::tag::unary_plus>(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<proto::basic_expr<proto::tag::terminal, proto::term<int &> > > > > > p3_type; p3_type p3 = proto::unpack_expr<proto::tag::unary_plus, mydomain>(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<proto::basic_expr<proto::tag::terminal, proto::term<int> > > > > > p4_type; p4_type p4 = proto::unpack_expr<proto::tag::plus>(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<int>::type t1 = proto::functional::unpack_expr<proto::tag::terminal>()(fusion::make_tuple(1)); proto::terminal<int &>::type t2 = proto::functional::unpack_expr<proto::tag::terminal>()(fusion::make_tuple(boost::ref(i))); proto::unary_plus<proto::terminal<int>::type>::type p1 = proto::functional::unpack_expr<proto::tag::unary_plus>()(fusion::make_tuple(1)); proto::unary_plus<proto::terminal<int &>::type>::type p2 = proto::functional::unpack_expr<proto::tag::unary_plus>()(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<proto::basic_expr<proto::tag::terminal, proto::term<int &> > > > > > p3_type; p3_type p3 = proto::functional::unpack_expr<proto::tag::unary_plus, mydomain>()(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<proto::basic_expr<proto::tag::terminal, proto::term<int> > > > > > p4_type; p4_type p4 = proto::functional::unpack_expr<proto::tag::plus>()(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<proto::_byref(x)> #define _byval(x) call<proto::_byval(x)> #define Minus(x) proto::call<Minus(x)> #endif // Turn all terminals held by reference into ones held by value struct ByVal : proto::or_< proto::when<proto::terminal<proto::_>, proto::_make_terminal(proto::_byval(proto::_value))> , proto::when<proto::nary_expr<proto::_, proto::vararg<ByVal> > > > {}; // Turn all terminals held by value into ones held by reference (not safe in general) struct ByRef : proto::or_< proto::when<proto::terminal<proto::_>, proto::_make_terminal(proto::_byref(proto::_value))> , proto::when<proto::nary_expr<proto::_, proto::vararg<ByRef> > > > {}; // turn all proto::plus nodes to minus nodes: struct Minus : proto::or_< proto::when<proto::terminal<proto::_> > , proto::when<proto::plus<Minus, Minus>, 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::terminal<proto::_>, proto::_make_multiplies(proto::_, proto::_)> , proto::when<proto::plus<Square, Square> > > {}; #if BOOST_WORKAROUND(BOOST_MSVC, == 1310) #undef _byref #undef _byval #undef Minus #endif void test_make_expr_transform() { proto::plus< proto::terminal<int>::type , proto::terminal<int>::type >::type t1 = ByVal()(proto::as_expr(1) + 1); proto::plus< proto::terminal<int const &>::type , proto::terminal<int const &>::type >::type t2 = ByRef()(proto::as_expr(1) + 1); proto::minus< proto::terminal<int>::type const & , proto::terminal<int const &>::type const & >::type t3 = Minus()(proto::as_expr(1) + 1); proto::plus< proto::multiplies<proto::terminal<int>::type const &, proto::terminal<int>::type const &>::type , proto::multiplies<proto::terminal<int const &>::type const &, proto::terminal<int const &>::type const &>::type >::type t4 = Square()(proto::as_expr(1) + 1); } struct length_impl {}; struct dot_impl {}; proto::terminal<length_impl>::type const length = {{}}; proto::terminal<dot_impl>::type const dot = {{}}; // work around msvc bugs... #if BOOST_WORKAROUND(BOOST_MSVC, BOOST_TESTED_AT(1500)) #define _byref(a) call<proto::_byref(a)> #define _byval(a) call<proto::_byval(a)> #define _child1(a) call<proto::_child1(a)> #define _make_terminal(a) call<proto::_make_terminal(a)> #define _make_function(a,b,c) call<proto::_make_function(a,b,c)> #define dot_impl() proto::make<dot_impl()> #endif // convert length(a) < length(b) to dot(a,a) < dot(b,b) struct Convert : proto::when< proto::less< proto::function<proto::terminal<length_impl>, proto::_> , proto::function<proto::terminal<length_impl>, 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<typename Expr> 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; }