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