//[ Vector /////////////////////////////////////////////////////////////////////////////// // Copyright 2008 Eric Niebler. 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) // // This is an example of using BOOST_PROTO_DEFINE_OPERATORS to Protofy // expressions using std::vector<>, a non-proto type. It is a port of the // Vector example from PETE (http://www.codesourcery.com/pooma/download.html). #include #include #include #include #include #include #include #include namespace mpl = boost::mpl; namespace proto = boost::proto; using proto::_; template struct VectorExpr; // Here is an evaluation context that indexes into a std::vector // expression and combines the result. struct VectorSubscriptCtx { VectorSubscriptCtx(std::size_t i) : i_(i) {} // Unless this is a vector terminal, use the // default evaluation context template struct eval : proto::default_eval {}; // Index vector terminals with our subscript. template struct eval< Expr , typename boost::enable_if< proto::matches > > >::type > { typedef typename proto::result_of::value::type::value_type result_type; result_type operator ()(Expr &expr, VectorSubscriptCtx const &ctx) const { return proto::value(expr)[ctx.i_]; } }; std::size_t i_; }; // Here is an evaluation context that verifies that all the // vectors in an expression have the same size. struct VectorSizeCtx { VectorSizeCtx(std::size_t size) : size_(size) {} // Unless this is a vector terminal, use the // null evaluation context template struct eval : proto::null_eval {}; // Index array terminals with our subscript. Everything // else will be handled by the default evaluation context. template struct eval< Expr , typename boost::enable_if< proto::matches > > >::type > { typedef void result_type; result_type operator ()(Expr &expr, VectorSizeCtx const &ctx) const { if(ctx.size_ != proto::value(expr).size()) { throw std::runtime_error("LHS and RHS are not compatible"); } } }; std::size_t size_; }; // A grammar which matches all the assignment operators, // so we can easily disable them. struct AssignOps : proto::switch_ {}; // Here are the cases used by the switch_ above. struct AssignOpsCases { template struct case_ : proto::not_<_> {}; template struct case_< proto::tag::plus_assign, D > : _ {}; template struct case_< proto::tag::minus_assign, D > : _ {}; template struct case_< proto::tag::multiplies_assign, D > : _ {}; template struct case_< proto::tag::divides_assign, D > : _ {}; template struct case_< proto::tag::modulus_assign, D > : _ {}; template struct case_< proto::tag::shift_left_assign, D > : _ {}; template struct case_< proto::tag::shift_right_assign, D > : _ {}; template struct case_< proto::tag::bitwise_and_assign, D > : _ {}; template struct case_< proto::tag::bitwise_or_assign, D > : _ {}; template struct case_< proto::tag::bitwise_xor_assign, D > : _ {}; }; // A vector grammar is a terminal or some op that is not an // assignment op. (Assignment will be handled specially.) struct VectorGrammar : proto::or_< proto::terminal<_> , proto::and_ >, proto::not_ > > {}; // Expressions in the vector domain will be wrapped in VectorExpr<> // and must conform to the VectorGrammar struct VectorDomain : proto::domain, VectorGrammar> {}; // Here is VectorExpr, which extends a proto expr type by // giving it an operator [] which uses the VectorSubscriptCtx // to evaluate an expression with a given index. template struct VectorExpr : proto::extends, VectorDomain> { explicit VectorExpr(Expr const &expr) : proto::extends, VectorDomain>(expr) {} // Use the VectorSubscriptCtx to implement subscripting // of a Vector expression tree. typename proto::result_of::eval::type operator []( std::size_t i ) const { VectorSubscriptCtx const ctx(i); return proto::eval(*this, ctx); } }; // Define a trait type for detecting vector terminals, to // be used by the BOOST_PROTO_DEFINE_OPERATORS macro below. template struct IsVector : mpl::false_ {}; template struct IsVector > : mpl::true_ {}; namespace VectorOps { // This defines all the overloads to make expressions involving // std::vector to build expression templates. BOOST_PROTO_DEFINE_OPERATORS(IsVector, VectorDomain) typedef VectorSubscriptCtx const CVectorSubscriptCtx; // Assign to a vector from some expression. template std::vector &assign(std::vector &arr, Expr const &expr) { VectorSizeCtx const size(arr.size()); proto::eval(proto::as_expr(expr), size); // will throw if the sizes don't match for(std::size_t i = 0; i < arr.size(); ++i) { arr[i] = proto::as_expr(expr)[i]; } return arr; } // Add-assign to a vector from some expression. template std::vector &operator +=(std::vector &arr, Expr const &expr) { VectorSizeCtx const size(arr.size()); proto::eval(proto::as_expr(expr), size); // will throw if the sizes don't match for(std::size_t i = 0; i < arr.size(); ++i) { arr[i] += proto::as_expr(expr)[i]; } return arr; } } int main() { using namespace VectorOps; int i; const int n = 10; std::vector a,b,c,d; std::vector 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); } VectorOps::assign(b, 2); VectorOps::assign(d, a + b * c); a += if_else(d < 30, b, c); VectorOps::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; } } //]