1 //[ TArray
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 example constructs a mini-library for linear algebra, using
8 // expression templates to eliminate the need for temporaries when
9 // adding arrays of numbers. It duplicates the TArray example from
10 // PETE (http://www.codesourcery.com/pooma/download.html)
11 
12 #include <iostream>
13 #include <boost/mpl/int.hpp>
14 #include <boost/proto/core.hpp>
15 #include <boost/proto/context.hpp>
16 namespace mpl = boost::mpl;
17 namespace proto = boost::proto;
18 using proto::_;
19 
20 // This grammar describes which TArray expressions
21 // are allowed; namely, int and array terminals
22 // plus, minus, multiplies and divides of TArray expressions.
23 struct TArrayGrammar
24   : proto::or_<
25         proto::terminal< int >
26       , proto::terminal< int[3] >
27       , proto::plus< TArrayGrammar, TArrayGrammar >
28       , proto::minus< TArrayGrammar, TArrayGrammar >
29       , proto::multiplies< TArrayGrammar, TArrayGrammar >
30       , proto::divides< TArrayGrammar, TArrayGrammar >
31     >
32 {};
33 
34 template<typename Expr>
35 struct TArrayExpr;
36 
37 // Tell proto that in the TArrayDomain, all
38 // expressions should be wrapped in TArrayExpr<> and
39 // must conform to the TArrayGrammar
40 struct TArrayDomain
41   : proto::domain<proto::generator<TArrayExpr>, TArrayGrammar>
42 {};
43 
44 // Here is an evaluation context that indexes into a TArray
45 // expression, and combines the result.
46 struct TArraySubscriptCtx
47   : proto::callable_context< TArraySubscriptCtx const >
48 {
49     typedef int result_type;
50 
TArraySubscriptCtxTArraySubscriptCtx51     TArraySubscriptCtx(std::ptrdiff_t i)
52       : i_(i)
53     {}
54 
55     // Index array terminals with our subscript. Everything
56     // else will be handled by the default evaluation context.
operator ()TArraySubscriptCtx57     int operator ()(proto::tag::terminal, int const (&data)[3]) const
58     {
59         return data[this->i_];
60     }
61 
62     std::ptrdiff_t i_;
63 };
64 
65 // Here is an evaluation context that prints a TArray expression.
66 struct TArrayPrintCtx
67   : proto::callable_context< TArrayPrintCtx const >
68 {
69     typedef std::ostream &result_type;
70 
TArrayPrintCtxTArrayPrintCtx71     TArrayPrintCtx() {}
72 
operator ()TArrayPrintCtx73     std::ostream &operator ()(proto::tag::terminal, int i) const
74     {
75         return std::cout << i;
76     }
77 
operator ()TArrayPrintCtx78     std::ostream &operator ()(proto::tag::terminal, int const (&arr)[3]) const
79     {
80         return std::cout << '{' << arr[0] << ", " << arr[1] << ", " << arr[2] << '}';
81     }
82 
83     template<typename L, typename R>
operator ()TArrayPrintCtx84     std::ostream &operator ()(proto::tag::plus, L const &l, R const &r) const
85     {
86         return std::cout << '(' << l << " + " << r << ')';
87     }
88 
89     template<typename L, typename R>
operator ()TArrayPrintCtx90     std::ostream &operator ()(proto::tag::minus, L const &l, R const &r) const
91     {
92         return std::cout << '(' << l << " - " << r << ')';
93     }
94 
95     template<typename L, typename R>
operator ()TArrayPrintCtx96     std::ostream &operator ()(proto::tag::multiplies, L const &l, R const &r) const
97     {
98         return std::cout << l << " * " << r;
99     }
100 
101     template<typename L, typename R>
operator ()TArrayPrintCtx102     std::ostream &operator ()(proto::tag::divides, L const &l, R const &r) const
103     {
104         return std::cout << l << " / " << r;
105     }
106 };
107 
108 // Here is the domain-specific expression wrapper, which overrides
109 // operator [] to evaluate the expression using the TArraySubscriptCtx.
110 template<typename Expr>
111 struct TArrayExpr
112   : proto::extends<Expr, TArrayExpr<Expr>, TArrayDomain>
113 {
114     typedef proto::extends<Expr, TArrayExpr<Expr>, TArrayDomain> base_type;
115 
TArrayExprTArrayExpr116     TArrayExpr( Expr const & expr = Expr() )
117       : base_type( expr )
118     {}
119 
120     // Use the TArraySubscriptCtx to implement subscripting
121     // of a TArray expression tree.
operator []TArrayExpr122     int operator []( std::ptrdiff_t i ) const
123     {
124         TArraySubscriptCtx const ctx(i);
125         return proto::eval(*this, ctx);
126     }
127 
128     // Use the TArrayPrintCtx to display a TArray expression tree.
operator <<(std::ostream & sout,TArrayExpr<Expr> const & expr)129     friend std::ostream &operator <<(std::ostream &sout, TArrayExpr<Expr> const &expr)
130     {
131         TArrayPrintCtx const ctx;
132         return proto::eval(expr, ctx);
133     }
134 };
135 
136 // Here is our TArray terminal, implemented in terms of TArrayExpr
137 // It is basically just an array of 3 integers.
138 struct TArray
139   : TArrayExpr< proto::terminal< int[3] >::type >
140 {
TArrayTArray141     explicit TArray( int i = 0, int j = 0, int k = 0 )
142     {
143         (*this)[0] = i;
144         (*this)[1] = j;
145         (*this)[2] = k;
146     }
147 
148     // Here we override operator [] to give read/write access to
149     // the elements of the array. (We could use the TArrayExpr
150     // operator [] if we made the subscript context smarter about
151     // returning non-const reference when appropriate.)
operator []TArray152     int &operator [](std::ptrdiff_t i)
153     {
154         return proto::value(*this)[i];
155     }
156 
operator []TArray157     int const &operator [](std::ptrdiff_t i) const
158     {
159         return proto::value(*this)[i];
160     }
161 
162     // Here we define a operator = for TArray terminals that
163     // takes a TArray expression.
164     template< typename Expr >
operator =TArray165     TArray &operator =(Expr const & expr)
166     {
167         // proto::as_expr<TArrayDomain>(expr) is the same as
168         // expr unless expr is an integer, in which case it
169         // is made into a TArrayExpr terminal first.
170         return this->assign(proto::as_expr<TArrayDomain>(expr));
171     }
172 
173     template< typename Expr >
printAssignTArray174     TArray &printAssign(Expr const & expr)
175     {
176         *this = expr;
177         std::cout << *this << " = " << expr << std::endl;
178         return *this;
179     }
180 
181 private:
182     template< typename Expr >
assignTArray183     TArray &assign(Expr const & expr)
184     {
185         // expr[i] here uses TArraySubscriptCtx under the covers.
186         (*this)[0] = expr[0];
187         (*this)[1] = expr[1];
188         (*this)[2] = expr[2];
189         return *this;
190     }
191 };
192 
main()193 int main()
194 {
195     TArray a(3,1,2);
196 
197     TArray b;
198 
199     std::cout << a << std::endl;
200     std::cout << b << std::endl;
201 
202     b[0] = 7; b[1] = 33; b[2] = -99;
203 
204     TArray c(a);
205 
206     std::cout << c << std::endl;
207 
208     a = 0;
209 
210     std::cout << a << std::endl;
211     std::cout << b << std::endl;
212     std::cout << c << std::endl;
213 
214     a = b + c;
215 
216     std::cout << a << std::endl;
217 
218     a.printAssign(b+c*(b + 3*c));
219 
220     return 0;
221 }
222 //]
223