vec3.cpp 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. //[ Vec3
  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 is a simple example using proto::extends to extend a terminal type with
  8. // additional behaviors, and using custom contexts and proto::eval for
  9. // evaluating expressions. It is a port of the Vec3 example
  10. // from PETE (http://www.codesourcery.com/pooma/download.html).
  11. #include <iostream>
  12. #include <functional>
  13. #include <boost/assert.hpp>
  14. #include <boost/mpl/int.hpp>
  15. #include <boost/proto/core.hpp>
  16. #include <boost/proto/context.hpp>
  17. #include <boost/proto/proto_typeof.hpp>
  18. #include <boost/proto/transform.hpp>
  19. namespace mpl = boost::mpl;
  20. namespace proto = boost::proto;
  21. using proto::_;
  22. // Here is an evaluation context that indexes into a Vec3
  23. // expression, and combines the result.
  24. struct Vec3SubscriptCtx
  25. : proto::callable_context< Vec3SubscriptCtx const >
  26. {
  27. typedef int result_type;
  28. Vec3SubscriptCtx(int i)
  29. : i_(i)
  30. {}
  31. // Index array terminals with our subscript. Everything
  32. // else will be handled by the default evaluation context.
  33. int operator ()(proto::tag::terminal, int const (&arr)[3]) const
  34. {
  35. return arr[this->i_];
  36. }
  37. int i_;
  38. };
  39. // Here is an evaluation context that counts the number
  40. // of Vec3 terminals in an expression.
  41. struct CountLeavesCtx
  42. : proto::callable_context< CountLeavesCtx, proto::null_context >
  43. {
  44. CountLeavesCtx()
  45. : count(0)
  46. {}
  47. typedef void result_type;
  48. void operator ()(proto::tag::terminal, int const(&)[3])
  49. {
  50. ++this->count;
  51. }
  52. int count;
  53. };
  54. struct iplus : std::plus<int>, proto::callable {};
  55. // Here is a transform that does the same thing as the above context.
  56. // It demonstrates the use of the std::plus<> function object
  57. // with the fold transform. With minor modifications, this
  58. // transform could be used to calculate the leaf count at compile
  59. // time, rather than at runtime.
  60. struct CountLeaves
  61. : proto::or_<
  62. // match a Vec3 terminal, return 1
  63. proto::when<proto::terminal<int[3]>, mpl::int_<1>() >
  64. // match a terminal, return int() (which is 0)
  65. , proto::when<proto::terminal<_>, int() >
  66. // fold everything else, using std::plus<> to add
  67. // the leaf count of each child to the accumulated state.
  68. , proto::otherwise< proto::fold<_, int(), iplus(CountLeaves, proto::_state) > >
  69. >
  70. {};
  71. // Here is the Vec3 struct, which is a vector of 3 integers.
  72. struct Vec3
  73. : proto::extends<proto::terminal<int[3]>::type, Vec3>
  74. {
  75. explicit Vec3(int i=0, int j=0, int k=0)
  76. {
  77. (*this)[0] = i;
  78. (*this)[1] = j;
  79. (*this)[2] = k;
  80. }
  81. int &operator [](int i)
  82. {
  83. return proto::value(*this)[i];
  84. }
  85. int const &operator [](int i) const
  86. {
  87. return proto::value(*this)[i];
  88. }
  89. // Here we define a operator = for Vec3 terminals that
  90. // takes a Vec3 expression.
  91. template< typename Expr >
  92. Vec3 &operator =(Expr const & expr)
  93. {
  94. typedef Vec3SubscriptCtx const CVec3SubscriptCtx;
  95. (*this)[0] = proto::eval(proto::as_expr(expr), CVec3SubscriptCtx(0));
  96. (*this)[1] = proto::eval(proto::as_expr(expr), CVec3SubscriptCtx(1));
  97. (*this)[2] = proto::eval(proto::as_expr(expr), CVec3SubscriptCtx(2));
  98. return *this;
  99. }
  100. // This copy-assign is needed because a template is never
  101. // considered for copy assignment.
  102. Vec3 &operator=(Vec3 const &that)
  103. {
  104. (*this)[0] = that[0];
  105. (*this)[1] = that[1];
  106. (*this)[2] = that[2];
  107. return *this;
  108. }
  109. void print() const
  110. {
  111. std::cout << '{' << (*this)[0]
  112. << ", " << (*this)[1]
  113. << ", " << (*this)[2]
  114. << '}' << std::endl;
  115. }
  116. };
  117. // The count_leaves() function uses the CountLeaves transform and
  118. // to count the number of leaves in an expression.
  119. template<typename Expr>
  120. int count_leaves(Expr const &expr)
  121. {
  122. // Count the number of Vec3 terminals using the
  123. // CountLeavesCtx evaluation context.
  124. CountLeavesCtx ctx;
  125. proto::eval(expr, ctx);
  126. // This is another way to count the leaves using a transform.
  127. int i = 0;
  128. BOOST_ASSERT( CountLeaves()(expr, i, i) == ctx.count );
  129. return ctx.count;
  130. }
  131. int main()
  132. {
  133. Vec3 a, b, c;
  134. c = 4;
  135. b[0] = -1;
  136. b[1] = -2;
  137. b[2] = -3;
  138. a = b + c;
  139. a.print();
  140. Vec3 d;
  141. BOOST_PROTO_AUTO(expr1, b + c);
  142. d = expr1;
  143. d.print();
  144. int num = count_leaves(expr1);
  145. std::cout << num << std::endl;
  146. BOOST_PROTO_AUTO(expr2, b + 3 * c);
  147. num = count_leaves(expr2);
  148. std::cout << num << std::endl;
  149. BOOST_PROTO_AUTO(expr3, b + c * d);
  150. num = count_leaves(expr3);
  151. std::cout << num << std::endl;
  152. return 0;
  153. }
  154. //]