• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //[ Mixed
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<> and std::list, non-proto types. It is a port
9 // of the Mixed example from PETE.
10 // (http://www.codesourcery.com/pooma/download.html).
11 
12 #include <list>
13 #include <cmath>
14 #include <vector>
15 #include <complex>
16 #include <iostream>
17 #include <stdexcept>
18 #include <boost/proto/core.hpp>
19 #include <boost/proto/debug.hpp>
20 #include <boost/proto/context.hpp>
21 #include <boost/proto/transform.hpp>
22 #include <boost/utility/enable_if.hpp>
23 #include <boost/typeof/std/list.hpp>
24 #include <boost/typeof/std/vector.hpp>
25 #include <boost/typeof/std/complex.hpp>
26 #include <boost/type_traits/remove_reference.hpp>
27 namespace proto = boost::proto;
28 namespace mpl = boost::mpl;
29 using proto::_;
30 
31 template<typename Expr>
32 struct MixedExpr;
33 
34 template<typename Iter>
35 struct iterator_wrapper
36 {
37     typedef Iter iterator;
38 
iterator_wrapperiterator_wrapper39     explicit iterator_wrapper(Iter iter)
40       : it(iter)
41     {}
42 
43     mutable Iter it;
44 };
45 
46 struct begin : proto::callable
47 {
48     template<class Sig>
49     struct result;
50 
51     template<class This, class Cont>
52     struct result<This(Cont)>
53       : proto::result_of::as_expr<
54             iterator_wrapper<typename boost::remove_reference<Cont>::type::const_iterator>
55         >
56     {};
57 
58     template<typename Cont>
59     typename result<begin(Cont const &)>::type
operator ()begin60     operator ()(Cont const &cont) const
61     {
62         iterator_wrapper<typename Cont::const_iterator> it(cont.begin());
63         return proto::as_expr(it);
64     }
65 };
66 
67 // Here is a grammar that replaces vector and list terminals with their
68 // begin iterators
69 struct Begin
70   : proto::or_<
71         proto::when< proto::terminal< std::vector<_, _> >, begin(proto::_value) >
72       , proto::when< proto::terminal< std::list<_, _> >, begin(proto::_value) >
73       , proto::when< proto::terminal<_> >
74       , proto::when< proto::nary_expr<_, proto::vararg<Begin> > >
75     >
76 {};
77 
78 // Here is an evaluation context that dereferences iterator
79 // terminals.
80 struct DereferenceCtx
81 {
82     // Unless this is an iterator terminal, use the
83     // default evaluation context
84     template<typename Expr, typename EnableIf = void>
85     struct eval
86       : proto::default_eval<Expr, DereferenceCtx const>
87     {};
88 
89     // Dereference iterator terminals.
90     template<typename Expr>
91     struct eval<
92         Expr
93       , typename boost::enable_if<
94             proto::matches<Expr, proto::terminal<iterator_wrapper<_> > >
95         >::type
96     >
97     {
98         typedef typename proto::result_of::value<Expr>::type IteratorWrapper;
99         typedef typename IteratorWrapper::iterator iterator;
100         typedef typename std::iterator_traits<iterator>::reference result_type;
101 
operator ()DereferenceCtx::eval102         result_type operator ()(Expr &expr, DereferenceCtx const &) const
103         {
104             return *proto::value(expr).it;
105         }
106     };
107 };
108 
109 // Here is an evaluation context that increments iterator
110 // terminals.
111 struct IncrementCtx
112 {
113     // Unless this is an iterator terminal, use the
114     // default evaluation context
115     template<typename Expr, typename EnableIf = void>
116     struct eval
117       : proto::null_eval<Expr, IncrementCtx const>
118     {};
119 
120     // advance iterator terminals.
121     template<typename Expr>
122     struct eval<
123         Expr
124       , typename boost::enable_if<
125             proto::matches<Expr, proto::terminal<iterator_wrapper<_> > >
126         >::type
127     >
128     {
129         typedef void result_type;
130 
operator ()IncrementCtx::eval131         result_type operator ()(Expr &expr, IncrementCtx const &) const
132         {
133             ++proto::value(expr).it;
134         }
135     };
136 };
137 
138 // A grammar which matches all the assignment operators,
139 // so we can easily disable them.
140 struct AssignOps
141   : proto::switch_<struct AssignOpsCases>
142 {};
143 
144 // Here are the cases used by the switch_ above.
145 struct AssignOpsCases
146 {
147     template<typename Tag, int D = 0> struct case_  : proto::not_<_> {};
148 
149     template<int D> struct case_< proto::tag::plus_assign, D >         : _ {};
150     template<int D> struct case_< proto::tag::minus_assign, D >        : _ {};
151     template<int D> struct case_< proto::tag::multiplies_assign, D >   : _ {};
152     template<int D> struct case_< proto::tag::divides_assign, D >      : _ {};
153     template<int D> struct case_< proto::tag::modulus_assign, D >      : _ {};
154     template<int D> struct case_< proto::tag::shift_left_assign, D >   : _ {};
155     template<int D> struct case_< proto::tag::shift_right_assign, D >  : _ {};
156     template<int D> struct case_< proto::tag::bitwise_and_assign, D >  : _ {};
157     template<int D> struct case_< proto::tag::bitwise_or_assign, D >   : _ {};
158     template<int D> struct case_< proto::tag::bitwise_xor_assign, D >  : _ {};
159 };
160 
161 // An expression conforms to the MixedGrammar if it is a terminal or some
162 // op that is not an assignment op. (Assignment will be handled specially.)
163 struct MixedGrammar
164   : proto::or_<
165         proto::terminal<_>
166       , proto::and_<
167             proto::nary_expr<_, proto::vararg<MixedGrammar> >
168           , proto::not_<AssignOps>
169         >
170     >
171 {};
172 
173 // Expressions in the MixedDomain will be wrapped in MixedExpr<>
174 // and must conform to the MixedGrammar
175 struct MixedDomain
176   : proto::domain<proto::generator<MixedExpr>, MixedGrammar>
177 {};
178 
179 // Here is MixedExpr, a wrapper for expression types in the MixedDomain.
180 template<typename Expr>
181 struct MixedExpr
182   : proto::extends<Expr, MixedExpr<Expr>, MixedDomain>
183 {
MixedExprMixedExpr184     explicit MixedExpr(Expr const &expr)
185       : MixedExpr::proto_extends(expr)
186     {}
187 private:
188     // hide this:
189     using proto::extends<Expr, MixedExpr<Expr>, MixedDomain>::operator [];
190 };
191 
192 // Define a trait type for detecting vector and list terminals, to
193 // be used by the BOOST_PROTO_DEFINE_OPERATORS macro below.
194 template<typename T>
195 struct IsMixed
196   : mpl::false_
197 {};
198 
199 template<typename T, typename A>
200 struct IsMixed<std::list<T, A> >
201   : mpl::true_
202 {};
203 
204 template<typename T, typename A>
205 struct IsMixed<std::vector<T, A> >
206   : mpl::true_
207 {};
208 
209 namespace MixedOps
210 {
211     // This defines all the overloads to make expressions involving
212     // std::vector to build expression templates.
213     BOOST_PROTO_DEFINE_OPERATORS(IsMixed, MixedDomain)
214 
215     struct assign_op
216     {
217         template<typename T, typename U>
operator ()MixedOps::assign_op218         void operator ()(T &t, U const &u) const
219         {
220             t = u;
221         }
222     };
223 
224     struct plus_assign_op
225     {
226         template<typename T, typename U>
operator ()MixedOps::plus_assign_op227         void operator ()(T &t, U const &u) const
228         {
229             t += u;
230         }
231     };
232 
233     struct minus_assign_op
234     {
235         template<typename T, typename U>
operator ()MixedOps::minus_assign_op236         void operator ()(T &t, U const &u) const
237         {
238             t -= u;
239         }
240     };
241 
242     struct sin_
243     {
244         template<typename Sig>
245         struct result;
246 
247         template<typename This, typename Arg>
248         struct result<This(Arg)>
249           : boost::remove_const<typename boost::remove_reference<Arg>::type>
250         {};
251 
252         template<typename Arg>
operator ()MixedOps::sin_253         Arg operator ()(Arg const &a) const
254         {
255             return std::sin(a);
256         }
257     };
258 
259     template<typename A>
260     typename proto::result_of::make_expr<
261         proto::tag::function
262       , MixedDomain
263       , sin_ const
264       , A const &
sin(A const & a)265     >::type sin(A const &a)
266     {
267         return proto::make_expr<proto::tag::function, MixedDomain>(sin_(), boost::ref(a));
268     }
269 
270     template<typename FwdIter, typename Expr, typename Op>
evaluate(FwdIter begin,FwdIter end,Expr const & expr,Op op)271     void evaluate(FwdIter begin, FwdIter end, Expr const &expr, Op op)
272     {
273         IncrementCtx const inc = {};
274         DereferenceCtx const deref = {};
275         typename boost::result_of<Begin(Expr const &)>::type expr2 = Begin()(expr);
276         for(; begin != end; ++begin)
277         {
278             op(*begin, proto::eval(expr2, deref));
279             proto::eval(expr2, inc);
280         }
281     }
282 
283     // Add-assign to a vector from some expression.
284     template<typename T, typename A, typename Expr>
assign(std::vector<T,A> & arr,Expr const & expr)285     std::vector<T, A> &assign(std::vector<T, A> &arr, Expr const &expr)
286     {
287         evaluate(arr.begin(), arr.end(), proto::as_expr<MixedDomain>(expr), assign_op());
288         return arr;
289     }
290 
291     // Add-assign to a list from some expression.
292     template<typename T, typename A, typename Expr>
assign(std::list<T,A> & arr,Expr const & expr)293     std::list<T, A> &assign(std::list<T, A> &arr, Expr const &expr)
294     {
295         evaluate(arr.begin(), arr.end(), proto::as_expr<MixedDomain>(expr), assign_op());
296         return arr;
297     }
298 
299     // Add-assign to a vector from some expression.
300     template<typename T, typename A, typename Expr>
operator +=(std::vector<T,A> & arr,Expr const & expr)301     std::vector<T, A> &operator +=(std::vector<T, A> &arr, Expr const &expr)
302     {
303         evaluate(arr.begin(), arr.end(), proto::as_expr<MixedDomain>(expr), plus_assign_op());
304         return arr;
305     }
306 
307     // Add-assign to a list from some expression.
308     template<typename T, typename A, typename Expr>
operator +=(std::list<T,A> & arr,Expr const & expr)309     std::list<T, A> &operator +=(std::list<T, A> &arr, Expr const &expr)
310     {
311         evaluate(arr.begin(), arr.end(), proto::as_expr<MixedDomain>(expr), plus_assign_op());
312         return arr;
313     }
314 
315     // Minus-assign to a vector from some expression.
316     template<typename T, typename A, typename Expr>
operator -=(std::vector<T,A> & arr,Expr const & expr)317     std::vector<T, A> &operator -=(std::vector<T, A> &arr, Expr const &expr)
318     {
319         evaluate(arr.begin(), arr.end(), proto::as_expr<MixedDomain>(expr), minus_assign_op());
320         return arr;
321     }
322 
323     // Minus-assign to a list from some expression.
324     template<typename T, typename A, typename Expr>
operator -=(std::list<T,A> & arr,Expr const & expr)325     std::list<T, A> &operator -=(std::list<T, A> &arr, Expr const &expr)
326     {
327         evaluate(arr.begin(), arr.end(), proto::as_expr<MixedDomain>(expr), minus_assign_op());
328         return arr;
329     }
330 }
331 
main()332 int main()
333 {
334     using namespace MixedOps;
335 
336     int n = 10;
337     std::vector<int> a,b,c,d;
338     std::list<double> e;
339     std::list<std::complex<double> > f;
340 
341     int i;
342     for(i = 0;i < n; ++i)
343     {
344         a.push_back(i);
345         b.push_back(2*i);
346         c.push_back(3*i);
347         d.push_back(i);
348         e.push_back(0.0);
349         f.push_back(std::complex<double>(1.0, 1.0));
350     }
351 
352     MixedOps::assign(b, 2);
353     MixedOps::assign(d, a + b * c);
354     a += if_else(d < 30, b, c);
355 
356     MixedOps::assign(e, c);
357     e += e - 4 / (c + 1);
358 
359     f -= sin(0.1 * e * std::complex<double>(0.2, 1.2));
360 
361     std::list<double>::const_iterator ei = e.begin();
362     std::list<std::complex<double> >::const_iterator fi = f.begin();
363     for (i = 0; i < n; ++i)
364     {
365         std::cout
366             << "a(" << i << ") = " << a[i]
367             << " b(" << i << ") = " << b[i]
368             << " c(" << i << ") = " << c[i]
369             << " d(" << i << ") = " << d[i]
370             << " e(" << i << ") = " << *ei++
371             << " f(" << i << ") = " << *fi++
372             << std::endl;
373     }
374 }
375 //]
376