// 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) //[ mixed #include #include #include #include #include // This wrapper makes the pattern matching in transforms below (like deref and // incr) a lot easier to write. template struct iter_wrapper { Iter it; }; template auto make_iter_wrapper (Iter it) { return iter_wrapper{it}; } // A container -> wrapped-begin transform. struct begin { template auto operator() (boost::yap::expr_tag, Cont const & cont) -> decltype(boost::yap::make_terminal(make_iter_wrapper(cont.begin()))) { return boost::yap::make_terminal(make_iter_wrapper(cont.begin())); } }; // A wrapped-iterator -> dereferenced value transform. struct deref { template auto operator() (boost::yap::expr_tag, iter_wrapper wrapper) -> decltype(boost::yap::make_terminal(*wrapper.it)) { return boost::yap::make_terminal(*wrapper.it); } }; // A wrapped-iterator increment transform, using side effects. struct incr { template auto operator() (boost::yap::expr_tag, iter_wrapper & wrapper) -> decltype(boost::yap::make_terminal(wrapper.it)) { ++wrapper.it; // Since this transform is valuable for its side effects, and thus the // result of the transform is ignored, we could return anything here. return boost::yap::make_terminal(wrapper.it); } }; // The implementation of elementwise evaluation of expressions of sequences; // all the later operations use this one. template < template class Cont, typename T, typename A, typename Expr, typename Op > Cont & op_assign (Cont & cont, Expr const & e, Op && op) { decltype(auto) expr = boost::yap::as_expr(e); // Transform the expression of sequences into an expression of // begin-iterators. auto expr2 = boost::yap::transform(boost::yap::as_expr(expr), begin{}); for (auto && x : cont) { // Transform the expression of iterators into an expression of // pointed-to-values, evaluate the resulting expression, and call op() // with the result of the evaluation. op(x, boost::yap::evaluate(boost::yap::transform(expr2, deref{}))); // Transform the expression of iterators into an ignored value; as a // side effect, increment the iterators in the expression. boost::yap::transform(expr2, incr{}); } return cont; } template < template class Cont, typename T, typename A, typename Expr > Cont & assign (Cont & cont, Expr const & expr) { return op_assign(cont, expr, [](auto & cont_value, auto && expr_value) { cont_value = std::forward(expr_value); }); } template < template class Cont, typename T, typename A, typename Expr > Cont & operator+= (Cont & cont, Expr const & expr) { return op_assign(cont, expr, [](auto & cont_value, auto && expr_value) { cont_value += std::forward(expr_value); }); } template < template class Cont, typename T, typename A, typename Expr > Cont & operator-= (Cont & cont, Expr const & expr) { return op_assign(cont, expr, [](auto & cont_value, auto && expr_value) { cont_value -= std::forward(expr_value); }); } // A type trait that identifies std::vectors and std::lists. template struct is_mixed : std::false_type {}; template struct is_mixed> : std::true_type {}; template struct is_mixed> : std::true_type {}; // Define expression-producing operators over std::vectors and std::lists. BOOST_YAP_USER_UDT_UNARY_OPERATOR(negate, boost::yap::expression, is_mixed); // - BOOST_YAP_USER_UDT_ANY_BINARY_OPERATOR(multiplies, boost::yap::expression, is_mixed); // * BOOST_YAP_USER_UDT_ANY_BINARY_OPERATOR(divides, boost::yap::expression, is_mixed); // / BOOST_YAP_USER_UDT_ANY_BINARY_OPERATOR(modulus, boost::yap::expression, is_mixed); // % BOOST_YAP_USER_UDT_ANY_BINARY_OPERATOR(plus, boost::yap::expression, is_mixed); // + BOOST_YAP_USER_UDT_ANY_BINARY_OPERATOR(minus, boost::yap::expression, is_mixed); // - BOOST_YAP_USER_UDT_ANY_BINARY_OPERATOR(less, boost::yap::expression, is_mixed); // < BOOST_YAP_USER_UDT_ANY_BINARY_OPERATOR(greater, boost::yap::expression, is_mixed); // > BOOST_YAP_USER_UDT_ANY_BINARY_OPERATOR(less_equal, boost::yap::expression, is_mixed); // <= BOOST_YAP_USER_UDT_ANY_BINARY_OPERATOR(greater_equal, boost::yap::expression, is_mixed); // >= BOOST_YAP_USER_UDT_ANY_BINARY_OPERATOR(equal_to, boost::yap::expression, is_mixed); // == BOOST_YAP_USER_UDT_ANY_BINARY_OPERATOR(not_equal_to, boost::yap::expression, is_mixed); // != BOOST_YAP_USER_UDT_ANY_BINARY_OPERATOR(logical_or, boost::yap::expression, is_mixed); // || BOOST_YAP_USER_UDT_ANY_BINARY_OPERATOR(logical_and, boost::yap::expression, is_mixed); // && BOOST_YAP_USER_UDT_ANY_BINARY_OPERATOR(bitwise_and, boost::yap::expression, is_mixed); // & BOOST_YAP_USER_UDT_ANY_BINARY_OPERATOR(bitwise_or, boost::yap::expression, is_mixed); // | BOOST_YAP_USER_UDT_ANY_BINARY_OPERATOR(bitwise_xor, boost::yap::expression, is_mixed); // ^ // Define a type that can resolve to any overload of std::sin(). struct sin_t { template T operator()(T x) { return std::sin(x); } }; int main() { int n = 10; std::vector a,b,c,d; std::list e; std::list> f; int i; for(i = 0;i < n; ++i) { a.push_back(i); b.push_back(2*i); c.push_back(3*i); d.push_back(i); e.push_back(0.0); f.push_back(std::complex(1.0, 1.0)); } assign(b, 2); assign(d, a + b * c); a += if_else(d < 30, b, c); assign(e, c); e += e - 4 / (c + 1); auto sin = boost::yap::make_terminal(sin_t{}); f -= sin(0.1 * e * std::complex(0.2, 1.2)); std::list::const_iterator ei = e.begin(); std::list>::const_iterator fi = f.begin(); 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 << ") = " << *ei++ << " f(" << i << ") = " << *fi++ << std::endl; } return 0; } //]