Boost logo

Boost Users :

Subject: [Boost-users] [Proto] Questions about deep_copy
From: Kim Kuen Tang (kuentang_at_[hidden])
Date: 2009-05-09 17:52:55


Hi all,

consider the following code:

std::vector<double> a(10,1.0), b(10,2.0);
BOOST_AUTO( temp , proto::as_expr<MixedDomain>(a+b+0.1) ); // is the
function proto::as_expr<MixedDomain>() needed?
temp[0];

Here the expression a +b+ 0.1 is created by the MixedDomain as it is
from the mixed example. And the operator[] is definde by:

    typedef typename boost::remove_reference<
        typename boost::result_of<Begin(MixedExpr<Expr> const &
)>::type>::type Expr2;
    typedef typename proto::result_of::eval<Expr2, DereferenceCtx
const>::type result_type;

    result_type
    operator[](std::size_t index) const
    {
        Expr2 expr2 = Begin()(*this);
        DereferenceCtx const deref = {};
        return proto::eval(expr2, deref);
    }

But the code crashes during runtime. The reason is that the number 0.1
is held by reference.
So the number 0.1 goes out of scope before i try to evaluate the
expression temp[0];

A way to solve this problem is to deep copy the expression with
deep_copy. But on the other hand i do not want to copy the two vectors a
and b.

So i am asking what is the best way to solve this problem? Can this
problem be solved by defining a Grammar that copies the number 0.1?

Or do i need to extend the deep_copy by deep_copy_if<double>()
(a+b+0.1). It should copy the terminal only if it matches the specified
type.

Thanks for your help.

B/Rgds
Kim

Here is the whole code:

//[ Mixed
///////////////////////////////////////////////////////////////////////////////
// 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<> and std::list, non-proto types. It is a port
// of the Mixed example from PETE.
// (http://www.codesourcery.com/pooma/download.html).

#include <list>
#include <cmath>
#include <vector>
#include <complex>
#include <iostream>
#include <stdexcept>
#include <boost/proto/core.hpp>
#include <boost/proto/debug.hpp>
#include <boost/proto/context.hpp>
#include <boost/proto/transform.hpp>
#include <boost/proto/proto_typeof.hpp>
#include <boost/proto/deep_copy.hpp>
#include <boost/utility/enable_if.hpp>
#include <boost/typeof/std/list.hpp>
#include <boost/typeof/std/vector.hpp>
#include <boost/typeof/std/complex.hpp>
#include <boost/type_traits/remove_reference.hpp>
#include <boost/utility/result_of.hpp>
#include <boost/typeof/typeof.hpp>

namespace proto = boost::proto;
namespace mpl = boost::mpl;
using proto::_;

template<typename Expr>
struct MixedExpr;

template<typename Iter>
struct iterator_wrapper
{
        typedef Iter iterator;
        iterator_wrapper(Iter it)
                :it(it) {};
        Iter it;
};

struct begin_iter :proto::callable
{
        template<class Sig>
        struct result;

        template<class This, class Cont>
        struct result<This(Cont)> : proto::result_of::as_expr<
                iterator_wrapper<typename boost::remove_reference<Cont>::type::const_iterator>
> {};

        template<class Cont>
        typename result<begin_iter(Cont const&)>::type
        operator()(Cont const& cont) const
        {
                iterator_wrapper<typename Cont::const_iterator> it(cont.begin());
                return proto::as_expr(it);
        }
};
template<typename Num>
struct num_wrapper
{
        typedef Num numeric;
        num_wrapper(Num num)
                :num_(num)
        {
                //BOOST_MPL_ASSERT( (boost::is_reference<Num>) );
        };
        Num num_;
};

struct begin_num :proto::callable
{
        template<class Sig>
        struct result;

        template<class This, class Cont>
        struct result<This(Cont)> : proto::result_of::make_expr<proto::tag::terminal
                ,num_wrapper<
                        typename boost::remove_const<
                                typename boost::remove_reference<Cont>::type
>::type
>
> {};

        template<class Cont>
        typename result<begin_num(Cont const)>::type
        operator()(Cont const cont) const
        {
                //BOOST_MPL_ASSERT( (boost::is_reference<result<begin_num(Cont const&)>::type>) );
                num_wrapper<Cont> num(cont);
                return proto::make_expr<proto::tag::terminal>(num);
        }
};
// Here is a grammar that replaces vector and list terminals with their
// begin iterators

