• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //[ Vec3
2 ///////////////////////////////////////////////////////////////////////////////
3 //  Copyright 2008 Eric Niebler. Distributed under the Boost
4 //  Software License, Version 1.0. (See accompanying file
5 //  LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6 //
7 // This is a simple example using proto::extends to extend a terminal type with
8 // additional behaviors, and using custom contexts and proto::eval for
9 // evaluating expressions. It is a port of the Vec3 example
10 // from PETE (http://www.codesourcery.com/pooma/download.html).
11 
12 #include <iostream>
13 #include <functional>
14 #include <boost/assert.hpp>
15 #include <boost/mpl/int.hpp>
16 #include <boost/proto/core.hpp>
17 #include <boost/proto/context.hpp>
18 #include <boost/proto/proto_typeof.hpp>
19 #include <boost/proto/transform.hpp>
20 namespace mpl = boost::mpl;
21 namespace proto = boost::proto;
22 using proto::_;
23 
24 // Here is an evaluation context that indexes into a Vec3
25 // expression, and combines the result.
26 struct Vec3SubscriptCtx
27   : proto::callable_context< Vec3SubscriptCtx const >
28 {
29     typedef int result_type;
30 
Vec3SubscriptCtxVec3SubscriptCtx31     Vec3SubscriptCtx(int i)
32       : i_(i)
33     {}
34 
35     // Index array terminals with our subscript. Everything
36     // else will be handled by the default evaluation context.
operator ()Vec3SubscriptCtx37     int operator ()(proto::tag::terminal, int const (&arr)[3]) const
38     {
39         return arr[this->i_];
40     }
41 
42     int i_;
43 };
44 
45 // Here is an evaluation context that counts the number
46 // of Vec3 terminals in an expression.
47 struct CountLeavesCtx
48   : proto::callable_context< CountLeavesCtx, proto::null_context >
49 {
CountLeavesCtxCountLeavesCtx50     CountLeavesCtx()
51       : count(0)
52       {}
53 
54       typedef void result_type;
55 
operator ()CountLeavesCtx56       void operator ()(proto::tag::terminal, int const(&)[3])
57       {
58           ++this->count;
59       }
60 
61       int count;
62 };
63 
64 struct iplus : std::plus<int>, proto::callable {};
65 
66 // Here is a transform that does the same thing as the above context.
67 // It demonstrates the use of the std::plus<> function object
68 // with the fold transform. With minor modifications, this
69 // transform could be used to calculate the leaf count at compile
70 // time, rather than at runtime.
71 struct CountLeaves
72   : proto::or_<
73         // match a Vec3 terminal, return 1
74         proto::when<proto::terminal<int[3]>, mpl::int_<1>() >
75         // match a terminal, return int() (which is 0)
76       , proto::when<proto::terminal<_>, int() >
77         // fold everything else, using std::plus<> to add
78         // the leaf count of each child to the accumulated state.
79       , proto::otherwise< proto::fold<_, int(), iplus(CountLeaves, proto::_state) > >
80     >
81 {};
82 
83 // Here is the Vec3 struct, which is a vector of 3 integers.
84 struct Vec3
85   : proto::extends<proto::terminal<int[3]>::type, Vec3>
86 {
Vec3Vec387     explicit Vec3(int i=0, int j=0, int k=0)
88     {
89         (*this)[0] = i;
90         (*this)[1] = j;
91         (*this)[2] = k;
92     }
93 
operator []Vec394     int &operator [](int i)
95     {
96         return proto::value(*this)[i];
97     }
98 
operator []Vec399     int const &operator [](int i) const
100     {
101         return proto::value(*this)[i];
102     }
103 
104     // Here we define a operator = for Vec3 terminals that
105     // takes a Vec3 expression.
106     template< typename Expr >
operator =Vec3107     Vec3 &operator =(Expr const & expr)
108     {
109         typedef Vec3SubscriptCtx const CVec3SubscriptCtx;
110         (*this)[0] = proto::eval(proto::as_expr(expr), CVec3SubscriptCtx(0));
111         (*this)[1] = proto::eval(proto::as_expr(expr), CVec3SubscriptCtx(1));
112         (*this)[2] = proto::eval(proto::as_expr(expr), CVec3SubscriptCtx(2));
113         return *this;
114     }
115 
116     // This copy-assign is needed because a template is never
117     // considered for copy assignment.
operator =Vec3118     Vec3 &operator=(Vec3 const &that)
119     {
120         (*this)[0] = that[0];
121         (*this)[1] = that[1];
122         (*this)[2] = that[2];
123         return *this;
124     }
125 
printVec3126     void print() const
127     {
128         std::cout << '{' << (*this)[0]
129                   << ", " << (*this)[1]
130                   << ", " << (*this)[2]
131                   << '}' << std::endl;
132     }
133 };
134 
135 // The count_leaves() function uses the CountLeaves transform and
136 // to count the number of leaves in an expression.
137 template<typename Expr>
count_leaves(Expr const & expr)138 int count_leaves(Expr const &expr)
139 {
140     // Count the number of Vec3 terminals using the
141     // CountLeavesCtx evaluation context.
142     CountLeavesCtx ctx;
143     proto::eval(expr, ctx);
144 
145     // This is another way to count the leaves using a transform.
146     int i = 0;
147     BOOST_ASSERT( CountLeaves()(expr, i, i) == ctx.count );
148 
149     return ctx.count;
150 }
151 
main()152 int main()
153 {
154     Vec3 a, b, c;
155 
156     c = 4;
157 
158     b[0] = -1;
159     b[1] = -2;
160     b[2] = -3;
161 
162     a = b + c;
163 
164     a.print();
165 
166     Vec3 d;
167     BOOST_PROTO_AUTO(expr1, b + c);
168     d = expr1;
169     d.print();
170 
171     int num = count_leaves(expr1);
172     std::cout << num << std::endl;
173 
174     BOOST_PROTO_AUTO(expr2, b + 3 * c);
175     num = count_leaves(expr2);
176     std::cout << num << std::endl;
177 
178     BOOST_PROTO_AUTO(expr3, b + c * d);
179     num = count_leaves(expr3);
180     std::cout << num << std::endl;
181 
182     return 0;
183 }
184 //]
185