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.
17template <typename Iter>
18struct iter_wrapper
19{
20 Iter it;
21};
22
23template <typename Iter>
24auto make_iter_wrapper (Iter it)
25{ return iter_wrapper<Iter>{it}; }
26
27
28// A container -> wrapped-begin transform.
29struct begin
30{
31 template <typename Cont>
32 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.
39struct deref
40{
41 template <typename Iter>
42 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.
49struct incr
50{
51 template <typename Iter>
52 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.
66template <
67 template <class, class> class Cont,
68 typename T,
69 typename A,
70 typename Expr,
71 typename Op
72>
73Cont<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
91template <
92 template <class, class> class Cont,
93 typename T,
94 typename A,
95 typename Expr
96>
97Cont<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
104template <
105 template <class, class> class Cont,
106 typename T,
107 typename A,
108 typename Expr
109>
110Cont<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
117template <
118 template <class, class> class Cont,
119 typename T,
120 typename A,
121 typename Expr
122>
123Cont<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.
131template <typename T>
132struct is_mixed : std::false_type {};
133
134template <typename T, typename A>
135struct is_mixed<std::vector<T, A>> : std::true_type {};
136
137template <typename T, typename A>
138struct is_mixed<std::list<T, A>> : std::true_type {};
139
140// Define expression-producing operators over std::vectors and std::lists.
141BOOST_YAP_USER_UDT_UNARY_OPERATOR(negate, boost::yap::expression, is_mixed); // -
142BOOST_YAP_USER_UDT_ANY_BINARY_OPERATOR(multiplies, boost::yap::expression, is_mixed); // *
143BOOST_YAP_USER_UDT_ANY_BINARY_OPERATOR(divides, boost::yap::expression, is_mixed); // /
144BOOST_YAP_USER_UDT_ANY_BINARY_OPERATOR(modulus, boost::yap::expression, is_mixed); // %
145BOOST_YAP_USER_UDT_ANY_BINARY_OPERATOR(plus, boost::yap::expression, is_mixed); // +
146BOOST_YAP_USER_UDT_ANY_BINARY_OPERATOR(minus, boost::yap::expression, is_mixed); // -
147BOOST_YAP_USER_UDT_ANY_BINARY_OPERATOR(less, boost::yap::expression, is_mixed); // <
148BOOST_YAP_USER_UDT_ANY_BINARY_OPERATOR(greater, boost::yap::expression, is_mixed); // >
149BOOST_YAP_USER_UDT_ANY_BINARY_OPERATOR(less_equal, boost::yap::expression, is_mixed); // <=
150BOOST_YAP_USER_UDT_ANY_BINARY_OPERATOR(greater_equal, boost::yap::expression, is_mixed); // >=
151BOOST_YAP_USER_UDT_ANY_BINARY_OPERATOR(equal_to, boost::yap::expression, is_mixed); // ==
152BOOST_YAP_USER_UDT_ANY_BINARY_OPERATOR(not_equal_to, boost::yap::expression, is_mixed); // !=
153BOOST_YAP_USER_UDT_ANY_BINARY_OPERATOR(logical_or, boost::yap::expression, is_mixed); // ||
154BOOST_YAP_USER_UDT_ANY_BINARY_OPERATOR(logical_and, boost::yap::expression, is_mixed); // &&
155BOOST_YAP_USER_UDT_ANY_BINARY_OPERATOR(bitwise_and, boost::yap::expression, is_mixed); // &
156BOOST_YAP_USER_UDT_ANY_BINARY_OPERATOR(bitwise_or, boost::yap::expression, is_mixed); // |
157BOOST_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().
160struct sin_t
161{
162 template<typename T>
163 T operator()(T x)
164 {
165 return std::sin(x);
166 }
167};
168
169int 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(x: i);
180 b.push_back(x: 2*i);
181 c.push_back(x: 3*i);
182 d.push_back(x: i);
183 e.push_back(x: 0.0);
184 f.push_back(x: std::complex<double>(1.0, 1.0));
185 }
186
187 assign(cont&: b, expr: 2);
188 assign(cont&: d, expr: a + b * c);
189 a += if_else(expr1: d < 30, expr2&: b, expr3&: c);
190
191 assign(cont&: e, expr: c);
192 e += e - 4 / (c + 1);
193
194 auto sin = boost::yap::make_terminal(t: 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

source code of boost/libs/yap/example/mixed.cpp