summaryrefslogtreecommitdiffstats
path: root/src/boost/libs/proto/example/vec3.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/boost/libs/proto/example/vec3.cpp')
-rw-r--r--src/boost/libs/proto/example/vec3.cpp184
1 files changed, 184 insertions, 0 deletions
diff --git a/src/boost/libs/proto/example/vec3.cpp b/src/boost/libs/proto/example/vec3.cpp
new file mode 100644
index 00000000..2da94872
--- /dev/null
+++ b/src/boost/libs/proto/example/vec3.cpp
@@ -0,0 +1,184 @@
+//[ 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;
+}
+//]