mixed.cpp 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. // Copyright (C) 2016-2018 T. Zachary Laine
  2. //
  3. // Distributed under the Boost Software License, Version 1.0. (See
  4. // accompanying file LICENSE_1_0.txt or copy at
  5. // http://www.boost.org/LICENSE_1_0.txt)
  6. //[ mixed
  7. #include <boost/yap/yap.hpp>
  8. #include <complex>
  9. #include <list>
  10. #include <vector>
  11. #include <iostream>
  12. // This wrapper makes the pattern matching in transforms below (like deref and
  13. // incr) a lot easier to write.
  14. template <typename Iter>
  15. struct iter_wrapper
  16. {
  17. Iter it;
  18. };
  19. template <typename Iter>
  20. auto make_iter_wrapper (Iter it)
  21. { return iter_wrapper<Iter>{it}; }
  22. // A container -> wrapped-begin transform.
  23. struct begin
  24. {
  25. template <typename Cont>
  26. auto operator() (boost::yap::expr_tag<boost::yap::expr_kind::terminal>,
  27. Cont const & cont)
  28. -> decltype(boost::yap::make_terminal(make_iter_wrapper(cont.begin())))
  29. { return boost::yap::make_terminal(make_iter_wrapper(cont.begin())); }
  30. };
  31. // A wrapped-iterator -> dereferenced value transform.
  32. struct deref
  33. {
  34. template <typename Iter>
  35. auto operator() (boost::yap::expr_tag<boost::yap::expr_kind::terminal>,
  36. iter_wrapper<Iter> wrapper)
  37. -> decltype(boost::yap::make_terminal(*wrapper.it))
  38. { return boost::yap::make_terminal(*wrapper.it); }
  39. };
  40. // A wrapped-iterator increment transform, using side effects.
  41. struct incr
  42. {
  43. template <typename Iter>
  44. auto operator() (boost::yap::expr_tag<boost::yap::expr_kind::terminal>,
  45. iter_wrapper<Iter> & wrapper)
  46. -> decltype(boost::yap::make_terminal(wrapper.it))
  47. {
  48. ++wrapper.it;
  49. // Since this transform is valuable for its side effects, and thus the
  50. // result of the transform is ignored, we could return anything here.
  51. return boost::yap::make_terminal(wrapper.it);
  52. }
  53. };
  54. // The implementation of elementwise evaluation of expressions of sequences;
  55. // all the later operations use this one.
  56. template <
  57. template <class, class> class Cont,
  58. typename T,
  59. typename A,
  60. typename Expr,
  61. typename Op
  62. >
  63. Cont<T, A> & op_assign (Cont<T, A> & cont, Expr const & e, Op && op)
  64. {
  65. decltype(auto) expr = boost::yap::as_expr(e);
  66. // Transform the expression of sequences into an expression of
  67. // begin-iterators.
  68. auto expr2 = boost::yap::transform(boost::yap::as_expr(expr), begin{});
  69. for (auto && x : cont) {
  70. // Transform the expression of iterators into an expression of
  71. // pointed-to-values, evaluate the resulting expression, and call op()
  72. // with the result of the evaluation.
  73. op(x, boost::yap::evaluate(boost::yap::transform(expr2, deref{})));
  74. // Transform the expression of iterators into an ignored value; as a
  75. // side effect, increment the iterators in the expression.
  76. boost::yap::transform(expr2, incr{});
  77. }
  78. return cont;
  79. }
  80. template <
  81. template <class, class> class Cont,
  82. typename T,
  83. typename A,
  84. typename Expr
  85. >
  86. Cont<T, A> & assign (Cont<T, A> & cont, Expr const & expr)
  87. {
  88. return op_assign(cont, expr, [](auto & cont_value, auto && expr_value) {
  89. cont_value = std::forward<decltype(expr_value)>(expr_value);
  90. });
  91. }
  92. template <
  93. template <class, class> class Cont,
  94. typename T,
  95. typename A,
  96. typename Expr
  97. >
  98. Cont<T, A> & operator+= (Cont<T, A> & cont, Expr const & expr)
  99. {
  100. return op_assign(cont, expr, [](auto & cont_value, auto && expr_value) {
  101. cont_value += std::forward<decltype(expr_value)>(expr_value);
  102. });
  103. }
  104. template <
  105. template <class, class> class Cont,
  106. typename T,
  107. typename A,
  108. typename Expr
  109. >
  110. Cont<T, A> & operator-= (Cont<T, A> & cont, Expr const & expr)
  111. {
  112. return op_assign(cont, expr, [](auto & cont_value, auto && expr_value) {
  113. cont_value -= std::forward<decltype(expr_value)>(expr_value);
  114. });
  115. }
  116. // A type trait that identifies std::vectors and std::lists.
  117. template <typename T>
  118. struct is_mixed : std::false_type {};
  119. template <typename T, typename A>
  120. struct is_mixed<std::vector<T, A>> : std::true_type {};
  121. template <typename T, typename A>
  122. struct is_mixed<std::list<T, A>> : std::true_type {};
  123. // Define expression-producing operators over std::vectors and std::lists.
  124. BOOST_YAP_USER_UDT_UNARY_OPERATOR(negate, boost::yap::expression, is_mixed); // -
  125. BOOST_YAP_USER_UDT_ANY_BINARY_OPERATOR(multiplies, boost::yap::expression, is_mixed); // *
  126. BOOST_YAP_USER_UDT_ANY_BINARY_OPERATOR(divides, boost::yap::expression, is_mixed); // /
  127. BOOST_YAP_USER_UDT_ANY_BINARY_OPERATOR(modulus, boost::yap::expression, is_mixed); // %
  128. BOOST_YAP_USER_UDT_ANY_BINARY_OPERATOR(plus, boost::yap::expression, is_mixed); // +
  129. BOOST_YAP_USER_UDT_ANY_BINARY_OPERATOR(minus, boost::yap::expression, is_mixed); // -
  130. BOOST_YAP_USER_UDT_ANY_BINARY_OPERATOR(less, boost::yap::expression, is_mixed); // <
  131. BOOST_YAP_USER_UDT_ANY_BINARY_OPERATOR(greater, boost::yap::expression, is_mixed); // >
  132. BOOST_YAP_USER_UDT_ANY_BINARY_OPERATOR(less_equal, boost::yap::expression, is_mixed); // <=
  133. BOOST_YAP_USER_UDT_ANY_BINARY_OPERATOR(greater_equal, boost::yap::expression, is_mixed); // >=
  134. BOOST_YAP_USER_UDT_ANY_BINARY_OPERATOR(equal_to, boost::yap::expression, is_mixed); // ==
  135. BOOST_YAP_USER_UDT_ANY_BINARY_OPERATOR(not_equal_to, boost::yap::expression, is_mixed); // !=
  136. BOOST_YAP_USER_UDT_ANY_BINARY_OPERATOR(logical_or, boost::yap::expression, is_mixed); // ||
  137. BOOST_YAP_USER_UDT_ANY_BINARY_OPERATOR(logical_and, boost::yap::expression, is_mixed); // &&
  138. BOOST_YAP_USER_UDT_ANY_BINARY_OPERATOR(bitwise_and, boost::yap::expression, is_mixed); // &
  139. BOOST_YAP_USER_UDT_ANY_BINARY_OPERATOR(bitwise_or, boost::yap::expression, is_mixed); // |
  140. BOOST_YAP_USER_UDT_ANY_BINARY_OPERATOR(bitwise_xor, boost::yap::expression, is_mixed); // ^
  141. // Define a type that can resolve to any overload of std::sin().
  142. struct sin_t
  143. {
  144. template<typename T>
  145. T operator()(T x)
  146. {
  147. return std::sin(x);
  148. }
  149. };
  150. int main()
  151. {
  152. int n = 10;
  153. std::vector<int> a,b,c,d;
  154. std::list<double> e;
  155. std::list<std::complex<double>> f;
  156. int i;
  157. for(i = 0;i < n; ++i)
  158. {
  159. a.push_back(i);
  160. b.push_back(2*i);
  161. c.push_back(3*i);
  162. d.push_back(i);
  163. e.push_back(0.0);
  164. f.push_back(std::complex<double>(1.0, 1.0));
  165. }
  166. assign(b, 2);
  167. assign(d, a + b * c);
  168. a += if_else(d < 30, b, c);
  169. assign(e, c);
  170. e += e - 4 / (c + 1);
  171. auto sin = boost::yap::make_terminal(sin_t{});
  172. f -= sin(0.1 * e * std::complex<double>(0.2, 1.2));
  173. std::list<double>::const_iterator ei = e.begin();
  174. std::list<std::complex<double>>::const_iterator fi = f.begin();
  175. for (i = 0; i < n; ++i)
  176. {
  177. std::cout
  178. << "a(" << i << ") = " << a[i]
  179. << " b(" << i << ") = " << b[i]
  180. << " c(" << i << ") = " << c[i]
  181. << " d(" << i << ") = " << d[i]
  182. << " e(" << i << ") = " << *ei++
  183. << " f(" << i << ") = " << *fi++
  184. << std::endl;
  185. }
  186. return 0;
  187. }
  188. //]