223 lines
6.1 KiB
C++
Executable File
223 lines
6.1 KiB
C++
Executable File
//[ 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;
|
|
}
|
|
//]
|