123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184 |
- //[ Vec3
- ///////////////////////////////////////////////////////////////////////////////
- // 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)
- //
- // This is a simple example using proto::extends to extend a terminal type with
- // additional behaviors, and using custom contexts and proto::eval for
- // evaluating expressions. It is a port of the Vec3 example
- // from PETE (http://www.codesourcery.com/pooma/download.html).
- #include <iostream>
- #include <functional>
- #include <boost/assert.hpp>
- #include <boost/mpl/int.hpp>
- #include <boost/proto/core.hpp>
- #include <boost/proto/context.hpp>
- #include <boost/proto/proto_typeof.hpp>
- #include <boost/proto/transform.hpp>
- namespace mpl = boost::mpl;
- namespace proto = boost::proto;
- using proto::_;
- // Here is an evaluation context that indexes into a Vec3
- // expression, and combines the result.
- struct Vec3SubscriptCtx
- : proto::callable_context< Vec3SubscriptCtx const >
- {
- typedef int result_type;
- Vec3SubscriptCtx(int i)
- : i_(i)
- {}
- // Index array terminals with our subscript. Everything
- // else will be handled by the default evaluation context.
- int operator ()(proto::tag::terminal, int const (&arr)[3]) const
- {
- return arr[this->i_];
- }
- int i_;
- };
- // Here is an evaluation context that counts the number
- // of Vec3 terminals in an expression.
- struct CountLeavesCtx
- : proto::callable_context< CountLeavesCtx, proto::null_context >
- {
- CountLeavesCtx()
- : count(0)
- {}
- typedef void result_type;
- void operator ()(proto::tag::terminal, int const(&)[3])
- {
- ++this->count;
- }
- int count;
- };
- struct iplus : std::plus<int>, proto::callable {};
- // Here is a transform that does the same thing as the above context.
- // It demonstrates the use of the std::plus<> function object
- // with the fold transform. With minor modifications, this
- // transform could be used to calculate the leaf count at compile
- // time, rather than at runtime.
- struct CountLeaves
- : proto::or_<
- // match a Vec3 terminal, return 1
- proto::when<proto::terminal<int[3]>, mpl::int_<1>() >
- // match a terminal, return int() (which is 0)
- , proto::when<proto::terminal<_>, int() >
- // fold everything else, using std::plus<> to add
- // the leaf count of each child to the accumulated state.
- , proto::otherwise< proto::fold<_, int(), iplus(CountLeaves, proto::_state) > >
- >
- {};
- // Here is the Vec3 struct, which is a vector of 3 integers.
- struct Vec3
- : proto::extends<proto::terminal<int[3]>::type, Vec3>
- {
- explicit Vec3(int i=0, int j=0, int k=0)
- {
- (*this)[0] = i;
- (*this)[1] = j;
- (*this)[2] = k;
- }
- int &operator [](int i)
- {
- return proto::value(*this)[i];
- }
- int const &operator [](int i) const
- {
- return proto::value(*this)[i];
- }
- // Here we define a operator = for Vec3 terminals that
- // takes a Vec3 expression.
- template< typename Expr >
- Vec3 &operator =(Expr const & expr)
- {
- typedef Vec3SubscriptCtx const CVec3SubscriptCtx;
- (*this)[0] = proto::eval(proto::as_expr(expr), CVec3SubscriptCtx(0));
- (*this)[1] = proto::eval(proto::as_expr(expr), CVec3SubscriptCtx(1));
- (*this)[2] = proto::eval(proto::as_expr(expr), CVec3SubscriptCtx(2));
- return *this;
- }
- // This copy-assign is needed because a template is never
- // considered for copy assignment.
- Vec3 &operator=(Vec3 const &that)
- {
- (*this)[0] = that[0];
- (*this)[1] = that[1];
- (*this)[2] = that[2];
- return *this;
- }
- void print() const
- {
- std::cout << '{' << (*this)[0]
- << ", " << (*this)[1]
- << ", " << (*this)[2]
- << '}' << std::endl;
- }
- };
- // The count_leaves() function uses the CountLeaves transform and
- // to count the number of leaves in an expression.
- template<typename Expr>
- int count_leaves(Expr const &expr)
- {
- // Count the number of Vec3 terminals using the
- // CountLeavesCtx evaluation context.
- CountLeavesCtx ctx;
- proto::eval(expr, ctx);
- // This is another way to count the leaves using a transform.
- int i = 0;
- BOOST_ASSERT( CountLeaves()(expr, i, i) == ctx.count );
- return ctx.count;
- }
- int main()
- {
- Vec3 a, b, c;
- c = 4;
- b[0] = -1;
- b[1] = -2;
- b[2] = -3;
- a = b + c;
- a.print();
- Vec3 d;
- BOOST_PROTO_AUTO(expr1, b + c);
- d = expr1;
- d.print();
- int num = count_leaves(expr1);
- std::cout << num << std::endl;
- BOOST_PROTO_AUTO(expr2, b + 3 * c);
- num = count_leaves(expr2);
- std::cout << num << std::endl;
- BOOST_PROTO_AUTO(expr3, b + c * d);
- num = count_leaves(expr3);
- std::cout << num << std::endl;
- return 0;
- }
- //]
|