vector.cpp 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  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. //[ vector
  7. #include <boost/yap/yap.hpp>
  8. #include <vector>
  9. #include <iostream>
  10. //[ vector_take_nth_xform
  11. struct take_nth
  12. {
  13. template <typename T>
  14. auto operator() (boost::yap::expr_tag<boost::yap::expr_kind::terminal>,
  15. std::vector<T> const & vec)
  16. { return boost::yap::make_terminal(vec[n]); }
  17. std::size_t n;
  18. };
  19. //]
  20. // A stateful transform that records whether all the std::vector<> terminals
  21. // it has seen are equal to the given size.
  22. struct equal_sizes_impl
  23. {
  24. template <typename T>
  25. auto operator() (boost::yap::expr_tag<boost::yap::expr_kind::terminal>,
  26. std::vector<T> const & vec)
  27. {
  28. auto const expr_size = vec.size();
  29. if (expr_size != size)
  30. value = false;
  31. return 0;
  32. }
  33. std::size_t const size;
  34. bool value;
  35. };
  36. template <typename Expr>
  37. bool equal_sizes (std::size_t size, Expr const & expr)
  38. {
  39. equal_sizes_impl impl{size, true};
  40. boost::yap::transform(boost::yap::as_expr(expr), impl);
  41. return impl.value;
  42. }
  43. // Assigns some expression e to the given vector by evaluating e elementwise,
  44. // to avoid temporaries and allocations.
  45. template <typename T, typename Expr>
  46. std::vector<T> & assign (std::vector<T> & vec, Expr const & e)
  47. {
  48. decltype(auto) expr = boost::yap::as_expr(e);
  49. assert(equal_sizes(vec.size(), expr));
  50. for (std::size_t i = 0, size = vec.size(); i < size; ++i) {
  51. vec[i] = boost::yap::evaluate(
  52. boost::yap::transform(boost::yap::as_expr(expr), take_nth{i}));
  53. }
  54. return vec;
  55. }
  56. // As assign() above, just using +=.
  57. template <typename T, typename Expr>
  58. std::vector<T> & operator+= (std::vector<T> & vec, Expr const & e)
  59. {
  60. decltype(auto) expr = boost::yap::as_expr(e);
  61. assert(equal_sizes(vec.size(), expr));
  62. for (std::size_t i = 0, size = vec.size(); i < size; ++i) {
  63. vec[i] += boost::yap::evaluate(
  64. boost::yap::transform(boost::yap::as_expr(expr), take_nth{i}));
  65. }
  66. return vec;
  67. }
  68. // Define a type trait that identifies std::vectors.
  69. template <typename T>
  70. struct is_vector : std::false_type {};
  71. template <typename T, typename A>
  72. struct is_vector<std::vector<T, A>> : std::true_type {};
  73. // Define all the expression-returning numeric operators we need. Each will
  74. // accept any std::vector<> as any of its arguments, and then any value in the
  75. // remaining argument, if any -- some of the operators below are unary.
  76. BOOST_YAP_USER_UDT_UNARY_OPERATOR(negate, boost::yap::expression, is_vector); // -
  77. BOOST_YAP_USER_UDT_ANY_BINARY_OPERATOR(multiplies, boost::yap::expression, is_vector); // *
  78. BOOST_YAP_USER_UDT_ANY_BINARY_OPERATOR(divides, boost::yap::expression, is_vector); // /
  79. BOOST_YAP_USER_UDT_ANY_BINARY_OPERATOR(modulus, boost::yap::expression, is_vector); // %
  80. BOOST_YAP_USER_UDT_ANY_BINARY_OPERATOR(plus, boost::yap::expression, is_vector); // +
  81. BOOST_YAP_USER_UDT_ANY_BINARY_OPERATOR(minus, boost::yap::expression, is_vector); // -
  82. BOOST_YAP_USER_UDT_ANY_BINARY_OPERATOR(less, boost::yap::expression, is_vector); // <
  83. BOOST_YAP_USER_UDT_ANY_BINARY_OPERATOR(greater, boost::yap::expression, is_vector); // >
  84. BOOST_YAP_USER_UDT_ANY_BINARY_OPERATOR(less_equal, boost::yap::expression, is_vector); // <=
  85. BOOST_YAP_USER_UDT_ANY_BINARY_OPERATOR(greater_equal, boost::yap::expression, is_vector); // >=
  86. BOOST_YAP_USER_UDT_ANY_BINARY_OPERATOR(equal_to, boost::yap::expression, is_vector); // ==
  87. BOOST_YAP_USER_UDT_ANY_BINARY_OPERATOR(not_equal_to, boost::yap::expression, is_vector); // !=
  88. BOOST_YAP_USER_UDT_ANY_BINARY_OPERATOR(logical_or, boost::yap::expression, is_vector); // ||
  89. BOOST_YAP_USER_UDT_ANY_BINARY_OPERATOR(logical_and, boost::yap::expression, is_vector); // &&
  90. BOOST_YAP_USER_UDT_ANY_BINARY_OPERATOR(bitwise_and, boost::yap::expression, is_vector); // &
  91. BOOST_YAP_USER_UDT_ANY_BINARY_OPERATOR(bitwise_or, boost::yap::expression, is_vector); // |
  92. BOOST_YAP_USER_UDT_ANY_BINARY_OPERATOR(bitwise_xor, boost::yap::expression, is_vector); // ^
  93. int main()
  94. {
  95. int i;
  96. int const n = 10;
  97. std::vector<int> a,b,c,d;
  98. std::vector<double> e(n);
  99. for (i = 0; i < n; ++i)
  100. {
  101. a.push_back(i);
  102. b.push_back(2*i);
  103. c.push_back(3*i);
  104. d.push_back(i);
  105. }
  106. // After this point, no allocations occur.
  107. assign(b, 2);
  108. assign(d, a + b * c);
  109. a += if_else(d < 30, b, c);
  110. assign(e, c);
  111. e += e - 4 / (c + 1);
  112. for (i = 0; i < n; ++i)
  113. {
  114. std::cout
  115. << " a(" << i << ") = " << a[i]
  116. << " b(" << i << ") = " << b[i]
  117. << " c(" << i << ") = " << c[i]
  118. << " d(" << i << ") = " << d[i]
  119. << " e(" << i << ") = " << e[i]
  120. << std::endl;
  121. }
  122. return 0;
  123. }
  124. //]