• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //[ Vector
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 an example of using BOOST_PROTO_DEFINE_OPERATORS to Protofy
8 // expressions using std::vector<>, a non-proto type. It is a port of the
9 // Vector example from PETE (http://www.codesourcery.com/pooma/download.html).
10 
11 #include <vector>
12 #include <iostream>
13 #include <stdexcept>
14 #include <boost/mpl/bool.hpp>
15 #include <boost/proto/core.hpp>
16 #include <boost/proto/debug.hpp>
17 #include <boost/proto/context.hpp>
18 #include <boost/utility/enable_if.hpp>
19 namespace mpl = boost::mpl;
20 namespace proto = boost::proto;
21 using proto::_;
22 
23 template<typename Expr>
24 struct VectorExpr;
25 
26 // Here is an evaluation context that indexes into a std::vector
27 // expression and combines the result.
28 struct VectorSubscriptCtx
29 {
VectorSubscriptCtxVectorSubscriptCtx30     VectorSubscriptCtx(std::size_t i)
31       : i_(i)
32     {}
33 
34     // Unless this is a vector terminal, use the
35     // default evaluation context
36     template<typename Expr, typename EnableIf = void>
37     struct eval
38       : proto::default_eval<Expr, VectorSubscriptCtx const>
39     {};
40 
41     // Index vector terminals with our subscript.
42     template<typename Expr>
43     struct eval<
44         Expr
45       , typename boost::enable_if<
46             proto::matches<Expr, proto::terminal<std::vector<_, _> > >
47         >::type
48     >
49     {
50         typedef typename proto::result_of::value<Expr>::type::value_type result_type;
51 
operator ()VectorSubscriptCtx::eval52         result_type operator ()(Expr &expr, VectorSubscriptCtx const &ctx) const
53         {
54             return proto::value(expr)[ctx.i_];
55         }
56     };
57 
58     std::size_t i_;
59 };
60 
61 // Here is an evaluation context that verifies that all the
62 // vectors in an expression have the same size.
63 struct VectorSizeCtx
64 {
VectorSizeCtxVectorSizeCtx65     VectorSizeCtx(std::size_t size)
66       : size_(size)
67     {}
68 
69     // Unless this is a vector terminal, use the
70     // null evaluation context
71     template<typename Expr, typename EnableIf = void>
72     struct eval
73       : proto::null_eval<Expr, VectorSizeCtx const>
74     {};
75 
76     // Index array terminals with our subscript. Everything
77     // else will be handled by the default evaluation context.
78     template<typename Expr>
79     struct eval<
80         Expr
81       , typename boost::enable_if<
82             proto::matches<Expr, proto::terminal<std::vector<_, _> > >
83         >::type
84     >
85     {
86         typedef void result_type;
87 
operator ()VectorSizeCtx::eval88         result_type operator ()(Expr &expr, VectorSizeCtx const &ctx) const
89         {
90             if(ctx.size_ != proto::value(expr).size())
91             {
92                 throw std::runtime_error("LHS and RHS are not compatible");
93             }
94         }
95     };
96 
97     std::size_t size_;
98 };
99 
100 // A grammar which matches all the assignment operators,
101 // so we can easily disable them.
102 struct AssignOps
103   : proto::switch_<struct AssignOpsCases>
104 {};
105 
106 // Here are the cases used by the switch_ above.
107 struct AssignOpsCases
108 {
109     template<typename Tag, int D = 0> struct case_  : proto::not_<_> {};
110 
111     template<int D> struct case_< proto::tag::plus_assign, D >         : _ {};
112     template<int D> struct case_< proto::tag::minus_assign, D >        : _ {};
113     template<int D> struct case_< proto::tag::multiplies_assign, D >   : _ {};
114     template<int D> struct case_< proto::tag::divides_assign, D >      : _ {};
115     template<int D> struct case_< proto::tag::modulus_assign, D >      : _ {};
116     template<int D> struct case_< proto::tag::shift_left_assign, D >   : _ {};
117     template<int D> struct case_< proto::tag::shift_right_assign, D >  : _ {};
118     template<int D> struct case_< proto::tag::bitwise_and_assign, D >  : _ {};
119     template<int D> struct case_< proto::tag::bitwise_or_assign, D >   : _ {};
120     template<int D> struct case_< proto::tag::bitwise_xor_assign, D >  : _ {};
121 };
122 
123 // A vector grammar is a terminal or some op that is not an
124 // assignment op. (Assignment will be handled specially.)
125 struct VectorGrammar
126   : proto::or_<
127         proto::terminal<_>
128       , proto::and_<proto::nary_expr<_, proto::vararg<VectorGrammar> >, proto::not_<AssignOps> >
129     >
130 {};
131 
132 // Expressions in the vector domain will be wrapped in VectorExpr<>
133 // and must conform to the VectorGrammar
134 struct VectorDomain
135   : proto::domain<proto::generator<VectorExpr>, VectorGrammar>
136 {};
137 
138 // Here is VectorExpr, which extends a proto expr type by
139 // giving it an operator [] which uses the VectorSubscriptCtx
140 // to evaluate an expression with a given index.
141 template<typename Expr>
142 struct VectorExpr
143   : proto::extends<Expr, VectorExpr<Expr>, VectorDomain>
144 {
VectorExprVectorExpr145     explicit VectorExpr(Expr const &expr)
146       : proto::extends<Expr, VectorExpr<Expr>, VectorDomain>(expr)
147     {}
148 
149     // Use the VectorSubscriptCtx to implement subscripting
150     // of a Vector expression tree.
151     typename proto::result_of::eval<Expr const, VectorSubscriptCtx const>::type
operator []VectorExpr152     operator []( std::size_t i ) const
153     {
154         VectorSubscriptCtx const ctx(i);
155         return proto::eval(*this, ctx);
156     }
157 };
158 
159 // Define a trait type for detecting vector terminals, to
160 // be used by the BOOST_PROTO_DEFINE_OPERATORS macro below.
161 template<typename T>
162 struct IsVector
163   : mpl::false_
164 {};
165 
166 template<typename T, typename A>
167 struct IsVector<std::vector<T, A> >
168   : mpl::true_
169 {};
170 
171 namespace VectorOps
172 {
173     // This defines all the overloads to make expressions involving
174     // std::vector to build expression templates.
175     BOOST_PROTO_DEFINE_OPERATORS(IsVector, VectorDomain)
176 
177     typedef VectorSubscriptCtx const CVectorSubscriptCtx;
178 
179     // Assign to a vector from some expression.
180     template<typename T, typename A, typename Expr>
assign(std::vector<T,A> & arr,Expr const & expr)181     std::vector<T, A> &assign(std::vector<T, A> &arr, Expr const &expr)
182     {
183         VectorSizeCtx const size(arr.size());
184         proto::eval(proto::as_expr<VectorDomain>(expr), size); // will throw if the sizes don't match
185         for(std::size_t i = 0; i < arr.size(); ++i)
186         {
187             arr[i] = proto::as_expr<VectorDomain>(expr)[i];
188         }
189         return arr;
190     }
191 
192     // Add-assign to a vector from some expression.
193     template<typename T, typename A, typename Expr>
operator +=(std::vector<T,A> & arr,Expr const & expr)194     std::vector<T, A> &operator +=(std::vector<T, A> &arr, Expr const &expr)
195     {
196         VectorSizeCtx const size(arr.size());
197         proto::eval(proto::as_expr<VectorDomain>(expr), size); // will throw if the sizes don't match
198         for(std::size_t i = 0; i < arr.size(); ++i)
199         {
200             arr[i] += proto::as_expr<VectorDomain>(expr)[i];
201         }
202         return arr;
203     }
204 }
205 
main()206 int main()
207 {
208     using namespace VectorOps;
209 
210     int i;
211     const int n = 10;
212     std::vector<int> a,b,c,d;
213     std::vector<double> e(n);
214 
215     for (i = 0; i < n; ++i)
216     {
217         a.push_back(i);
218         b.push_back(2*i);
219         c.push_back(3*i);
220         d.push_back(i);
221     }
222 
223     VectorOps::assign(b, 2);
224     VectorOps::assign(d, a + b * c);
225     a += if_else(d < 30, b, c);
226 
227     VectorOps::assign(e, c);
228     e += e - 4 / (c + 1);
229 
230     for (i = 0; i < n; ++i)
231     {
232         std::cout
233             << " a(" << i << ") = " << a[i]
234             << " b(" << i << ") = " << b[i]
235             << " c(" << i << ") = " << c[i]
236             << " d(" << i << ") = " << d[i]
237             << " e(" << i << ") = " << e[i]
238             << std::endl;
239     }
240 }
241 //]
242