123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222 |
- //[ TArray
- ///////////////////////////////////////////////////////////////////////////////
- // 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 example constructs a mini-library for linear algebra, using
- // expression templates to eliminate the need for temporaries when
- // adding arrays of numbers. It duplicates the TArray example from
- // PETE (http://www.codesourcery.com/pooma/download.html)
- #include <iostream>
- #include <boost/mpl/int.hpp>
- #include <boost/proto/core.hpp>
- #include <boost/proto/context.hpp>
- namespace mpl = boost::mpl;
- namespace proto = boost::proto;
- using proto::_;
- // This grammar describes which TArray expressions
- // are allowed; namely, int and array terminals
- // plus, minus, multiplies and divides of TArray expressions.
- struct TArrayGrammar
- : proto::or_<
- proto::terminal< int >
- , proto::terminal< int[3] >
- , proto::plus< TArrayGrammar, TArrayGrammar >
- , proto::minus< TArrayGrammar, TArrayGrammar >
- , proto::multiplies< TArrayGrammar, TArrayGrammar >
- , proto::divides< TArrayGrammar, TArrayGrammar >
- >
- {};
- template<typename Expr>
- struct TArrayExpr;
- // Tell proto that in the TArrayDomain, all
- // expressions should be wrapped in TArrayExpr<> and
- // must conform to the TArrayGrammar
- struct TArrayDomain
- : proto::domain<proto::generator<TArrayExpr>, TArrayGrammar>
- {};
- // Here is an evaluation context that indexes into a TArray
- // expression, and combines the result.
- struct TArraySubscriptCtx
- : proto::callable_context< TArraySubscriptCtx const >
- {
- typedef int result_type;
- TArraySubscriptCtx(std::ptrdiff_t 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 (&data)[3]) const
- {
- return data[this->i_];
- }
- std::ptrdiff_t i_;
- };
- // Here is an evaluation context that prints a TArray expression.
- struct TArrayPrintCtx
- : proto::callable_context< TArrayPrintCtx const >
- {
- typedef std::ostream &result_type;
- TArrayPrintCtx() {}
- std::ostream &operator ()(proto::tag::terminal, int i) const
- {
- return std::cout << i;
- }
- std::ostream &operator ()(proto::tag::terminal, int const (&arr)[3]) const
- {
- return std::cout << '{' << arr[0] << ", " << arr[1] << ", " << arr[2] << '}';
- }
- template<typename L, typename R>
- std::ostream &operator ()(proto::tag::plus, L const &l, R const &r) const
- {
- return std::cout << '(' << l << " + " << r << ')';
- }
- template<typename L, typename R>
- std::ostream &operator ()(proto::tag::minus, L const &l, R const &r) const
- {
- return std::cout << '(' << l << " - " << r << ')';
- }
- template<typename L, typename R>
- std::ostream &operator ()(proto::tag::multiplies, L const &l, R const &r) const
- {
- return std::cout << l << " * " << r;
- }
- template<typename L, typename R>
- std::ostream &operator ()(proto::tag::divides, L const &l, R const &r) const
- {
- return std::cout << l << " / " << r;
- }
- };
- // Here is the domain-specific expression wrapper, which overrides
- // operator [] to evaluate the expression using the TArraySubscriptCtx.
- template<typename Expr>
- struct TArrayExpr
- : proto::extends<Expr, TArrayExpr<Expr>, TArrayDomain>
- {
- typedef proto::extends<Expr, TArrayExpr<Expr>, TArrayDomain> base_type;
- TArrayExpr( Expr const & expr = Expr() )
- : base_type( expr )
- {}
- // Use the TArraySubscriptCtx to implement subscripting
- // of a TArray expression tree.
- int operator []( std::ptrdiff_t i ) const
- {
- TArraySubscriptCtx const ctx(i);
- return proto::eval(*this, ctx);
- }
- // Use the TArrayPrintCtx to display a TArray expression tree.
- friend std::ostream &operator <<(std::ostream &sout, TArrayExpr<Expr> const &expr)
- {
- TArrayPrintCtx const ctx;
- return proto::eval(expr, ctx);
- }
- };
- // Here is our TArray terminal, implemented in terms of TArrayExpr
- // It is basically just an array of 3 integers.
- struct TArray
- : TArrayExpr< proto::terminal< int[3] >::type >
- {
- explicit TArray( int i = 0, int j = 0, int k = 0 )
- {
- (*this)[0] = i;
- (*this)[1] = j;
- (*this)[2] = k;
- }
- // Here we override operator [] to give read/write access to
- // the elements of the array. (We could use the TArrayExpr
- // operator [] if we made the subscript context smarter about
- // returning non-const reference when appropriate.)
- int &operator [](std::ptrdiff_t i)
- {
- return proto::value(*this)[i];
- }
- int const &operator [](std::ptrdiff_t i) const
- {
- return proto::value(*this)[i];
- }
- // Here we define a operator = for TArray terminals that
- // takes a TArray expression.
- template< typename Expr >
- TArray &operator =(Expr const & expr)
- {
- // proto::as_expr<TArrayDomain>(expr) is the same as
- // expr unless expr is an integer, in which case it
- // is made into a TArrayExpr terminal first.
- return this->assign(proto::as_expr<TArrayDomain>(expr));
- }
- template< typename Expr >
- TArray &printAssign(Expr const & expr)
- {
- *this = expr;
- std::cout << *this << " = " << expr << std::endl;
- return *this;
- }
- private:
- template< typename Expr >
- TArray &assign(Expr const & expr)
- {
- // expr[i] here uses TArraySubscriptCtx under the covers.
- (*this)[0] = expr[0];
- (*this)[1] = expr[1];
- (*this)[2] = expr[2];
- return *this;
- }
- };
- int main()
- {
- TArray a(3,1,2);
- TArray b;
- std::cout << a << std::endl;
- std::cout << b << std::endl;
- b[0] = 7; b[1] = 33; b[2] = -99;
- TArray c(a);
- std::cout << c << std::endl;
- a = 0;
- std::cout << a << std::endl;
- std::cout << b << std::endl;
- std::cout << c << std::endl;
- a = b + c;
- std::cout << a << std::endl;
- a.printAssign(b+c*(b + 3*c));
- return 0;
- }
- //]
|