vector.cpp 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241
  1. //[ Vector
  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 an example of using BOOST_PROTO_DEFINE_OPERATORS to Protofy
  8. // expressions using std::vector<>, a non-proto type. It is a port of the
  9. // Vector example from PETE (http://www.codesourcery.com/pooma/download.html).
  10. #include <vector>
  11. #include <iostream>
  12. #include <stdexcept>
  13. #include <boost/mpl/bool.hpp>
  14. #include <boost/proto/core.hpp>
  15. #include <boost/proto/debug.hpp>
  16. #include <boost/proto/context.hpp>
  17. #include <boost/utility/enable_if.hpp>
  18. namespace mpl = boost::mpl;
  19. namespace proto = boost::proto;
  20. using proto::_;
  21. template<typename Expr>
  22. struct VectorExpr;
  23. // Here is an evaluation context that indexes into a std::vector
  24. // expression and combines the result.
  25. struct VectorSubscriptCtx
  26. {
  27. VectorSubscriptCtx(std::size_t i)
  28. : i_(i)
  29. {}
  30. // Unless this is a vector terminal, use the
  31. // default evaluation context
  32. template<typename Expr, typename EnableIf = void>
  33. struct eval
  34. : proto::default_eval<Expr, VectorSubscriptCtx const>
  35. {};
  36. // Index vector terminals with our subscript.
  37. template<typename Expr>
  38. struct eval<
  39. Expr
  40. , typename boost::enable_if<
  41. proto::matches<Expr, proto::terminal<std::vector<_, _> > >
  42. >::type
  43. >
  44. {
  45. typedef typename proto::result_of::value<Expr>::type::value_type result_type;
  46. result_type operator ()(Expr &expr, VectorSubscriptCtx const &ctx) const
  47. {
  48. return proto::value(expr)[ctx.i_];
  49. }
  50. };
  51. std::size_t i_;
  52. };
  53. // Here is an evaluation context that verifies that all the
  54. // vectors in an expression have the same size.
  55. struct VectorSizeCtx
  56. {
  57. VectorSizeCtx(std::size_t size)
  58. : size_(size)
  59. {}
  60. // Unless this is a vector terminal, use the
  61. // null evaluation context
  62. template<typename Expr, typename EnableIf = void>
  63. struct eval
  64. : proto::null_eval<Expr, VectorSizeCtx const>
  65. {};
  66. // Index array terminals with our subscript. Everything
  67. // else will be handled by the default evaluation context.
  68. template<typename Expr>
  69. struct eval<
  70. Expr
  71. , typename boost::enable_if<
  72. proto::matches<Expr, proto::terminal<std::vector<_, _> > >
  73. >::type
  74. >
  75. {
  76. typedef void result_type;
  77. result_type operator ()(Expr &expr, VectorSizeCtx const &ctx) const
  78. {
  79. if(ctx.size_ != proto::value(expr).size())
  80. {
  81. throw std::runtime_error("LHS and RHS are not compatible");
  82. }
  83. }
  84. };
  85. std::size_t size_;
  86. };
  87. // A grammar which matches all the assignment operators,
  88. // so we can easily disable them.
  89. struct AssignOps
  90. : proto::switch_<struct AssignOpsCases>
  91. {};
  92. // Here are the cases used by the switch_ above.
  93. struct AssignOpsCases
  94. {
  95. template<typename Tag, int D = 0> struct case_ : proto::not_<_> {};
  96. template<int D> struct case_< proto::tag::plus_assign, D > : _ {};
  97. template<int D> struct case_< proto::tag::minus_assign, D > : _ {};
  98. template<int D> struct case_< proto::tag::multiplies_assign, D > : _ {};
  99. template<int D> struct case_< proto::tag::divides_assign, D > : _ {};
  100. template<int D> struct case_< proto::tag::modulus_assign, D > : _ {};
  101. template<int D> struct case_< proto::tag::shift_left_assign, D > : _ {};
  102. template<int D> struct case_< proto::tag::shift_right_assign, D > : _ {};
  103. template<int D> struct case_< proto::tag::bitwise_and_assign, D > : _ {};
  104. template<int D> struct case_< proto::tag::bitwise_or_assign, D > : _ {};
  105. template<int D> struct case_< proto::tag::bitwise_xor_assign, D > : _ {};
  106. };
  107. // A vector grammar is a terminal or some op that is not an
  108. // assignment op. (Assignment will be handled specially.)
  109. struct VectorGrammar
  110. : proto::or_<
  111. proto::terminal<_>
  112. , proto::and_<proto::nary_expr<_, proto::vararg<VectorGrammar> >, proto::not_<AssignOps> >
  113. >
  114. {};
  115. // Expressions in the vector domain will be wrapped in VectorExpr<>
  116. // and must conform to the VectorGrammar
  117. struct VectorDomain
  118. : proto::domain<proto::generator<VectorExpr>, VectorGrammar>
  119. {};
  120. // Here is VectorExpr, which extends a proto expr type by
  121. // giving it an operator [] which uses the VectorSubscriptCtx
  122. // to evaluate an expression with a given index.
  123. template<typename Expr>
  124. struct VectorExpr
  125. : proto::extends<Expr, VectorExpr<Expr>, VectorDomain>
  126. {
  127. explicit VectorExpr(Expr const &expr)
  128. : proto::extends<Expr, VectorExpr<Expr>, VectorDomain>(expr)
  129. {}
  130. // Use the VectorSubscriptCtx to implement subscripting
  131. // of a Vector expression tree.
  132. typename proto::result_of::eval<Expr const, VectorSubscriptCtx const>::type
  133. operator []( std::size_t i ) const
  134. {
  135. VectorSubscriptCtx const ctx(i);
  136. return proto::eval(*this, ctx);
  137. }
  138. };
  139. // Define a trait type for detecting vector terminals, to
  140. // be used by the BOOST_PROTO_DEFINE_OPERATORS macro below.
  141. template<typename T>
  142. struct IsVector
  143. : mpl::false_
  144. {};
  145. template<typename T, typename A>
  146. struct IsVector<std::vector<T, A> >
  147. : mpl::true_
  148. {};
  149. namespace VectorOps
  150. {
  151. // This defines all the overloads to make expressions involving
  152. // std::vector to build expression templates.
  153. BOOST_PROTO_DEFINE_OPERATORS(IsVector, VectorDomain)
  154. typedef VectorSubscriptCtx const CVectorSubscriptCtx;
  155. // Assign to a vector from some expression.
  156. template<typename T, typename A, typename Expr>
  157. std::vector<T, A> &assign(std::vector<T, A> &arr, Expr const &expr)
  158. {
  159. VectorSizeCtx const size(arr.size());
  160. proto::eval(proto::as_expr<VectorDomain>(expr), size); // will throw if the sizes don't match
  161. for(std::size_t i = 0; i < arr.size(); ++i)
  162. {
  163. arr[i] = proto::as_expr<VectorDomain>(expr)[i];
  164. }
  165. return arr;
  166. }
  167. // Add-assign to a vector from some expression.
  168. template<typename T, typename A, typename Expr>
  169. std::vector<T, A> &operator +=(std::vector<T, A> &arr, Expr const &expr)
  170. {
  171. VectorSizeCtx const size(arr.size());
  172. proto::eval(proto::as_expr<VectorDomain>(expr), size); // will throw if the sizes don't match
  173. for(std::size_t i = 0; i < arr.size(); ++i)
  174. {
  175. arr[i] += proto::as_expr<VectorDomain>(expr)[i];
  176. }
  177. return arr;
  178. }
  179. }
  180. int main()
  181. {
  182. using namespace VectorOps;
  183. int i;
  184. const int n = 10;
  185. std::vector<int> a,b,c,d;
  186. std::vector<double> e(n);
  187. for (i = 0; i < n; ++i)
  188. {
  189. a.push_back(i);
  190. b.push_back(2*i);
  191. c.push_back(3*i);
  192. d.push_back(i);
  193. }
  194. VectorOps::assign(b, 2);
  195. VectorOps::assign(d, a + b * c);
  196. a += if_else(d < 30, b, c);
  197. VectorOps::assign(e, c);
  198. e += e - 4 / (c + 1);
  199. for (i = 0; i < n; ++i)
  200. {
  201. std::cout
  202. << " a(" << i << ") = " << a[i]
  203. << " b(" << i << ") = " << b[i]
  204. << " c(" << i << ") = " << c[i]
  205. << " d(" << i << ") = " << d[i]
  206. << " e(" << i << ") = " << e[i]
  207. << std::endl;
  208. }
  209. }
  210. //]