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 #include <boost/yap/yap.hpp>
7
8 #include <vector>
9 #include <iostream>
10
11 #include <boost/test/minimal.hpp>
12
13
14 int allocations = 0;
15
operator new(std::size_t size)16 void * operator new(std::size_t size)
17 {
18 ++allocations;
19 void * retval = malloc(size);
20 if (!retval)
21 throw std::bad_alloc();
22 return retval;
23 }
24
operator delete(void * ptr)25 void operator delete(void * ptr) noexcept { free(ptr); }
26
27
28 struct take_nth
29 {
30 template<typename T>
operator ()take_nth31 auto operator()(
32 boost::yap::expr_tag<boost::yap::expr_kind::terminal>,
33 std::vector<T> const & vec)
34 {
35 return boost::yap::make_terminal(vec[n]);
36 }
37
38 std::size_t n;
39 };
40
41 struct equal_sizes_impl
42 {
43 template<typename T>
operator ()equal_sizes_impl44 auto operator()(
45 boost::yap::expr_tag<boost::yap::expr_kind::terminal>,
46 std::vector<T> const & vec)
47 {
48 auto const expr_size = vec.size();
49 if (expr_size != size)
50 value = false;
51 return 0;
52 }
53
54 std::size_t const size;
55 bool value;
56 };
57
58 template<typename Expr>
equal_sizes(std::size_t size,Expr const & expr)59 bool equal_sizes(std::size_t size, Expr const & expr)
60 {
61 equal_sizes_impl impl{size, true};
62 boost::yap::transform(boost::yap::as_expr(expr), impl);
63 return impl.value;
64 }
65
66
67 template<typename T, typename Expr>
assign(std::vector<T> & vec,Expr const & e)68 std::vector<T> & assign(std::vector<T> & vec, Expr const & e)
69 {
70 decltype(auto) expr = boost::yap::as_expr(e);
71 assert(equal_sizes(vec.size(), expr));
72 for (std::size_t i = 0, size = vec.size(); i < size; ++i) {
73 vec[i] = boost::yap::evaluate(
74 boost::yap::transform(boost::yap::as_expr(expr), take_nth{i}));
75 }
76 return vec;
77 }
78
79 template<typename T, typename Expr>
operator +=(std::vector<T> & vec,Expr const & e)80 std::vector<T> & operator+=(std::vector<T> & vec, Expr const & e)
81 {
82 decltype(auto) expr = boost::yap::as_expr(e);
83 assert(equal_sizes(vec.size(), expr));
84 for (std::size_t i = 0, size = vec.size(); i < size; ++i) {
85 vec[i] += boost::yap::evaluate(
86 boost::yap::transform(boost::yap::as_expr(expr), take_nth{i}));
87 }
88 return vec;
89 }
90
91 template<typename T>
92 struct is_vector : std::false_type
93 {
94 };
95
96 template<typename T, typename A>
97 struct is_vector<std::vector<T, A>> : std::true_type
98 {
99 };
100
101 BOOST_YAP_USER_UDT_UNARY_OPERATOR(
102 negate, boost::yap::expression, is_vector); // -
103 BOOST_YAP_USER_UDT_ANY_BINARY_OPERATOR(
104 multiplies, boost::yap::expression, is_vector); // *
105 BOOST_YAP_USER_UDT_ANY_BINARY_OPERATOR(
106 divides, boost::yap::expression, is_vector); // /
107 BOOST_YAP_USER_UDT_ANY_BINARY_OPERATOR(
108 modulus, boost::yap::expression, is_vector); // %
109 BOOST_YAP_USER_UDT_ANY_BINARY_OPERATOR(
110 plus, boost::yap::expression, is_vector); // +
111 BOOST_YAP_USER_UDT_ANY_BINARY_OPERATOR(
112 minus, boost::yap::expression, is_vector); // -
113 BOOST_YAP_USER_UDT_ANY_BINARY_OPERATOR(
114 less, boost::yap::expression, is_vector); // <
115 BOOST_YAP_USER_UDT_ANY_BINARY_OPERATOR(
116 greater, boost::yap::expression, is_vector); // >
117 BOOST_YAP_USER_UDT_ANY_BINARY_OPERATOR(
118 less_equal, boost::yap::expression, is_vector); // <=
119 BOOST_YAP_USER_UDT_ANY_BINARY_OPERATOR(
120 greater_equal, boost::yap::expression, is_vector); // >=
121 BOOST_YAP_USER_UDT_ANY_BINARY_OPERATOR(
122 equal_to, boost::yap::expression, is_vector); // ==
123 BOOST_YAP_USER_UDT_ANY_BINARY_OPERATOR(
124 not_equal_to, boost::yap::expression, is_vector); // !=
125 BOOST_YAP_USER_UDT_ANY_BINARY_OPERATOR(
126 logical_or, boost::yap::expression, is_vector); // ||
127 BOOST_YAP_USER_UDT_ANY_BINARY_OPERATOR(
128 logical_and, boost::yap::expression, is_vector); // &&
129 BOOST_YAP_USER_UDT_ANY_BINARY_OPERATOR(
130 bitwise_and, boost::yap::expression, is_vector); // &
131 BOOST_YAP_USER_UDT_ANY_BINARY_OPERATOR(
132 bitwise_or, boost::yap::expression, is_vector); // |
133 BOOST_YAP_USER_UDT_ANY_BINARY_OPERATOR(
134 bitwise_xor, boost::yap::expression, is_vector); // ^
135
test_main(int,char * [])136 int test_main(int, char * [])
137 {
138 int i;
139 int const n = 10;
140 std::vector<int> a(n), b(n), c(n), d(n);
141 std::vector<double> e(n);
142
143 // Reset allocation count. There should be none from this point on.
144 allocations = 0;
145
146 for (i = 0; i < n; ++i) {
147 a[i] = i;
148 b[i] = 2 * i;
149 c[i] = 3 * i;
150 d[i] = i;
151 }
152
153 assign(b, 2);
154 assign(d, a + b * c);
155
156 if_else(d < 30, b, c);
157 a += if_else(d < 30, b, c);
158
159 assign(e, c);
160 e += e - 4 / (c + 1);
161
162 for (i = 0; i < n; ++i) {
163 std::cout << " a(" << i << ") = " << a[i] << " b(" << i
164 << ") = " << b[i] << " c(" << i << ") = " << c[i] << " d("
165 << i << ") = " << d[i] << " e(" << i << ") = " << e[i]
166 << std::endl;
167 }
168
169 BOOST_CHECK(allocations == 0);
170
171 return 0;
172 }
173