From 59288e597ff90c3b6c387c637c5d6067feee9b4d Mon Sep 17 00:00:00 2001 From: Olivier Parcollet Date: Sun, 29 Sep 2013 19:59:46 +0200 Subject: [PATCH] clef. Clean evaluator when producing temporaries... - When evaluation produces temporaries in intermediate steps, they were capture by ref, not properly forwarded. This results in bugs in more complex cases, like evaluation of objects returning new arrays expression template. (preparation for next commit). --- triqs/clef/clef.hpp | 161 ++++++++++++++++++++++---------------------- 1 file changed, 80 insertions(+), 81 deletions(-) diff --git a/triqs/clef/clef.hpp b/triqs/clef/clef.hpp index cb816103..6f51af06 100644 --- a/triqs/clef/clef.hpp +++ b/triqs/clef/clef.hpp @@ -46,21 +46,23 @@ namespace triqs { namespace clef { template struct force_copy_in_expr : force_copy_in_expr{}; template< class T > struct expr_storage_t {typedef T type;}; - template< class T > struct expr_storage_t : std::conditional::value, T ,std::reference_wrapper>{}; + template< class T > struct expr_storage_t : std::conditional::value, typename std::remove_const::type ,std::reference_wrapper>{}; template< class T > struct expr_storage_t {typedef T type;}; - + template< class T > struct expr_storage_t {typedef T type;}; + template< class T > struct expr_storage_t {typedef T type;}; + /* --------------------------------------------------------------------------------------------------- * Placeholder and corresponding traits * --------------------------------------------------------------------------------------------------- */ template class pair; // forward - // a placeholder is an empty struct, labelled by an int. + // a placeholder is an empty struct, labelled by an int. template struct placeholder { static_assert( (N>=0) && (N<64) , "Placeholder number limited to [0,63]"); static constexpr int index = N; template pair operator = (RHS && rhs) { return {std::forward(rhs)};} }; - + // placeholder will always be copied (they are empty anyway). template< int N > struct force_copy_in_expr> : std::true_type{}; @@ -90,11 +92,11 @@ namespace triqs { namespace clef { std::integral_constant::value || is_any_lazy::value> {}; template - constexpr bool ClefExpression() { return is_any_lazy::value;} + constexpr bool ClefExpression() { return is_any_lazy::value;} template struct is_clef_expression : is_any_lazy{}; -/* --------------------------------------------------------------------------------------------------- + /* --------------------------------------------------------------------------------------------------- * Node of the expression tree * --------------------------------------------------------------------------------------------------- */ template struct expr { @@ -136,7 +138,7 @@ namespace triqs { namespace clef { template struct operation; // a little function to clean the reference_wrapper - template U & _cl(U & x) { return x;} + template U _cl(U && x) { return std::forward(x);} template U & _cl(std::reference_wrapper x) { return x.get();} /// Terminal @@ -156,7 +158,7 @@ namespace triqs { namespace clef { #define TRIQS_CLEF_OPERATION(TAG,OP)\ namespace tags { struct TAG : binary_op { static const char * name() { return BOOST_PP_STRINGIZE(OP);} };}\ template<> struct operation {\ - template auto operator()(L const & l, R const & r) const DECL_AND_RETURN ( _cl(l) OP _cl(r));\ + template auto operator()(L && l, R && r) const DECL_AND_RETURN ( _cl(std::forward(l)) OP _cl(std::forward(r)));\ };\ template\ typename std::enable_if::value, expr::type,typename expr_storage_t::type> >::type \ @@ -189,7 +191,9 @@ namespace triqs { namespace clef { /// the only ternary node : expression if template<> struct operation { - template auto operator()(C const & c, A const & a, B const & b) const DECL_AND_RETURN (_cl(c) ? _cl(a): _cl(b)); + // A and B MUST be the same + template A operator()(C const & c, A const & a, B const & b) const {return _cl(c) ? _cl(a): _cl(b);} + //template auto operator()(C const & c, A const & a, B const & b) const DECL_AND_RETURN (_cl(c) ? _cl(a): _cl(b)); }; // operator is : if_else( Condition, A, B) template @@ -199,79 +203,76 @@ namespace triqs { namespace clef { /* --------------------------------------------------------------------------------------------------- * Evaluation of the expression tree. * --------------------------------------------------------------------------------------------------- */ + template struct _or; + template struct _or : std::integral_constant::value>{}; + template<> struct _or<> : std::false_type{}; - template struct operation2; - template struct operation2 { - typedef expr::type ...> rtype; - rtype operator()(Args const & ... args) const {return rtype {Tag(), args...};} - }; - template struct operation2 { - typedef typename std::remove_reference(Args...)>::type>::type rtype; - // remove the reference because of ternary if_else in which decltype returns a ref... - rtype operator()(Args const & ... args) const {return operation()(args...); } - }; - - // Generic case : do nothing (for the leaf of the tree except placeholder) + // Generic case : do nothing (for the leaf of the tree including placeholder) template struct evaluator{ - typedef T rtype; - rtype operator()(T const & k, Pairs const &... pairs) {return k;} + typedef is_any_lazy is_lazy; + T operator()(T const & k, Pairs const &... pairs) { return k;} }; // placeholder template struct evaluator< placeholder, pair, Pairs... > { typedef evaluator< placeholder, Pairs...> eval_t; - typedef typename eval_t::rtype rtype; - rtype operator()(placeholder, pair const &, Pairs const& ... pairs) { return eval_t()(placeholder(), pairs...);} + typedef typename eval_t::is_lazy is_lazy; + auto operator()(placeholder, pair const &, Pairs const& ... pairs) DECL_AND_RETURN( eval_t()(placeholder(), pairs...)); }; + template struct evaluator< placeholder, pair, Pairs... > { - typedef T const & rtype; - //typedef typename pair::value_type const & rtype; - rtype operator()(placeholder, pair const & p, Pairs const& ...) { return p.rhs;} + typedef std::false_type is_lazy; + T operator()(placeholder, pair const & p, Pairs const& ...) { return p.rhs;} + }; + + template struct operation2; + template struct operation2 { + template + expr::type ...> operator()(Args && ... args) const { + return {Tag(), std::forward(args)...}; + } + }; + template struct operation2 { + template + auto operator()(Args && ... args) const DECL_AND_RETURN( operation()(std::forward(args)...)); + void operator() (...) const {} }; // general expr node - template struct evaluator, Pairs...> { - typedef operation2::rtype... >::value, typename evaluator::rtype... > OPTYPE; - typedef typename OPTYPE::rtype rtype; + template struct evaluator_node_gal; + + template struct evaluator_node_gal<1, expr, Pairs...> { + typedef _or::is_lazy... > is_lazy; + typedef operation2 OPTYPE; + auto operator()(expr const & ex, Pairs const & ... pairs) const + DECL_AND_RETURN (OPTYPE()(eval(std::get<0>(ex.childs),pairs...))); + }; + + template struct evaluator_node_gal<2, expr, Pairs...> { + typedef _or::is_lazy... > is_lazy; + typedef operation2 OPTYPE; + auto operator()(expr const & ex, Pairs const & ... pairs) const + DECL_AND_RETURN (OPTYPE()(eval(std::get<0>(ex.childs),pairs...),eval(std::get<1>(ex.childs),pairs...))); + }; - // first done manually for clearer error messages ... - template< int arity = sizeof...(Childs)> - typename std::enable_if< arity==1, rtype>::type - operator()(expr const & ex, Pairs const & ... pairs) const - { return OPTYPE()(eval(std::get<0>(ex.childs),pairs...) );} - - template< int arity = sizeof...(Childs)> - typename std::enable_if< arity==2, rtype>::type - operator()(expr const & ex, Pairs const & ... pairs) const - { return OPTYPE()(eval(std::get<0>(ex.childs),pairs...),eval(std::get<1>(ex.childs),pairs...) );} - #define AUX(z,p,unused) eval(std::get

(ex.childs),pairs...) #define IMPL(z, NN, unused) \ - template< int arity = sizeof...(Childs)>\ - typename std::enable_if< arity==NN, rtype>::type\ - operator()(expr const & ex, Pairs const & ... pairs) const\ - { return OPTYPE()(BOOST_PP_ENUM(NN,AUX,nil));} - BOOST_PP_REPEAT_FROM_TO(3,BOOST_PP_INC(TRIQS_CLEF_MAXNARGS), IMPL, nil); + template struct evaluator_node_gal, Pairs...> {\ + typedef _or::is_lazy... > is_lazy;\ + typedef operation2 OPTYPE;\ + auto operator()(expr const & ex, Pairs const & ... pairs) const\ + DECL_AND_RETURN ( OPTYPE()(BOOST_PP_ENUM(NN,AUX,nil)));\ + }; + BOOST_PP_REPEAT_FROM_TO(3,BOOST_PP_INC(TRIQS_CLEF_MAXNARGS), IMPL, nil); #undef AUX #undef IMPL - }; -#ifdef TRIQS_CLEF_EVAL_SHORT_CIRCUIT - // A short circuit if intersection of ph and is 0, no need to evaluate the whole tree...... - // Seems useless, && the second eval is not correct if hte expression is a terminal. - template - typename std::enable_if< (ph_set::value & ph_set::value) !=0, typename evaluator::rtype > ::type - eval (T const & ex, Pairs const &... pairs) { return evaluator()(ex, pairs...); } + template + struct evaluator, Pairs...> : evaluator_node_gal, Pairs...>{}; - template - typename std::enable_if< (ph_set::value & ph_set::value) ==0, T const &> ::type - eval (T const & ex, Pairs const &... pairs) { return ex;} -#else // The general eval function for expressions template - typename evaluator::rtype - eval (T const & ex, Pairs const &... pairs) { return evaluator()(ex, pairs...); } -#endif + auto eval (T const & ex, Pairs const &... pairs) DECL_AND_RETURN( evaluator()(ex, pairs...)); /* --------------------------------------------------------------------------------------------------- * make_function : transform an expression to a function @@ -284,17 +285,15 @@ namespace triqs { namespace clef { // gcc 4.6 crashes (!!!) on the first variant #ifndef TRIQS_COMPILER_OBSOLETE_GCC template - typename evaluator...>::rtype - operator()(Args &&... args) const - { return evaluator...>() ( ex, pair{std::forward(args)}...); } + auto operator()(Args &&... args) const + DECL_AND_RETURN( evaluator...>() ( ex, pair{std::forward(args)}...)); #else template struct __eval { typedef evaluator...> eval_t; - typedef typename eval_t::rtype rtype; - rtype operator()(Expr const &ex , Args &&... args) const { return eval_t() ( ex, pair{std::forward(args)}...); } + auto operator()(Expr const &ex , Args &&... args) const DECL_AND_RETURN( return eval_t() ( ex, pair{std::forward(args)}...)); }; template - typename __eval::rtype operator()(Args &&... args) const { return __eval() ( ex, std::forward(args)...); } + auto operator()(Args &&... args) const DECL_AND_RETURN(return __eval() ( ex, std::forward(args)...)); #endif }; @@ -307,12 +306,6 @@ namespace triqs { namespace clef { template< typename Expr, int... Is> struct is_any_lazy > : std::integral_constant>::value !=0>{}; template< typename Expr, int... Is> struct force_copy_in_expr > : std::true_type{}; - template< typename Expr, int... Is,typename... Pairs> struct evaluator, Pairs...> { - typedef evaluator e_t; - typedef make_fun_impl rtype; - rtype operator()(make_fun_impl const & f, Pairs const & ... pairs) const { return rtype( e_t()(f.ex, pairs...));} - }; - template< typename Expr, typename ... Phs> make_fun_impl::type,Phs::index...> make_function(Expr && ex, Phs...) { return {ex}; } @@ -323,11 +316,17 @@ namespace triqs { namespace clef { }; } + template< typename Expr, int... Is,typename... Pairs> struct evaluator, Pairs...> { + typedef evaluator e_t; + typedef std::integral_constant >::value != ph_set::value> is_lazy; + auto operator()(make_fun_impl const & f, Pairs const & ... pairs) const DECL_AND_RETURN( make_function( e_t()(f.ex, pairs...),placeholder()...)); + }; + template struct ph_list {}; template ph_list var( placeholder ...) { return {};} template - auto operator >> (ph_list, Expr const & ex) DECL_AND_RETURN( make_function(ex, placeholder()...)); + auto operator >> (ph_list, Expr const & ex) DECL_AND_RETURN( make_function(ex, placeholder()...)); /* -------------------------------------------------------------------------------------------------- * make_function @@ -400,15 +399,15 @@ namespace triqs { namespace clef { void operator<<(expr...> const & ex, RHS && rhs) { triqs_clef_auto_assign_subscript(std::get<0>(ex.childs), make_function(std::forward(rhs), placeholder()...)); } - template + template void operator<<(expr...> && ex, RHS && rhs) { triqs_clef_auto_assign_subscript(std::get<0>(ex.childs), make_function(std::forward(rhs), placeholder()...)); } - template + template void operator<<(expr && ex, RHS && rhs) = delete; - template + template void operator<<(expr const & ex, RHS && rhs) = delete; /* -------------------------------------------------------------------------------------------------- @@ -433,7 +432,7 @@ namespace triqs { namespace clef { namespace _result_of { template< typename Obj, typename... Args > struct make_expr_call : std::enable_if< is_any_lazy::value, expr::type, typename expr_storage_t::type ...> > { - static_assert (((arity::value==-1) || (arity::value == sizeof...(Args))), "Object called with a wrong number of arguments"); + static_assert (((arity::value==-1) || (arity::value == sizeof...(Args))), "Object called with a wrong number of arguments"); }; } template< typename Obj, typename... Args > @@ -477,7 +476,7 @@ namespace triqs { namespace clef { auto operator()( Args&&... args ) const DECL_AND_RETURN(make_expr_call (*this,std::forward(args)...)); #else template< typename... Args> - typename _result_of::make_expr_call::type + typename _result_of::make_expr_call::type operator()( Args&&... args ) const { return make_expr_call (*this,args...);} #endif @@ -488,7 +487,7 @@ namespace triqs { namespace clef { }; template struct force_copy_in_expr > : std::true_type{}; - + /* -------------------------------------------------------------------------------------------------- * The macro to make any function lazy * TRIQS_CLEF_MAKE_FNT_LAZY (Arity,FunctionName ) : creates a new function in the triqs::lazy namespace @@ -504,7 +503,7 @@ namespace triqs { namespace clef { #ifndef TRIQS_COMPILER_OBSOLETE_GCC - #define TRIQS_CLEF_IMPLEMENT_LAZY_METHOD(TY,name)\ +#define TRIQS_CLEF_IMPLEMENT_LAZY_METHOD(TY,name)\ struct __clef_lazy_method_impl_##name { \ TY * _x;\ template auto operator()(A&&... a) const DECL_AND_RETURN (_x->name(std::forward(a)...));\