struct Begin
        : proto::or_<
                proto::when< proto::terminal<std::vector<_,_> >, begin_iter(proto::_value)>
                ,proto::when< proto::terminal<std::list<_,_> >, begin_iter(proto::_value)>
                ,proto::when<proto::terminal<double>, begin_num(proto::_value) >
                ,proto::when<proto::terminal<_> >
                ,proto::nary_expr<_ , proto::vararg<Begin> >
>
{};

struct DereferenceCtx
{
        template<typename Expr,typename EnableIf=void>
        struct eval : proto::default_eval<Expr, DereferenceCtx const>
        {};

        template<typename Expr>
        struct eval<Expr,
                typename boost::enable_if<
                proto::matches<Expr, proto::terminal< iterator_wrapper<_> > >
>::type
>
        {
                typedef typename proto::result_of::value<Expr>::type IteratorWrapper;
                typedef typename IteratorWrapper::iterator iterator;
                typedef typename std::iterator_traits<iterator>::reference result_type;

                template<typename Expr>
                result_type
                operator()(Expr &expr,DereferenceCtx const&)
                {
                        return *proto::value(expr).it;
                }
        };

        template<typename Expr>
        struct eval<Expr,
                typename boost::enable_if<
                proto::matches<Expr, proto::terminal< num_wrapper<_> > >
>::type
>
        {
                typedef typename proto::result_of::value<Expr>::type NumWrapper;
                typedef typename NumWrapper::numeric result_type;

                template<typename Expr>
                result_type
                operator()(Expr &expr,DereferenceCtx const&)
                {
                        return proto::value(expr).num_;
                }
        };

        
};

struct IncrementCtx
{
        template<typename Expr,typename EnableIf=void>
        struct eval : proto::null_eval<Expr, IncrementCtx const> {};

        template<typename Expr>
        struct eval<Expr,
                typename boost::enable_if< proto::matches<Expr, proto::terminal<iterator_wrapper<_> > >
>::type>
        {
                typedef void result_type;

                template<typename Expr>
                result_type
                operator()(Expr& expr, IncrementCtx const & )
                {
                        ++proto::value(expr).it;
                }
        };
};

struct AdvanceCtx
{
        std::size_t index_;
        template<typename Expr,typename EnableIf=void>
        struct eval : proto::null_eval<Expr, AdvanceCtx const> {};

        template<typename Expr>
        struct eval<Expr,
                typename boost::enable_if< proto::matches<Expr, proto::terminal<iterator_wrapper<_> > >
>::type>
        {
                typedef void result_type;

                template<typename Expr>
                result_type
                operator()(Expr& expr, AdvanceCtx const & ctx)
                {
                        std::advance(proto::value(expr).it, ctx.index_);
                }
        };
};

// 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 MixedGrammar
  : proto::or_<
          proto::when< proto::terminal<double const&> , begin_num(proto::_value)>
      , proto::terminal<_>
      , proto::and_<
            proto::nary_expr<_, proto::vararg<MixedGrammar> >
          , proto::not_<AssignOps>
>
>
{};

// Expressions in the vector domain will be wrapped in VectorExpr<>
// and must conform to the VectorGrammar
struct MixedDomain
  : proto::domain<proto::generator<MixedExpr>, MixedGrammar>
{};

// Here is MixedExpr, a wrapper for expression types in the MixedDomain.
template<typename Expr>
struct MixedExpr
  : proto::extends<Expr, MixedExpr<Expr>, MixedDomain>
{
    explicit MixedExpr(Expr const &expr)
      : proto::extends<Expr, MixedExpr<Expr>, MixedDomain>(expr)
    {}
        typedef typename boost::remove_reference<
                typename boost::result_of<Begin(MixedExpr<Expr> const & )>::type>::type Expr2;
        typedef typename proto::result_of::eval<Expr2, DereferenceCtx const>::type result_type;

        result_type
        operator[](std::size_t index) const
        {
                //BOOST_MPL_ASSERT( (boost::is_reference<Expr2>) );
                Expr2 expr2 = Begin()(*this);
                AdvanceCtx const adv = {index};
                proto::eval(expr2, adv);
                DereferenceCtx const deref = {};
                return proto::eval(expr2, deref);
        }
private:
    // hide this:
    //using proto::extends<Expr, MixedExpr<Expr>, MixedDomain>::operator [];
};

