1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241
|
//[ 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 <vector>
#include <iostream>
#include <stdexcept>
#include <boost/mpl/bool.hpp>
#include <boost/proto/core.hpp>
#include <boost/proto/debug.hpp>
#include <boost/proto/context.hpp>
#include <boost/utility/enable_if.hpp>
namespace mpl = boost::mpl;
namespace proto = boost::proto;
using proto::_;
template<typename Expr>
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<typename Expr, typename EnableIf = void>
struct eval
: proto::default_eval<Expr, VectorSubscriptCtx const>
{};
// Index vector terminals with our subscript.
template<typename Expr>
struct eval<
Expr
, typename boost::enable_if<
proto::matches<Expr, proto::terminal<std::vector<_, _> > >
>::type
>
{
typedef typename proto::result_of::value<Expr>::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<typename Expr, typename EnableIf = void>
struct eval
: proto::null_eval<Expr, VectorSizeCtx const>
{};
// Index array terminals with our subscript. Everything
// else will be handled by the default evaluation context.
template<typename Expr>
struct eval<
Expr
, typename boost::enable_if<
proto::matches<Expr, proto::terminal<std::vector<_, _> > >
>::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_<struct AssignOpsCases>
{};
// Here are the cases used by the switch_ above.
struct AssignOpsCases
{
template<typename Tag, int D = 0> struct case_ : proto::not_<_> {};
template<int D> struct case_< proto::tag::plus_assign, D > : _ {};
template<int D> struct case_< proto::tag::minus_assign, D > : _ {};
template<int D> struct case_< proto::tag::multiplies_assign, D > : _ {};
template<int D> struct case_< proto::tag::divides_assign, D > : _ {};
template<int D> struct case_< proto::tag::modulus_assign, D > : _ {};
template<int D> struct case_< proto::tag::shift_left_assign, D > : _ {};
template<int D> struct case_< proto::tag::shift_right_assign, D > : _ {};
template<int D> struct case_< proto::tag::bitwise_and_assign, D > : _ {};
template<int D> struct case_< proto::tag::bitwise_or_assign, D > : _ {};
template<int D> 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::nary_expr<_, proto::vararg<VectorGrammar> >, proto::not_<AssignOps> >
>
{};
// Expressions in the vector domain will be wrapped in VectorExpr<>
// and must conform to the VectorGrammar
struct VectorDomain
: proto::domain<proto::generator<VectorExpr>, 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<typename Expr>
struct VectorExpr
: proto::extends<Expr, VectorExpr<Expr>, VectorDomain>
{
explicit VectorExpr(Expr const &expr)
: proto::extends<Expr, VectorExpr<Expr>, VectorDomain>(expr)
{}
// Use the VectorSubscriptCtx to implement subscripting
// of a Vector expression tree.
typename proto::result_of::eval<Expr const, VectorSubscriptCtx const>::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<typename T>
struct IsVector
: mpl::false_
{};
template<typename T, typename A>
struct IsVector<std::vector<T, A> >
: 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<typename T, typename A, typename Expr>
std::vector<T, A> &assign(std::vector<T, A> &arr, Expr const &expr)
{
VectorSizeCtx const size(arr.size());
proto::eval(proto::as_expr<VectorDomain>(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<VectorDomain>(expr)[i];
}
return arr;
}
// Add-assign to a vector from some expression.
template<typename T, typename A, typename Expr>
std::vector<T, A> &operator +=(std::vector<T, A> &arr, Expr const &expr)
{
VectorSizeCtx const size(arr.size());
proto::eval(proto::as_expr<VectorDomain>(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<VectorDomain>(expr)[i];
}
return arr;
}
}
int main()
{
using namespace VectorOps;
int i;
const int n = 10;
std::vector<int> a,b,c,d;
std::vector<double> 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;
}
}
//]
|