185 lines
4.8 KiB
C++
185 lines
4.8 KiB
C++
//[ Vec3
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// 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 is a simple example using proto::extends to extend a terminal type with
|
|
// additional behaviors, and using custom contexts and proto::eval for
|
|
// evaluating expressions. It is a port of the Vec3 example
|
|
// from PETE (http://www.codesourcery.com/pooma/download.html).
|
|
|
|
#include <iostream>
|
|
#include <functional>
|
|
#include <boost/assert.hpp>
|
|
#include <boost/mpl/int.hpp>
|
|
#include <boost/proto/core.hpp>
|
|
#include <boost/proto/context.hpp>
|
|
#include <boost/proto/proto_typeof.hpp>
|
|
#include <boost/proto/transform.hpp>
|
|
namespace mpl = boost::mpl;
|
|
namespace proto = boost::proto;
|
|
using proto::_;
|
|
|
|
// Here is an evaluation context that indexes into a Vec3
|
|
// expression, and combines the result.
|
|
struct Vec3SubscriptCtx
|
|
: proto::callable_context< Vec3SubscriptCtx const >
|
|
{
|
|
typedef int result_type;
|
|
|
|
Vec3SubscriptCtx(int 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 (&arr)[3]) const
|
|
{
|
|
return arr[this->i_];
|
|
}
|
|
|
|
int i_;
|
|
};
|
|
|
|
// Here is an evaluation context that counts the number
|
|
// of Vec3 terminals in an expression.
|
|
struct CountLeavesCtx
|
|
: proto::callable_context< CountLeavesCtx, proto::null_context >
|
|
{
|
|
CountLeavesCtx()
|
|
: count(0)
|
|
{}
|
|
|
|
typedef void result_type;
|
|
|
|
void operator ()(proto::tag::terminal, int const(&)[3])
|
|
{
|
|
++this->count;
|
|
}
|
|
|
|
int count;
|
|
};
|
|
|
|
struct iplus : std::plus<int>, proto::callable {};
|
|
|
|
// Here is a transform that does the same thing as the above context.
|
|
// It demonstrates the use of the std::plus<> function object
|
|
// with the fold transform. With minor modifications, this
|
|
// transform could be used to calculate the leaf count at compile
|
|
// time, rather than at runtime.
|
|
struct CountLeaves
|
|
: proto::or_<
|
|
// match a Vec3 terminal, return 1
|
|
proto::when<proto::terminal<int[3]>, mpl::int_<1>() >
|
|
// match a terminal, return int() (which is 0)
|
|
, proto::when<proto::terminal<_>, int() >
|
|
// fold everything else, using std::plus<> to add
|
|
// the leaf count of each child to the accumulated state.
|
|
, proto::otherwise< proto::fold<_, int(), iplus(CountLeaves, proto::_state) > >
|
|
>
|
|
{};
|
|
|
|
// Here is the Vec3 struct, which is a vector of 3 integers.
|
|
struct Vec3
|
|
: proto::extends<proto::terminal<int[3]>::type, Vec3>
|
|
{
|
|
explicit Vec3(int i=0, int j=0, int k=0)
|
|
{
|
|
(*this)[0] = i;
|
|
(*this)[1] = j;
|
|
(*this)[2] = k;
|
|
}
|
|
|
|
int &operator [](int i)
|
|
{
|
|
return proto::value(*this)[i];
|
|
}
|
|
|
|
int const &operator [](int i) const
|
|
{
|
|
return proto::value(*this)[i];
|
|
}
|
|
|
|
// Here we define a operator = for Vec3 terminals that
|
|
// takes a Vec3 expression.
|
|
template< typename Expr >
|
|
Vec3 &operator =(Expr const & expr)
|
|
{
|
|
typedef Vec3SubscriptCtx const CVec3SubscriptCtx;
|
|
(*this)[0] = proto::eval(proto::as_expr(expr), CVec3SubscriptCtx(0));
|
|
(*this)[1] = proto::eval(proto::as_expr(expr), CVec3SubscriptCtx(1));
|
|
(*this)[2] = proto::eval(proto::as_expr(expr), CVec3SubscriptCtx(2));
|
|
return *this;
|
|
}
|
|
|
|
// This copy-assign is needed because a template is never
|
|
// considered for copy assignment.
|
|
Vec3 &operator=(Vec3 const &that)
|
|
{
|
|
(*this)[0] = that[0];
|
|
(*this)[1] = that[1];
|
|
(*this)[2] = that[2];
|
|
return *this;
|
|
}
|
|
|
|
void print() const
|
|
{
|
|
std::cout << '{' << (*this)[0]
|
|
<< ", " << (*this)[1]
|
|
<< ", " << (*this)[2]
|
|
<< '}' << std::endl;
|
|
}
|
|
};
|
|
|
|
// The count_leaves() function uses the CountLeaves transform and
|
|
// to count the number of leaves in an expression.
|
|
template<typename Expr>
|
|
int count_leaves(Expr const &expr)
|
|
{
|
|
// Count the number of Vec3 terminals using the
|
|
// CountLeavesCtx evaluation context.
|
|
CountLeavesCtx ctx;
|
|
proto::eval(expr, ctx);
|
|
|
|
// This is another way to count the leaves using a transform.
|
|
int i = 0;
|
|
BOOST_ASSERT( CountLeaves()(expr, i, i) == ctx.count );
|
|
|
|
return ctx.count;
|
|
}
|
|
|
|
int main()
|
|
{
|
|
Vec3 a, b, c;
|
|
|
|
c = 4;
|
|
|
|
b[0] = -1;
|
|
b[1] = -2;
|
|
b[2] = -3;
|
|
|
|
a = b + c;
|
|
|
|
a.print();
|
|
|
|
Vec3 d;
|
|
BOOST_PROTO_AUTO(expr1, b + c);
|
|
d = expr1;
|
|
d.print();
|
|
|
|
int num = count_leaves(expr1);
|
|
std::cout << num << std::endl;
|
|
|
|
BOOST_PROTO_AUTO(expr2, b + 3 * c);
|
|
num = count_leaves(expr2);
|
|
std::cout << num << std::endl;
|
|
|
|
BOOST_PROTO_AUTO(expr3, b + c * d);
|
|
num = count_leaves(expr3);
|
|
std::cout << num << std::endl;
|
|
|
|
return 0;
|
|
}
|
|
//]
|