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