123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498 |
- ///////////////////////////////////////////////////////////////////////////////
- // examples.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 <iostream>
- #include <boost/config.hpp>
- #include <boost/mpl/min_max.hpp>
- #include <boost/proto/core.hpp>
- #include <boost/proto/transform.hpp>
- #include <boost/proto/functional/fusion.hpp>
- #include <boost/utility/result_of.hpp>
- #include <boost/fusion/include/cons.hpp>
- #include <boost/fusion/include/tuple.hpp>
- #include <boost/fusion/include/pop_front.hpp>
- #include <boost/test/unit_test.hpp>
- namespace mpl = boost::mpl;
- namespace proto = boost::proto;
- namespace fusion = boost::fusion;
- using proto::_;
- template<int I>
- struct placeholder
- {};
- namespace test1
- {
- //[ CalcGrammar
- // This is the grammar for calculator expressions,
- // to which we will attach transforms for computing
- // the expressions' arity.
- /*<< A Calculator expression is ... >>*/
- struct CalcArity
- : proto::or_<
- /*<< _1, or ... >>*/
- proto::terminal< placeholder<0> >
- /*<< _2, or ... >>*/
- , proto::terminal< placeholder<1> >
- /*<< some other terminal, or ... >>*/
- , proto::terminal< _ >
- /*<< a unary expression where the operand is a calculator expression, or ... >>*/
- , proto::unary_expr< _, CalcArity >
- /*<< a binary expression where the operands are calculator expressions >>*/
- , proto::binary_expr< _, CalcArity, CalcArity >
- >
- {};
- //]
- }
- //[ binary_arity
- /*<< The `CalculatorArity` is a transform for calculating
- the arity of a calculator expression. It will be define in
- terms of `binary_arity`, which is defined in terms of
- `CalculatorArity`; hence, the definition is recursive.>>*/
- struct CalculatorArity;
- // A custom transform that returns the arity of a unary
- // calculator expression by finding the arity of the
- // child expression.
- struct unary_arity
- /*<< Custom transforms should inherit from
- transform<>. In some cases, (e.g., when the transform
- is a template), it is also necessary to specialize
- the proto::is_callable<> trait. >>*/
- : proto::transform<unary_arity>
- {
- template<typename Expr, typename State, typename Data>
- /*<< Transforms have a nested `impl<>` that is
- a valid TR1 function object. >>*/
- struct impl
- : proto::transform_impl<Expr, State, Data>
- {
- /*<< Get the child. >>*/
- typedef typename proto::result_of::child<Expr>::type child_expr;
- /*<< Apply `CalculatorArity` to find the arity of the child. >>*/
- typedef typename boost::result_of<CalculatorArity(child_expr, State, Data)>::type result_type;
- /*<< The `unary_arity` transform doesn't have an interesting
- runtime counterpart, so just return a default-constructed object
- of the correct type. >>*/
- result_type operator ()(proto::ignore, proto::ignore, proto::ignore) const
- {
- return result_type();
- }
- };
- };
- // A custom transform that returns the arity of a binary
- // calculator expression by finding the maximum of the
- // arities of the mpl::int_<2> child expressions.
- struct binary_arity
- /*<< All custom transforms should inherit from
- transform. In some cases, (e.g., when the transform
- is a template), it is also necessary to specialize
- the proto::is_callable<> trait. >>*/
- : proto::transform<binary_arity>
- {
- template<typename Expr, typename State, typename Data>
- /*<< Transforms have a nested `impl<>` that is
- a valid TR1 function object. >>*/
- struct impl
- : proto::transform_impl<Expr, State, Data>
- {
- /*<< Get the left and right children. >>*/
- typedef typename proto::result_of::left<Expr>::type left_expr;
- typedef typename proto::result_of::right<Expr>::type right_expr;
- /*<< Apply `CalculatorArity` to find the arity of the left and right children. >>*/
- typedef typename boost::result_of<CalculatorArity(left_expr, State, Data)>::type left_arity;
- typedef typename boost::result_of<CalculatorArity(right_expr, State, Data)>::type right_arity;
- /*<< The return type is the maximum of the children's arities. >>*/
- typedef typename mpl::max<left_arity, right_arity>::type result_type;
- /*<< The `unary_arity` transform doesn't have an interesting
- runtime counterpart, so just return a default-constructed object
- of the correct type. >>*/
- result_type operator ()(proto::ignore, proto::ignore, proto::ignore) const
- {
- return result_type();
- }
- };
- };
- //]
- proto::terminal< placeholder<0> >::type const _1 = {};
- proto::terminal< placeholder<1> >::type const _2 = {};
- //[ CalculatorArityGrammar
- struct CalculatorArity
- : proto::or_<
- proto::when< proto::terminal< placeholder<0> >, mpl::int_<1>() >
- , proto::when< proto::terminal< placeholder<1> >, mpl::int_<2>() >
- , proto::when< proto::terminal<_>, mpl::int_<0>() >
- , proto::when< proto::unary_expr<_, _>, unary_arity >
- , proto::when< proto::binary_expr<_, _, _>, binary_arity >
- >
- {};
- //]
- //[ CalcArity
- struct CalcArity
- : proto::or_<
- proto::when< proto::terminal< placeholder<0> >,
- mpl::int_<1>()
- >
- , proto::when< proto::terminal< placeholder<1> >,
- mpl::int_<2>()
- >
- , proto::when< proto::terminal<_>,
- mpl::int_<0>()
- >
- , proto::when< proto::unary_expr<_, CalcArity>,
- CalcArity(proto::_child)
- >
- , proto::when< proto::binary_expr<_, CalcArity, CalcArity>,
- mpl::max<CalcArity(proto::_left),
- CalcArity(proto::_right)>()
- >
- >
- {};
- //]
- // BUGBUG find workaround for this
- #if BOOST_WORKAROUND(BOOST_MSVC, == 1310)
- #define _pop_front(x) call<proto::_pop_front(x)>
- #define _value(x) call<proto::_value(x)>
- #endif
- //[ AsArgList
- // This transform matches function invocations such as foo(1,'a',"b")
- // and transforms them into Fusion cons lists of their arguments. In this
- // case, the result would be cons(1, cons('a', cons("b", nil()))).
- struct ArgsAsList
- : proto::when<
- proto::function<proto::terminal<_>, proto::vararg<proto::terminal<_> > >
- /*<< Use a `fold<>` transform to iterate over the children of this
- node in forward order, building a fusion list from front to back. >>*/
- , proto::fold<
- /*<< The first child expression of a `function<>` node is the
- function being invoked. We don't want that in our list, so use
- `pop_front()` to remove it. >>*/
- proto::_pop_front(_)
- /*<< `nil` is the initial state used by the `fold<>` transform. >>*/
- , fusion::nil()
- /*<< Put the rest of the function arguments in a fusion cons
- list. >>*/
- , proto::functional::push_back(proto::_state, proto::_value)
- >
- >
- {};
- //]
- //[ FoldTreeToList
- // This transform matches expressions of the form (_1=1,'a',"b")
- // (note the use of the comma operator) and transforms it into a
- // Fusion cons list of their arguments. In this case, the result
- // would be cons(1, cons('a', cons("b", nil()))).
- struct FoldTreeToList
- : proto::or_<
- // This grammar describes what counts as the terminals in expressions
- // of the form (_1=1,'a',"b"), which will be flattened using
- // reverse_fold_tree<> below.
- proto::when< proto::assign<_, proto::terminal<_> >
- , proto::_value(proto::_right)
- >
- , proto::when< proto::terminal<_>
- , proto::_value
- >
- , proto::when<
- proto::comma<FoldTreeToList, FoldTreeToList>
- /*<< Fold all terminals that are separated by commas into a Fusion cons list. >>*/
- , proto::reverse_fold_tree<
- _
- , fusion::nil()
- , fusion::cons<FoldTreeToList, proto::_state>(FoldTreeToList, proto::_state)
- >
- >
- >
- {};
- //]
- //[ Promote
- // This transform finds all float terminals in an expression and promotes
- // them to doubles.
- struct Promote
- : proto::or_<
- /*<< Match a `terminal<float>`, then construct a
- `terminal<double>::type` with the `float`. >>*/
- proto::when<proto::terminal<float>, proto::terminal<double>::type(proto::_value) >
- , proto::when<proto::terminal<_> >
- /*<< `nary_expr<>` has a pass-through transform which
- will transform each child sub-expression using the
- `Promote` transform. >>*/
- , proto::when<proto::nary_expr<_, proto::vararg<Promote> > >
- >
- {};
- //]
- //[ LazyMakePair
- struct make_pair_tag {};
- proto::terminal<make_pair_tag>::type const make_pair_ = {{}};
- // This transform matches lazy function invocations like
- // `make_pair_(1, 3.14)` and actually builds a `std::pair<>`
- // from the arguments.
- struct MakePair
- : proto::when<
- /*<< Match expressions like `make_pair_(1, 3.14)` >>*/
- proto::function<
- proto::terminal<make_pair_tag>
- , proto::terminal<_>
- , proto::terminal<_>
- >
- /*<< Return `std::pair<F,S>(f,s)` where `f` and `s` are the
- first and second arguments to the lazy `make_pair_()` function.
- (This uses `proto::make<>` under the covers to evaluate the
- transform.)>>*/
- , std::pair<
- proto::_value(proto::_child1)
- , proto::_value(proto::_child2)
- >(
- proto::_value(proto::_child1)
- , proto::_value(proto::_child2)
- )
- >
- {};
- //]
- namespace lazy_make_pair2
- {
- //[ LazyMakePair2
- struct make_pair_tag {};
- proto::terminal<make_pair_tag>::type const make_pair_ = {{}};
- // Like std::make_pair(), only as a function object.
- /*<<Inheriting from `proto::callable` lets Proto know
- that this is a callable transform, so we can use it
- without having to wrap it in `proto::call<>`.>>*/
- struct make_pair : proto::callable
- {
- template<typename Sig> struct result;
- template<typename This, typename First, typename Second>
- struct result<This(First, Second)>
- {
- typedef
- std::pair<
- BOOST_PROTO_UNCVREF(First)
- , BOOST_PROTO_UNCVREF(Second)
- >
- type;
- };
- template<typename First, typename Second>
- std::pair<First, Second>
- operator()(First const &first, Second const &second) const
- {
- return std::make_pair(first, second);
- }
- };
- // This transform matches lazy function invocations like
- // `make_pair_(1, 3.14)` and actually builds a `std::pair<>`
- // from the arguments.
- struct MakePair
- : proto::when<
- /*<< Match expressions like `make_pair_(1, 3.14)` >>*/
- proto::function<
- proto::terminal<make_pair_tag>
- , proto::terminal<_>
- , proto::terminal<_>
- >
- /*<< Return `make_pair()(f,s)` where `f` and `s` are the
- first and second arguments to the lazy `make_pair_()` function.
- (This uses `proto::call<>` under the covers to evaluate the
- transform.)>>*/
- , make_pair(
- proto::_value(proto::_child1)
- , proto::_value(proto::_child2)
- )
- >
- {};
- //]
- }
- //[ NegateInt
- struct NegateInt
- : proto::when<proto::terminal<int>, proto::negate<_>(_)>
- {};
- //]
- #ifndef BOOST_MSVC
- //[ SquareAndPromoteInt
- struct SquareAndPromoteInt
- : proto::when<
- proto::terminal<int>
- , proto::_make_multiplies(
- proto::terminal<long>::type(proto::_value)
- , proto::terminal<long>::type(proto::_value)
- )
- >
- {};
- //]
- #endif
- namespace lambda_transform
- {
- //[LambdaTransform
- template<typename N>
- struct placeholder : N {};
- // A function object that calls fusion::at()
- struct at : proto::callable
- {
- template<typename Sig>
- struct result;
- template<typename This, typename Cont, typename Index>
- struct result<This(Cont, Index)>
- : fusion::result_of::at<
- typename boost::remove_reference<Cont>::type
- , typename boost::remove_reference<Index>::type
- >
- {};
- template<typename Cont, typename Index>
- typename fusion::result_of::at<Cont, Index>::type
- operator ()(Cont &cont, Index const &) const
- {
- return fusion::at<Index>(cont);
- }
- };
- // A transform that evaluates a lambda expression.
- struct LambdaEval
- : proto::or_<
- /*<<When you match a placeholder ...>>*/
- proto::when<
- proto::terminal<placeholder<_> >
- /*<<... call at() with the data parameter, which
- is a tuple, and the placeholder, which is an MPL
- Integral Constant.>>*/
- , at(proto::_data, proto::_value)
- >
- /*<<Otherwise, use the _default<> transform, which
- gives the operators their usual C++ meanings.>>*/
- , proto::otherwise< proto::_default<LambdaEval> >
- >
- {};
- // Define the lambda placeholders
- proto::terminal<placeholder<mpl::int_<0> > >::type const _1 = {};
- proto::terminal<placeholder<mpl::int_<1> > >::type const _2 = {};
- void test_lambda()
- {
- // a tuple that contains the values
- // of _1 and _2
- fusion::tuple<int, int> tup(2,3);
- // Use LambdaEval to evaluate a lambda expression
- int j = LambdaEval()( _2 - _1, 0, tup );
- BOOST_CHECK_EQUAL(j, 1);
- // You can mutate leaves in an expression tree
- proto::literal<int> k(42);
- int &l = LambdaEval()( k += 4, 0, tup );
- BOOST_CHECK_EQUAL(k.get(), 46);
- BOOST_CHECK_EQUAL(&l, &k.get());
- // You can mutate the values in the tuple, too.
- LambdaEval()( _1 += 4, 0, tup );
- BOOST_CHECK_EQUAL(6, fusion::at_c<0>(tup));
- }
- //]
- }
- void test_examples()
- {
- //[ CalculatorArityTest
- int i = 0; // not used, dummy state and data parameter
- std::cout << CalculatorArity()( proto::lit(100) * 200, i, i) << '\n';
- std::cout << CalculatorArity()( (_1 - _1) / _1 * 100, i, i) << '\n';
- std::cout << CalculatorArity()( (_2 - _1) / _2 * 100, i, i) << '\n';
- //]
- BOOST_CHECK_EQUAL(0, CalculatorArity()( proto::lit(100) * 200, i, i));
- BOOST_CHECK_EQUAL(1, CalculatorArity()( (_1 - _1) / _1 * 100, i, i));
- BOOST_CHECK_EQUAL(2, CalculatorArity()( (_2 - _1) / _2 * 100, i, i));
- BOOST_CHECK_EQUAL(0, CalcArity()( proto::lit(100) * 200, i, i));
- BOOST_CHECK_EQUAL(1, CalcArity()( (_1 - _1) / _1 * 100, i, i));
- BOOST_CHECK_EQUAL(2, CalcArity()( (_2 - _1) / _2 * 100, i, i));
- using boost::fusion::cons;
- using boost::fusion::nil;
- cons<int, cons<char, cons<std::string> > > args(ArgsAsList()( _1(1, 'a', std::string("b")), i, i ));
- BOOST_CHECK_EQUAL(args.car, 1);
- BOOST_CHECK_EQUAL(args.cdr.car, 'a');
- BOOST_CHECK_EQUAL(args.cdr.cdr.car, std::string("b"));
- cons<int, cons<char, cons<std::string> > > lst(FoldTreeToList()( (_1 = 1, 'a', std::string("b")), i, i ));
- BOOST_CHECK_EQUAL(lst.car, 1);
- BOOST_CHECK_EQUAL(lst.cdr.car, 'a');
- BOOST_CHECK_EQUAL(lst.cdr.cdr.car, std::string("b"));
- proto::plus<
- proto::terminal<double>::type
- , proto::terminal<double>::type
- >::type p = Promote()( proto::lit(1.f) + 2.f, i, i );
- //[ LazyMakePairTest
- int j = 0; // not used, dummy state and data parameter
- std::pair<int, double> p2 = MakePair()( make_pair_(1, 3.14), j, j );
- std::cout << p2.first << std::endl;
- std::cout << p2.second << std::endl;
- //]
- BOOST_CHECK_EQUAL(p2.first, 1);
- BOOST_CHECK_EQUAL(p2.second, 3.14);
- std::pair<int, double> p3 = lazy_make_pair2::MakePair()( lazy_make_pair2::make_pair_(1, 3.14), j, j );
- std::cout << p3.first << std::endl;
- std::cout << p3.second << std::endl;
- BOOST_CHECK_EQUAL(p3.first, 1);
- BOOST_CHECK_EQUAL(p3.second, 3.14);
- NegateInt()(proto::lit(1), i, i);
- #ifndef BOOST_MSVC
- SquareAndPromoteInt()(proto::lit(1), i, i);
- #endif
- lambda_transform::test_lambda();
- }
- 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 examples from the documentation");
- test->add(BOOST_TEST_CASE(&test_examples));
- return test;
- }
|