// Define a trait type for detecting vector and list terminals, to
// be used by the BOOST_PROTO_DEFINE_OPERATORS macro below.
template<typename T>
struct IsMixed
  : mpl::false_
{};

template<typename T, typename A>
struct IsMixed<std::list<T, A> >
  : mpl::true_
{};

template<typename T, typename A>
struct IsMixed<std::vector<T, A> >
  : mpl::true_
{};

namespace MixedOps
{
    // This defines all the overloads to make expressions involving
    // std::vector to build expression templates.
    BOOST_PROTO_DEFINE_OPERATORS(IsMixed, MixedDomain)

    struct assign_op
    {
        template<typename T, typename U>
        void operator ()(T &t, U const &u) const
        {
            t = u;
        }
    };

    struct plus_assign_op
    {
        template<typename T, typename U>
        void operator ()(T &t, U const &u) const
        {
            t += u;
        }
    };

    struct minus_assign_op
    {
        template<typename T, typename U>
        void operator ()(T &t, U const &u) const
        {
            t -= u;
        }
    };

    struct sin_
    {
        template<typename Sig>
        struct result;

        template<typename This, typename Arg>
        struct result<This(Arg)>
          : boost::remove_const<typename boost::remove_reference<Arg>::type>
        {};

        template<typename Arg>
        Arg operator ()(Arg const &a) const
        {
            return std::sin(a);
        }
    };

    template<typename A>
    typename proto::result_of::make_expr<
        proto::tag::function
      , MixedDomain
      , sin_ const
      , A const &
>::type sin(A const &a)
    {
        return proto::make_expr<proto::tag::function, MixedDomain>(sin_(), boost::ref(a));
    }

    template<typename FwdIter, typename Expr, typename Op>
    void evaluate(FwdIter begin, FwdIter end, Expr const &expr, Op op)
    {
        IncrementCtx const inc = {};
        DereferenceCtx const deref = {};
        typename boost::result_of<Begin(Expr const &)>::type expr2 = Begin()(expr);
        for(; begin != end; ++begin)
        {
            op(*begin, proto::eval(expr2, deref));
            proto::eval(expr2, inc);
        }
    }

        template<typename Vector, typename Expr>
        Vector& assign(Vector &arr,Expr const &expr)
        {
                evaluate(arr.begin(),arr.end(),proto::as_expr<MixedDomain>(expr),assign_op());
                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)
    {
        evaluate(arr.begin(), arr.end(), proto::as_expr<MixedDomain>(expr), plus_assign_op());
        return arr;
    }

    // Add-assign to a list from some expression.
    template<typename T, typename A, typename Expr>
    std::list<T, A> &operator +=(std::list<T, A> &arr, Expr const &expr)
    {
        evaluate(arr.begin(), arr.end(), proto::as_expr<MixedDomain>(expr), plus_assign_op());
        return arr;
    }

    // Minus-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)
    {
        evaluate(arr.begin(), arr.end(), proto::as_expr<MixedDomain>(expr), minus_assign_op());
        return arr;
    }

    // Minus-assign to a list from some expression.
    template<typename T, typename A, typename Expr>
    std::list<T, A> &operator -=(std::list<T, A> &arr, Expr const &expr)
    {
        evaluate(arr.begin(), arr.end(), proto::as_expr<MixedDomain>(expr), minus_assign_op());
        return arr;
    }
}

int main()
{
    using namespace MixedOps;

    int n = 10;
    std::vector<int> a,b,c,d;
    std::list<double> e;
    std::list<std::complex<double> > 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<double>(1.0, 1.0));
    }

        BOOST_AUTO(temp ,c + a + 0.1 );
        for(int i=0, end=n;i<end;++i)
                   std::cout<<temp[i]<<"\t";

    //f -= sin(0.1 * e * std::complex<double>(0.2, 1.2));

    //std::list<double>::const_iterator ei = e.begin();
    //std::list<std::complex<double> >::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;
    //}

        //boost::array<double,10> sad;
}
//]


Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net