tarray.cpp 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  1. //[ TArray
  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 example constructs a mini-library for linear algebra, using
  8. // expression templates to eliminate the need for temporaries when
  9. // adding arrays of numbers. It duplicates the TArray example from
  10. // PETE (http://www.codesourcery.com/pooma/download.html)
  11. #include <iostream>
  12. #include <boost/mpl/int.hpp>
  13. #include <boost/proto/core.hpp>
  14. #include <boost/proto/context.hpp>
  15. namespace mpl = boost::mpl;
  16. namespace proto = boost::proto;
  17. using proto::_;
  18. // This grammar describes which TArray expressions
  19. // are allowed; namely, int and array terminals
  20. // plus, minus, multiplies and divides of TArray expressions.
  21. struct TArrayGrammar
  22. : proto::or_<
  23. proto::terminal< int >
  24. , proto::terminal< int[3] >
  25. , proto::plus< TArrayGrammar, TArrayGrammar >
  26. , proto::minus< TArrayGrammar, TArrayGrammar >
  27. , proto::multiplies< TArrayGrammar, TArrayGrammar >
  28. , proto::divides< TArrayGrammar, TArrayGrammar >
  29. >
  30. {};
  31. template<typename Expr>
  32. struct TArrayExpr;
  33. // Tell proto that in the TArrayDomain, all
  34. // expressions should be wrapped in TArrayExpr<> and
  35. // must conform to the TArrayGrammar
  36. struct TArrayDomain
  37. : proto::domain<proto::generator<TArrayExpr>, TArrayGrammar>
  38. {};
  39. // Here is an evaluation context that indexes into a TArray
  40. // expression, and combines the result.
  41. struct TArraySubscriptCtx
  42. : proto::callable_context< TArraySubscriptCtx const >
  43. {
  44. typedef int result_type;
  45. TArraySubscriptCtx(std::ptrdiff_t i)
  46. : i_(i)
  47. {}
  48. // Index array terminals with our subscript. Everything
  49. // else will be handled by the default evaluation context.
  50. int operator ()(proto::tag::terminal, int const (&data)[3]) const
  51. {
  52. return data[this->i_];
  53. }
  54. std::ptrdiff_t i_;
  55. };
  56. // Here is an evaluation context that prints a TArray expression.
  57. struct TArrayPrintCtx
  58. : proto::callable_context< TArrayPrintCtx const >
  59. {
  60. typedef std::ostream &result_type;
  61. TArrayPrintCtx() {}
  62. std::ostream &operator ()(proto::tag::terminal, int i) const
  63. {
  64. return std::cout << i;
  65. }
  66. std::ostream &operator ()(proto::tag::terminal, int const (&arr)[3]) const
  67. {
  68. return std::cout << '{' << arr[0] << ", " << arr[1] << ", " << arr[2] << '}';
  69. }
  70. template<typename L, typename R>
  71. std::ostream &operator ()(proto::tag::plus, L const &l, R const &r) const
  72. {
  73. return std::cout << '(' << l << " + " << r << ')';
  74. }
  75. template<typename L, typename R>
  76. std::ostream &operator ()(proto::tag::minus, L const &l, R const &r) const
  77. {
  78. return std::cout << '(' << l << " - " << r << ')';
  79. }
  80. template<typename L, typename R>
  81. std::ostream &operator ()(proto::tag::multiplies, L const &l, R const &r) const
  82. {
  83. return std::cout << l << " * " << r;
  84. }
  85. template<typename L, typename R>
  86. std::ostream &operator ()(proto::tag::divides, L const &l, R const &r) const
  87. {
  88. return std::cout << l << " / " << r;
  89. }
  90. };
  91. // Here is the domain-specific expression wrapper, which overrides
  92. // operator [] to evaluate the expression using the TArraySubscriptCtx.
  93. template<typename Expr>
  94. struct TArrayExpr
  95. : proto::extends<Expr, TArrayExpr<Expr>, TArrayDomain>
  96. {
  97. typedef proto::extends<Expr, TArrayExpr<Expr>, TArrayDomain> base_type;
  98. TArrayExpr( Expr const & expr = Expr() )
  99. : base_type( expr )
  100. {}
  101. // Use the TArraySubscriptCtx to implement subscripting
  102. // of a TArray expression tree.
  103. int operator []( std::ptrdiff_t i ) const
  104. {
  105. TArraySubscriptCtx const ctx(i);
  106. return proto::eval(*this, ctx);
  107. }
  108. // Use the TArrayPrintCtx to display a TArray expression tree.
  109. friend std::ostream &operator <<(std::ostream &sout, TArrayExpr<Expr> const &expr)
  110. {
  111. TArrayPrintCtx const ctx;
  112. return proto::eval(expr, ctx);
  113. }
  114. };
  115. // Here is our TArray terminal, implemented in terms of TArrayExpr
  116. // It is basically just an array of 3 integers.
  117. struct TArray
  118. : TArrayExpr< proto::terminal< int[3] >::type >
  119. {
  120. explicit TArray( int i = 0, int j = 0, int k = 0 )
  121. {
  122. (*this)[0] = i;
  123. (*this)[1] = j;
  124. (*this)[2] = k;
  125. }
  126. // Here we override operator [] to give read/write access to
  127. // the elements of the array. (We could use the TArrayExpr
  128. // operator [] if we made the subscript context smarter about
  129. // returning non-const reference when appropriate.)
  130. int &operator [](std::ptrdiff_t i)
  131. {
  132. return proto::value(*this)[i];
  133. }
  134. int const &operator [](std::ptrdiff_t i) const
  135. {
  136. return proto::value(*this)[i];
  137. }
  138. // Here we define a operator = for TArray terminals that
  139. // takes a TArray expression.
  140. template< typename Expr >
  141. TArray &operator =(Expr const & expr)
  142. {
  143. // proto::as_expr<TArrayDomain>(expr) is the same as
  144. // expr unless expr is an integer, in which case it
  145. // is made into a TArrayExpr terminal first.
  146. return this->assign(proto::as_expr<TArrayDomain>(expr));
  147. }
  148. template< typename Expr >
  149. TArray &printAssign(Expr const & expr)
  150. {
  151. *this = expr;
  152. std::cout << *this << " = " << expr << std::endl;
  153. return *this;
  154. }
  155. private:
  156. template< typename Expr >
  157. TArray &assign(Expr const & expr)
  158. {
  159. // expr[i] here uses TArraySubscriptCtx under the covers.
  160. (*this)[0] = expr[0];
  161. (*this)[1] = expr[1];
  162. (*this)[2] = expr[2];
  163. return *this;
  164. }
  165. };
  166. int main()
  167. {
  168. TArray a(3,1,2);
  169. TArray b;
  170. std::cout << a << std::endl;
  171. std::cout << b << std::endl;
  172. b[0] = 7; b[1] = 33; b[2] = -99;
  173. TArray c(a);
  174. std::cout << c << std::endl;
  175. a = 0;
  176. std::cout << a << std::endl;
  177. std::cout << b << std::endl;
  178. std::cout << c << std::endl;
  179. a = b + c;
  180. std::cout << a << std::endl;
  181. a.printAssign(b+c*(b + 3*c));
  182. return 0;
  183. }
  184. //]